gtag 추가

This commit is contained in:
2025-07-03 08:36:26 +09:00
parent 01aa5dfe66
commit 73b6439702
23 changed files with 414 additions and 17 deletions
+14
View File
@@ -35,6 +35,7 @@
<script setup>
import { AVERAGE_CALCULATION_PERIOD_OPTIONS } from '@/utils/enumMappings';
import { ref, computed, onMounted, inject } from 'vue';
import { useGtag } from 'vue-gtag-next';
import { useRouter } from 'vue-router';
import { useToast } from 'primevue/usetoast';
import clubService from '@/services/clubService';
@@ -55,7 +56,14 @@ const loading = ref(false);
const clubNameError = ref('');
const clubDescriptionError = ref('');
// 페이지 진입 시 Google Analytics 페이지뷰 추적
onMounted(() => {
const gtag = useGtag();
gtag.pageview({
page_title: '클럽생성',
page_path: window.location.pathname,
page_location: window.location.href
});
authStore.loadUserInfo();
});
@@ -81,7 +89,13 @@ const validateForm = () => {
return isValid;
};
// 클럽 생성 시도/성공/실패 GA 이벤트 추적
const handleCreateClub = async () => {
const gtag = useGtag();
gtag.event('create_club_attempt', {
event_category: '클럽생성',
event_label: '클럽 생성 시도'
});
if (!validateForm()) return;
if (!authStore.user) {
+7
View File
@@ -130,6 +130,7 @@
import { AVERAGE_CALCULATION_PERIOD_OPTIONS, getMemberTypeLabel } from '@/utils/enumMappings';
import { ref, onMounted, computed, inject } from 'vue';
import { useGtag } from 'vue-gtag-next';
import { useRouter } from 'vue-router';
import { useToast } from 'primevue/usetoast';
import { useClubStore } from '@/stores/clubStore';
@@ -309,7 +310,13 @@ const getFeatureIcon = (featureType) => {
};
// 클럽 정보 저장
// 클럽 정보 저장 버튼 클릭 시 GA 이벤트 추적
const saveClubInfo = async () => {
const gtag = useGtag();
gtag.event('save_club_info', {
event_category: '클럽설정',
event_label: '클럽 정보 저장'
});
try {
if (!clubId) {
router.push('/club');
+15
View File
@@ -146,9 +146,11 @@ import { useRouter } from 'vue-router';
import apiClient from '@/services/api';
import dayjs from 'dayjs';
import { useToast } from 'primevue/usetoast';
import { useGtag } from 'vue-gtag-next';
const router = useRouter();
const toast = useToast();
const gtag = useGtag();
// 데이터 상태 변수들
const loading = ref(false);
@@ -260,6 +262,12 @@ const loadDashboardData = async () => {
// 페이지 이동 함수
const navigateTo = (path) => {
// Google Analytics 이벤트 추적
gtag.event('navigation', {
'event_category': '대시보드',
'event_label': path,
'value': 1
});
router.push(path);
};
@@ -267,6 +275,13 @@ const navigateTo = (path) => {
onMounted(async () => {
clubId.value = localStorage.getItem('clubId') || null;
await loadDashboardData();
// Google Analytics 페이지뷰 추적
gtag.pageview({
page_title: '클럽 대시보드',
page_path: window.location.pathname,
page_location: window.location.href
});
});
</script>
+28
View File
@@ -29,6 +29,7 @@
<script setup>
// getEventTypeLabel 중복 import 제거. eventUtils.js의 getEventTypeLabel만 사용.
import { ref, onMounted, computed } from 'vue';
import { useGtag } from 'vue-gtag-next';
import { useRouter } from 'vue-router';
import { useToast } from 'primevue/usetoast';
import FullCalendar from '@fullcalendar/vue3';
@@ -56,7 +57,14 @@ const loading = ref(false);
const clubId = ref(localStorage.getItem('clubId') || null);
// 페이지 로드 시 데이터 가져오기
// 페이지 진입 시 Google Analytics 페이지뷰 추적
onMounted(async () => {
const gtag = useGtag();
gtag.pageview({
page_title: '이벤트캘린더',
page_path: window.location.pathname,
page_location: window.location.href
});
await fetchEvents();
});
@@ -107,13 +115,27 @@ const getEventColor = (eventType) => {
};
// 캘린더 이벤트 클릭 핸들러
// 캘린더 이벤트 클릭 시 GA 이벤트 추적
const handleEventClick = (info) => {
const gtag = useGtag();
gtag.event('calendar_event_click', {
event_category: '이벤트캘린더',
event_label: '캘린더 이벤트 클릭',
value: info.event.id
});
const eventId = info.event.id;
viewEventDetails(eventId);
};
// 이벤트 상세 보기
// 이벤트 상세보기 클릭 시 GA 이벤트 추적
const viewEventDetails = async (eventId) => {
const gtag = useGtag();
gtag.event('view_event_details', {
event_category: '이벤트캘린더',
event_label: '이벤트 상세보기',
value: eventId
});
try {
selectedEvent.value = await eventService.getEventById(eventId);
eventDetailsDialog.value = true;
@@ -140,7 +162,13 @@ const removeParticipant = async (participant) => {
};
// 이벤트 관리 페이지로 이동
// 이벤트관리 이동 버튼 클릭 시 GA 이벤트 추적
const navigateToEventManagement = () => {
const gtag = useGtag();
gtag.event('go_to_event_management', {
event_category: '이벤트캘린더',
event_label: '이벤트관리 이동'
});
router.push('/club/events');
};
+48 -2
View File
@@ -122,6 +122,7 @@
<script setup>
import { getEventTypeLabel, getEventStatusLabel, getStatusSeverity } from '@/utils/enumMappings';
import { ref, onMounted, computed } from 'vue';
import { useGtag } from 'vue-gtag-next';
import { useToast } from 'primevue/usetoast';
import { useRoute } from 'vue-router';
import { useClubStore } from '@/stores/clubStore';
@@ -203,7 +204,14 @@ const fetchClubMembers = async () => {
};
// 컴포넌트 마운트 시 데이터 로드
// 페이지 진입 시 Google Analytics 페이지뷰 추적
onMounted(async () => {
const gtag = useGtag();
gtag.pageview({
page_title: '이벤트관리',
page_path: window.location.pathname,
page_location: window.location.href
});
if (!clubId.value) {
toast.add({
severity: 'error',
@@ -265,7 +273,14 @@ const editEvent = (eventData) => {
};
// 이벤트 상세 정보 보기
// 이벤트 상세보기 클릭 시 GA 이벤트 추적
const viewEventDetails = async (eventData) => {
const gtag = useGtag();
gtag.event('view_event_details', {
event_category: '이벤트관리',
event_label: '이벤트 상세보기',
value: eventData.id
});
try {
const response = await eventService.getEventById(eventData.id);
event.value = response;
@@ -302,9 +317,16 @@ const confirmDeleteEvent = (eventData) => {
};
// 이벤트 저장
// 이벤트 저장(생성/수정) 시 GA 이벤트 추적
const saveEvent = async (eventData) => {
const gtag = useGtag();
try {
if (eventData.id) {
gtag.event('edit_event', {
event_category: '이벤트관리',
event_label: '이벤트 수정',
value: eventData.id
});
// 이벤트 수정
const response = await eventService.updateEvent({
...eventData,
@@ -312,6 +334,10 @@ const saveEvent = async (eventData) => {
});
await fetchEvents(); // 목록 갱신
} else {
gtag.event('create_event', {
event_category: '이벤트관리',
event_label: '이벤트 생성'
});
// 이벤트 생성
const response = await eventService.createEvent({
...eventData,
@@ -327,6 +353,10 @@ const saveEvent = async (eventData) => {
});
hideDialog();
} catch (error) {
gtag.event('event_save_fail', {
event_category: '이벤트관리',
event_label: eventData.id ? '이벤트 수정 실패' : '이벤트 생성 실패'
});
toast.add({
severity: 'error',
summary: '오류',
@@ -337,17 +367,22 @@ const saveEvent = async (eventData) => {
};
// 이벤트 삭제
// 이벤트 삭제 시 GA 이벤트 추적
const deleteEvent = async () => {
const gtag = useGtag();
try {
await eventService.deleteEvent(clubId.value, event.value.id);
gtag.event('delete_event', {
event_category: '이벤트관리',
event_label: '이벤트 삭제',
value: event.value.id
});
toast.add({
severity: 'success',
summary: '성공',
detail: '이벤트가 삭제되었습니다.',
life: 3000
});
deleteEventDialog.value = false;
const index = events.value.findIndex(e => e.id === event.value.id);
if (index > -1) {
@@ -355,6 +390,11 @@ const deleteEvent = async () => {
}
event.value = {};
} catch (error) {
gtag.event('delete_event_fail', {
event_category: '이벤트관리',
event_label: '이벤트 삭제 실패',
value: event.value.id
});
toast.add({
severity: 'error',
summary: '오류',
@@ -398,7 +438,13 @@ const goToScoreEntry = () => {
};
// 이벤트 캘린더 페이지로 이동
// 캘린더 이동 버튼 클릭 시 GA 이벤트 추적
const navigateToCalendar = () => {
const gtag = useGtag();
gtag.event('go_to_calendar', {
event_category: '이벤트관리',
event_label: '캘린더 이동'
});
const url = `/club/calendar?clubId=${clubId.value}`;
window.location.href = url;
};
+26 -3
View File
@@ -190,6 +190,7 @@
</template>
<script setup>
import { useGtag } from 'vue-gtag-next';
import { ref, reactive, computed, onMounted, watch } from 'vue';
import clubService from '@/services/clubService';
import { useClubStore } from '@/stores/clubStore';
@@ -368,7 +369,8 @@ const loadMembers = async () => {
// 새 회원 추가 다이얼로그 열기
const openNewMemberDialog = () => {
member.value = {
dialogMode.value = 'new';
member.value = {
name: '',
gender: null,
memberTypeObj: null,
@@ -376,7 +378,6 @@ const openNewMemberDialog = () => {
email: '',
handicap: 0
};
dialogMode.value = 'new';
memberDialog.value = true;
};
@@ -392,6 +393,8 @@ watch(() => member.value.gender, (newGender) => {
});
// 회원 수정 다이얼로그 열기
const gtag = useGtag();
const editMember = (data) => {
member.value = {
...data
@@ -410,12 +413,18 @@ const hideDialog = () => {
const saveMember = async () => {
try {
const memberData = { ...member.value };
const isNew = dialogMode.value === 'new';
const response = isNew
? await clubService.addClubMember(clubId.value, memberData)
: await clubService.updateClubMember(clubId.value, memberData.id, memberData);
// Google Analytics 이벤트 추적 - 회원 저장
gtag.event(isNew ? 'add_member' : 'edit_member', {
'event_category': '회원관리',
'event_label': isNew ? '새 회원 추가' : '회원 정보 수정',
'value': 1
});
toast.add({
severity: 'success',
summary: '성공',
@@ -444,6 +453,12 @@ const deleteMember = async () => {
try {
await clubService.deleteClubMember(clubId.value, selectedMember.value.id);
deleteDialog.value = false;
// Google Analytics 이벤트 추적 - 회원 삭제
gtag.event('delete_member', {
'event_category': '회원관리',
'event_label': '회원 삭제',
'value': 1
});
toast.add({ severity: 'success', summary: '성공', detail: '회원이 삭제되었습니다.', life: 3000 });
await loadMembers();
} catch (error) {
@@ -453,6 +468,14 @@ const deleteMember = async () => {
};
onMounted(() => {
// Google Analytics 페이지뷰 추적
gtag.pageview({
page_title: '회원 관리',
page_path: window.location.pathname,
page_location: window.location.href
});
});
</script>
<style scoped>
@@ -199,6 +199,7 @@ import { ref, reactive, computed, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useToast } from 'primevue/usetoast';
import scoreService from '@/services/scoreService';
import { useGtag } from 'vue-gtag-next';
const router = useRouter();
const route = useRoute();
@@ -411,7 +412,13 @@ const calculateTotal = (participant) => {
};
// 모든 점수 저장
// 점수 저장 버튼 클릭 시 GA 이벤트 추적
const saveAllScores = async () => {
const gtag = useGtag();
gtag.event('save_scores', {
event_category: '점수관리',
event_label: '점수 저장'
});
try {
loading.value = true;
await scoreService.saveScores(meetingId.value, participants.value);
@@ -425,7 +432,13 @@ const saveAllScores = async () => {
};
// 점수 내보내기 다이얼로그 열기
// 점수 내보내기 버튼 클릭 시 GA 이벤트 추적
const exportScores = () => {
const gtag = useGtag();
gtag.event('export_scores', {
event_category: '점수관리',
event_label: '점수 내보내기'
});
exportContent.value = [exportContentOptions.value[0]];
exportDialog.value = true;
};
@@ -446,12 +459,25 @@ const downloadExport = async () => {
};
// 뒤로 가기
// 뒤로가기 버튼 클릭 시 GA 이벤트 추적
const goBack = () => {
const gtag = useGtag();
gtag.event('go_back', {
event_category: '점수관리',
event_label: '뒤로가기'
});
router.push('/clubs/meetings');
};
// 컴포넌트 마운트 시 데이터 로드
// 페이지 진입 시 Google Analytics 페이지뷰 추적
onMounted(async () => {
const gtag = useGtag();
gtag.pageview({
page_title: '점수관리',
page_path: window.location.pathname,
page_location: window.location.href
});
if (!clubId.value) {
toast.add({ severity: 'error', summary: '오류', detail: '클럽 ID가 설정되지 않았습니다.', life: 3000 });
return;
+21 -2
View File
@@ -6,7 +6,7 @@
</div>
<div v-else>
<div class="period-selector">
<select v-model="selectedPeriod" @change="loadStatistics">
<select v-model="selectedPeriod" @change="onPeriodChange">
<option value="30">최근 30</option>
<option value="90">최근 90</option>
<option value="180">최근 180</option>
@@ -184,6 +184,7 @@
<script>
import { ref, onMounted, computed } from 'vue';
import { useGtag } from 'vue-gtag-next';
import { Bar as BarChart, Line as LineChart } from 'vue-chartjs';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend } from 'chart.js';
import apiClient from '@/services/api';
@@ -194,6 +195,7 @@ export default {
name: 'Statistics',
components: { BarChart, LineChart },
setup() {
const gtag = useGtag();
const stats = ref({
summary: {},
scoreDistribution: [],
@@ -300,9 +302,25 @@ export default {
}
onMounted(() => {
// Google Analytics 페이지뷰 추적
gtag.pageview({
page_title: '통계',
page_path: window.location.pathname,
page_location: window.location.href
});
loadStatistics();
});
// 기간 변경 시 GA 이벤트
const onPeriodChange = () => {
gtag.event('change_period', {
'event_category': '통계',
'event_label': selectedPeriod.value + '일',
'value': Number(selectedPeriod.value)
});
loadStatistics();
};
return {
stats,
selectedPeriod,
@@ -314,7 +332,8 @@ export default {
attendanceTrendChartData,
attendanceTrendChartOptions,
participantTrendChartData,
getHandicapTrendChartData
getHandicapTrendChartData,
onPeriodChange
};
}
};