gtag 추가
This commit is contained in:
Generated
+26
@@ -33,6 +33,8 @@
|
|||||||
"vee-validate": "^4.12.5",
|
"vee-validate": "^4.12.5",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-chartjs": "^5.3.2",
|
"vue-chartjs": "^5.3.2",
|
||||||
|
"vue-gtag": "^3.5.1",
|
||||||
|
"vue-gtag-next": "^1.14.0",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
"vuedraggable": "^4.1.0",
|
"vuedraggable": "^4.1.0",
|
||||||
"xlsx": "^0.18.5",
|
"xlsx": "^0.18.5",
|
||||||
@@ -3748,6 +3750,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-gtag": {
|
||||||
|
"version": "3.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-gtag/-/vue-gtag-3.5.1.tgz",
|
||||||
|
"integrity": "sha512-fyXQeIIc2cMibgggCbIZKfP0NvVbMupi4yl7CIwnD2feL9MGVVjzN/3nb5mX9AmZhIrkYri9dmBX6jY0lRCKDg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.5.13",
|
||||||
|
"vue-router": "^4.5.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"vue-router": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vue-gtag-next": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-gtag-next/-/vue-gtag-next-1.14.0.tgz",
|
||||||
|
"integrity": "sha512-iJl+cOG2GU5NuxqzSSIpt03WVOvZqyKB9TOy7d55KiuvRklcnb2nlqxW5B/a3/sbIt7fla+XEkRyMCcoz0zAHw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.0-rc.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-router": {
|
"node_modules/vue-router": {
|
||||||
"version": "4.5.1",
|
"version": "4.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz",
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
"vee-validate": "^4.12.5",
|
"vee-validate": "^4.12.5",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-chartjs": "^5.3.2",
|
"vue-chartjs": "^5.3.2",
|
||||||
|
"vue-gtag": "^3.5.1",
|
||||||
|
"vue-gtag-next": "^1.14.0",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
"vuedraggable": "^4.1.0",
|
"vuedraggable": "^4.1.0",
|
||||||
"xlsx": "^0.18.5",
|
"xlsx": "^0.18.5",
|
||||||
|
|||||||
@@ -191,8 +191,29 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
<!-- Google Tag Manager -->
|
||||||
|
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||||
|
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||||
|
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||||
|
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||||
|
})(window,document,'script','dataLayer','GTM-PPDRKT7Q');</script>
|
||||||
|
<!-- End Google Tag Manager -->
|
||||||
|
<script>
|
||||||
|
// 페이지 진입 시 GA 페이지뷰 이벤트 전송
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
window.dataLayer.push({
|
||||||
|
event: 'page_view',
|
||||||
|
page_title: document.title,
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Google Tag Manager (noscript) -->
|
||||||
|
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PPDRKT7Q"
|
||||||
|
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||||
|
<!-- End Google Tag Manager (noscript) -->
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>볼링공 속도 계산기</h1>
|
<h1>볼링공 속도 계산기</h1>
|
||||||
|
|
||||||
@@ -206,8 +227,14 @@
|
|||||||
<p>볼링공이 파울라인을 지날 때 '시작'을 누르고, 헤드핀에 도달할 때 '정지'를 누르세요.</p>
|
<p>볼링공이 파울라인을 지날 때 '시작'을 누르고, 헤드핀에 도달할 때 '정지'를 누르세요.</p>
|
||||||
<div class="stopwatch-display" id="stopwatch-display">00:00.000</div>
|
<div class="stopwatch-display" id="stopwatch-display">00:00.000</div>
|
||||||
<div class="stopwatch-container">
|
<div class="stopwatch-container">
|
||||||
<button class="toggle-btn" id="toggle-btn">시작</button>
|
<button class="toggle-btn" id="toggle-btn"
|
||||||
<button class="reset-btn" id="reset-btn">초기화</button>
|
onclick="dataLayer.push({event:'button_click', event_category:'볼스피드', event_label:'스톱워치'});">
|
||||||
|
시작
|
||||||
|
</button> <!-- [GA] 시작 버튼 클릭 추적 -->
|
||||||
|
<button class="reset-btn" id="reset-btn"
|
||||||
|
onclick="dataLayer.push({event:'button_click', event_category:'볼스피드', event_label:'초기화'});">
|
||||||
|
초기화
|
||||||
|
</button> <!-- [GA] 초기화 버튼 클릭 추적 -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -229,8 +256,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button onclick="calculateSpeed()">계산하기</button>
|
<button onclick="dataLayer.push({event:'button_click', event_category:'볼스피드', event_label:'계산하기'}); calculateSpeed()">계산하기</button> <!-- [GA] 계산하기 버튼 클릭 추적 -->
|
||||||
<button onclick="resetValues()">초기화</button>
|
<button onclick="dataLayer.push({event:'button_click', event_category:'볼스피드', event_label:'계산초기화'}); resetValues()">초기화</button> <!-- [GA] 계산초기화 버튼 클릭 추적 -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="results" id="results">
|
<div class="results" id="results">
|
||||||
|
|||||||
@@ -7,7 +7,27 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
// 별도 로직 없음
|
import { useGtag } from 'vue-gtag-next'
|
||||||
|
|
||||||
|
// Google Analytics(GA) 추적용 gtag 인스턴스 사용
|
||||||
|
const gtag = useGtag()
|
||||||
|
|
||||||
|
// 컴포넌트 마운트 시 페이지뷰 이벤트 발생
|
||||||
|
// (퍼블릭 레이아웃 진입 시 추적)
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '퍼블릭 레이아웃',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
})
|
||||||
|
|
||||||
|
// 주요 버튼 클릭 등 액션 추적용 함수 예시
|
||||||
|
const trackPublicAction = (actionName) => {
|
||||||
|
gtag.event('button_click', {
|
||||||
|
event_category: '퍼블릭',
|
||||||
|
event_label: actionName,
|
||||||
|
value: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -5,8 +5,33 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useGtag } from 'vue-gtag-next'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ClubLayout'
|
name: 'ClubLayout',
|
||||||
|
setup() {
|
||||||
|
const gtag = useGtag()
|
||||||
|
|
||||||
|
// 컴포넌트 마운트 시 페이지뷰 이벤트 발생
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '클럽 레이아웃',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
})
|
||||||
|
|
||||||
|
// 이벤트 추적 메서드 예시
|
||||||
|
const trackButtonClick = (buttonName) => {
|
||||||
|
gtag.event('button_click', {
|
||||||
|
'event_category': '클럽',
|
||||||
|
'event_label': buttonName,
|
||||||
|
'value': 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
trackButtonClick
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import App from './App.vue'
|
|||||||
import router from './router'
|
import router from './router'
|
||||||
import './assets/base.css'
|
import './assets/base.css'
|
||||||
|
|
||||||
|
// Google Tag Manager 설정
|
||||||
|
import VueGtag from 'vue-gtag-next'
|
||||||
|
|
||||||
// dayjs configuration
|
// dayjs configuration
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import timezone from 'dayjs/plugin/timezone'
|
import timezone from 'dayjs/plugin/timezone'
|
||||||
@@ -79,6 +82,16 @@ app.use(ToastService)
|
|||||||
app.use(createPinia())
|
app.use(createPinia())
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
||||||
|
// Google Analytics(GA) vue-gtag-next 플러그인 등록
|
||||||
|
app.use(VueGtag, {
|
||||||
|
property: {
|
||||||
|
id: 'GTM-PPDRKT7Q'
|
||||||
|
},
|
||||||
|
appName: '볼링매니저',
|
||||||
|
pageTrackerScreenviewEnabled: true
|
||||||
|
}, router)
|
||||||
|
// GTM-PPDRKT7Q: 구글 태그매니저(GA4) ID
|
||||||
|
|
||||||
// Register custom components
|
// Register custom components
|
||||||
app.component('AppHeader', AppHeader);
|
app.component('AppHeader', AppHeader);
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import adminService from '@/services/adminService';
|
import adminService from '@/services/adminService';
|
||||||
|
|
||||||
@@ -58,7 +59,14 @@ const currentPage = ref(1);
|
|||||||
const rowsPerPage = ref(20);
|
const rowsPerPage = ref(20);
|
||||||
|
|
||||||
// 페이지 로드 시 활동 로그 목록 가져오기
|
// 페이지 로드 시 활동 로그 목록 가져오기
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '활동로그관리',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
await fetchLogs();
|
await fetchLogs();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -248,8 +248,10 @@ import { ref, reactive, onMounted } from 'vue';
|
|||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import adminService from '@/services/adminService';
|
import adminService from '@/services/adminService';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const gtag = useGtag();
|
||||||
|
|
||||||
// 상태 변수
|
// 상태 변수
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
@@ -319,7 +321,14 @@ const member = reactive({
|
|||||||
const canChangeOwner = ref(true);
|
const canChangeOwner = ref(true);
|
||||||
|
|
||||||
// 페이지 로드 시 클럽 목록 가져오기
|
// 페이지 로드 시 클럽 목록 가져오기
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '클럽관리',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
await fetchClubs();
|
await fetchClubs();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from 'vue';
|
import { ref, onMounted, computed } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@@ -206,7 +207,14 @@ const chartOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 컴포넌트 마운트 시 데이터 로드
|
// 컴포넌트 마운트 시 데이터 로드
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '관리자대시보드',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await loadDashboardData();
|
await loadDashboardData();
|
||||||
|
|||||||
@@ -202,12 +202,14 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { getStatusLabel, getStatusSeverity, getSubscriptionStatusLabel, getSubscriptionStatusSeverity, SUBSCRIPTION_STATUS_OPTIONS, SUBSCRIPTION_STATUS_LABELS } from '@/utils/enumMappings';
|
import { getStatusLabel, getStatusSeverity, getSubscriptionStatusLabel, getSubscriptionStatusSeverity, SUBSCRIPTION_STATUS_OPTIONS, SUBSCRIPTION_STATUS_LABELS } from '@/utils/enumMappings';
|
||||||
import { ref, onMounted, computed } from 'vue';
|
import { ref, onMounted, computed, watch } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import adminService from '@/services/adminService';
|
import adminService from '@/services/adminService';
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const gtag = useGtag();
|
||||||
const API_URL = 'http://localhost:3030/api';
|
const API_URL = 'http://localhost:3030/api';
|
||||||
|
|
||||||
// 데이터 정의
|
// 데이터 정의
|
||||||
@@ -272,7 +274,14 @@ const fetchPlanSubscriptions = async (planId) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 컴포넌트 마운트 시 데이터 로드
|
// 컴포넌트 마운트 시 데이터 로드
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '구독플랜관리',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
await fetchPlans();
|
await fetchPlans();
|
||||||
await fetchFeatures();
|
await fetchFeatures();
|
||||||
await fetchClubs();
|
await fetchClubs();
|
||||||
|
|||||||
@@ -125,6 +125,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { getStatusLabel, getRoleName, getRoleSeverity, getStatusSeverity, STATUS_OPTIONS, ROLE_OPTIONS } from '@/utils/enumMappings';
|
import { getStatusLabel, getRoleName, getRoleSeverity, getStatusSeverity, STATUS_OPTIONS, ROLE_OPTIONS } from '@/utils/enumMappings';
|
||||||
import { ref, onMounted, reactive, computed } from 'vue';
|
import { ref, onMounted, reactive, computed } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import adminService from '@/services/adminService';
|
import adminService from '@/services/adminService';
|
||||||
|
|
||||||
@@ -153,7 +154,14 @@ const dialogTitle = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 페이지 로드 시 사용자 목록 가져오기
|
// 페이지 로드 시 사용자 목록 가져오기
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '사용자관리',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
await fetchUsers();
|
await fetchUsers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<Button type="submit" label="로그인" class="w-full" :loading="loading" />
|
<Button type="submit" label="로그인" class="w-full" :loading="loading" />
|
||||||
<div class="register-link">
|
<div class="register-link">
|
||||||
<p>계정이 없으신가요? <a href="#" @click.prevent="showRegisterForm = true">회원가입</a></p>
|
<p>계정이 없으신가요? <a href="#" @click.prevent="showRegisterForm = true; gtag.event('show_register_form', { 'event_category': '인증', 'event_label': '회원가입 폼 표시' });">회원가입</a></p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
|
|
||||||
<Button type="submit" label="회원가입" class="w-full" :loading="loading" />
|
<Button type="submit" label="회원가입" class="w-full" :loading="loading" />
|
||||||
<div class="login-link">
|
<div class="login-link">
|
||||||
<p>이미 계정이 있으신가요? <a href="#" @click.prevent="showRegisterForm = false">로그인</a></p>
|
<p>이미 계정이 있으신가요? <a href="#" @click.prevent="showRegisterForm = false; gtag.event('show_login_form', { 'event_category': '인증', 'event_label': '로그인 폼 표시' });">로그인</a></p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,14 +74,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, inject } from 'vue';
|
import { ref, computed, inject, onMounted } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import authService from '@/services/authService';
|
import authService from '@/services/authService';
|
||||||
|
|
||||||
const user = inject('user');
|
const user = inject('user');
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const gtag = useGtag();
|
||||||
|
|
||||||
const username = ref('');
|
const username = ref('');
|
||||||
const password = ref('');
|
const password = ref('');
|
||||||
@@ -177,6 +179,13 @@ const validateRegisterForm = () => {
|
|||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
if (!validateForm()) return;
|
if (!validateForm()) return;
|
||||||
|
|
||||||
|
// Google Analytics 이벤트 추적 - 로그인 시도
|
||||||
|
gtag.event('login_attempt', {
|
||||||
|
'event_category': '인증',
|
||||||
|
'event_label': '로그인 시도',
|
||||||
|
'value': 1
|
||||||
|
});
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -198,6 +207,12 @@ const handleLogin = async () => {
|
|||||||
// 로그인 성공 메시지
|
// 로그인 성공 메시지
|
||||||
toast.add({ severity: 'success', summary: '성공', detail: '로그인에 성공했습니다.', life: 3000 });
|
toast.add({ severity: 'success', summary: '성공', detail: '로그인에 성공했습니다.', life: 3000 });
|
||||||
|
|
||||||
|
// Google Analytics 이벤트 추적 - 로그인 성공
|
||||||
|
gtag.event('login', {
|
||||||
|
'method': 'id_password',
|
||||||
|
'user_role': userData.role
|
||||||
|
});
|
||||||
|
|
||||||
// 사용자 정보 및 메뉴 아이템 로드 이벤트 발생
|
// 사용자 정보 및 메뉴 아이템 로드 이벤트 발생
|
||||||
window.dispatchEvent(new CustomEvent('user-logged-in'));
|
window.dispatchEvent(new CustomEvent('user-logged-in'));
|
||||||
|
|
||||||
@@ -210,6 +225,13 @@ const handleLogin = async () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('로그인 오류:', error);
|
console.error('로그인 오류:', error);
|
||||||
|
|
||||||
|
// Google Analytics 이벤트 추적 - 로그인 실패
|
||||||
|
gtag.event('login_failed', {
|
||||||
|
'event_category': '인증',
|
||||||
|
'event_label': error.response?.data?.message || '인증 실패',
|
||||||
|
'value': 1
|
||||||
|
});
|
||||||
|
|
||||||
// 오류 메시지 처리
|
// 오류 메시지 처리
|
||||||
const errorMessage = error.response?.data?.message || '로그인에 실패했습니다. 이메일과 비밀번호를 확인해주세요.';
|
const errorMessage = error.response?.data?.message || '로그인에 실패했습니다. 이메일과 비밀번호를 확인해주세요.';
|
||||||
toast.add({ severity: 'error', summary: '오류', detail: errorMessage, life: 3000 });
|
toast.add({ severity: 'error', summary: '오류', detail: errorMessage, life: 3000 });
|
||||||
@@ -222,6 +244,13 @@ const handleLogin = async () => {
|
|||||||
const handleRegister = async () => {
|
const handleRegister = async () => {
|
||||||
if (!validateRegisterForm()) return;
|
if (!validateRegisterForm()) return;
|
||||||
|
|
||||||
|
// Google Analytics 이벤트 추적 - 회원가입 시도
|
||||||
|
gtag.event('sign_up_attempt', {
|
||||||
|
'event_category': '인증',
|
||||||
|
'event_label': '회원가입 시도',
|
||||||
|
'value': 1
|
||||||
|
});
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -235,6 +264,11 @@ const handleRegister = async () => {
|
|||||||
// 회원가입 성공 메시지
|
// 회원가입 성공 메시지
|
||||||
toast.add({ severity: 'success', summary: '성공', detail: '회원가입에 성공했습니다. 로그인해주세요.', life: 3000 });
|
toast.add({ severity: 'success', summary: '성공', detail: '회원가입에 성공했습니다. 로그인해주세요.', life: 3000 });
|
||||||
|
|
||||||
|
// Google Analytics 이벤트 추적 - 회원가입 성공
|
||||||
|
gtag.event('sign_up', {
|
||||||
|
'method': 'form'
|
||||||
|
});
|
||||||
|
|
||||||
// 로그인 폼으로 전환
|
// 로그인 폼으로 전환
|
||||||
showRegisterForm.value = false;
|
showRegisterForm.value = false;
|
||||||
|
|
||||||
@@ -251,6 +285,13 @@ const handleRegister = async () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('회원가입 오류:', error);
|
console.error('회원가입 오류:', error);
|
||||||
|
|
||||||
|
// Google Analytics 이벤트 추적 - 회원가입 실패
|
||||||
|
gtag.event('sign_up_failed', {
|
||||||
|
'event_category': '인증',
|
||||||
|
'event_label': error.response?.data?.message || '회원가입 실패',
|
||||||
|
'value': 1
|
||||||
|
});
|
||||||
|
|
||||||
// 오류 메시지 처리
|
// 오류 메시지 처리
|
||||||
const errorMessage = error.response?.data?.message || '회원가입에 실패했습니다. 다시 시도해주세요.';
|
const errorMessage = error.response?.data?.message || '회원가입에 실패했습니다. 다시 시도해주세요.';
|
||||||
toast.add({ severity: 'error', summary: '오류', detail: errorMessage, life: 3000 });
|
toast.add({ severity: 'error', summary: '오류', detail: errorMessage, life: 3000 });
|
||||||
|
|||||||
@@ -83,6 +83,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, onMounted } from 'vue';
|
import { ref, reactive, computed, onMounted } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import { useVuelidate } from '@vuelidate/core';
|
import { useVuelidate } from '@vuelidate/core';
|
||||||
import { required, email, minLength, sameAs, helpers } from '@vuelidate/validators';
|
import { required, email, minLength, sameAs, helpers } from '@vuelidate/validators';
|
||||||
@@ -134,7 +135,14 @@ const rules = computed(() => ({
|
|||||||
const v$ = useVuelidate(rules, form);
|
const v$ = useVuelidate(rules, form);
|
||||||
|
|
||||||
// 페이지 로드 시 사용자 정보 가져오기
|
// 페이지 로드 시 사용자 정보 가져오기
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '프로필',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
await fetchUserProfile();
|
await fetchUserProfile();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { AVERAGE_CALCULATION_PERIOD_OPTIONS } from '@/utils/enumMappings';
|
import { AVERAGE_CALCULATION_PERIOD_OPTIONS } from '@/utils/enumMappings';
|
||||||
import { ref, computed, onMounted, inject } from 'vue';
|
import { ref, computed, onMounted, inject } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import clubService from '@/services/clubService';
|
import clubService from '@/services/clubService';
|
||||||
@@ -55,7 +56,14 @@ const loading = ref(false);
|
|||||||
const clubNameError = ref('');
|
const clubNameError = ref('');
|
||||||
const clubDescriptionError = ref('');
|
const clubDescriptionError = ref('');
|
||||||
|
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '클럽생성',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
authStore.loadUserInfo();
|
authStore.loadUserInfo();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -81,7 +89,13 @@ const validateForm = () => {
|
|||||||
return isValid;
|
return isValid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 클럽 생성 시도/성공/실패 GA 이벤트 추적
|
||||||
const handleCreateClub = async () => {
|
const handleCreateClub = async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('create_club_attempt', {
|
||||||
|
event_category: '클럽생성',
|
||||||
|
event_label: '클럽 생성 시도'
|
||||||
|
});
|
||||||
if (!validateForm()) return;
|
if (!validateForm()) return;
|
||||||
|
|
||||||
if (!authStore.user) {
|
if (!authStore.user) {
|
||||||
|
|||||||
@@ -130,6 +130,7 @@
|
|||||||
import { AVERAGE_CALCULATION_PERIOD_OPTIONS, getMemberTypeLabel } from '@/utils/enumMappings';
|
import { AVERAGE_CALCULATION_PERIOD_OPTIONS, getMemberTypeLabel } from '@/utils/enumMappings';
|
||||||
|
|
||||||
import { ref, onMounted, computed, inject } from 'vue';
|
import { ref, onMounted, computed, inject } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import { useClubStore } from '@/stores/clubStore';
|
import { useClubStore } from '@/stores/clubStore';
|
||||||
@@ -309,7 +310,13 @@ const getFeatureIcon = (featureType) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 클럽 정보 저장
|
// 클럽 정보 저장
|
||||||
|
// 클럽 정보 저장 버튼 클릭 시 GA 이벤트 추적
|
||||||
const saveClubInfo = async () => {
|
const saveClubInfo = async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('save_club_info', {
|
||||||
|
event_category: '클럽설정',
|
||||||
|
event_label: '클럽 정보 저장'
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
if (!clubId) {
|
if (!clubId) {
|
||||||
router.push('/club');
|
router.push('/club');
|
||||||
|
|||||||
@@ -146,9 +146,11 @@ import { useRouter } from 'vue-router';
|
|||||||
import apiClient from '@/services/api';
|
import apiClient from '@/services/api';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const gtag = useGtag();
|
||||||
|
|
||||||
// 데이터 상태 변수들
|
// 데이터 상태 변수들
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
@@ -260,6 +262,12 @@ const loadDashboardData = async () => {
|
|||||||
|
|
||||||
// 페이지 이동 함수
|
// 페이지 이동 함수
|
||||||
const navigateTo = (path) => {
|
const navigateTo = (path) => {
|
||||||
|
// Google Analytics 이벤트 추적
|
||||||
|
gtag.event('navigation', {
|
||||||
|
'event_category': '대시보드',
|
||||||
|
'event_label': path,
|
||||||
|
'value': 1
|
||||||
|
});
|
||||||
router.push(path);
|
router.push(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -267,6 +275,13 @@ const navigateTo = (path) => {
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
clubId.value = localStorage.getItem('clubId') || null;
|
clubId.value = localStorage.getItem('clubId') || null;
|
||||||
await loadDashboardData();
|
await loadDashboardData();
|
||||||
|
|
||||||
|
// Google Analytics 페이지뷰 추적
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '클럽 대시보드',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
// getEventTypeLabel 중복 import 제거. eventUtils.js의 getEventTypeLabel만 사용.
|
// getEventTypeLabel 중복 import 제거. eventUtils.js의 getEventTypeLabel만 사용.
|
||||||
import { ref, onMounted, computed } from 'vue';
|
import { ref, onMounted, computed } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import FullCalendar from '@fullcalendar/vue3';
|
import FullCalendar from '@fullcalendar/vue3';
|
||||||
@@ -56,7 +57,14 @@ const loading = ref(false);
|
|||||||
const clubId = ref(localStorage.getItem('clubId') || null);
|
const clubId = ref(localStorage.getItem('clubId') || null);
|
||||||
|
|
||||||
// 페이지 로드 시 데이터 가져오기
|
// 페이지 로드 시 데이터 가져오기
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '이벤트캘린더',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
await fetchEvents();
|
await fetchEvents();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -107,13 +115,27 @@ const getEventColor = (eventType) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 캘린더 이벤트 클릭 핸들러
|
// 캘린더 이벤트 클릭 핸들러
|
||||||
|
// 캘린더 이벤트 클릭 시 GA 이벤트 추적
|
||||||
const handleEventClick = (info) => {
|
const handleEventClick = (info) => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('calendar_event_click', {
|
||||||
|
event_category: '이벤트캘린더',
|
||||||
|
event_label: '캘린더 이벤트 클릭',
|
||||||
|
value: info.event.id
|
||||||
|
});
|
||||||
const eventId = info.event.id;
|
const eventId = info.event.id;
|
||||||
viewEventDetails(eventId);
|
viewEventDetails(eventId);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 이벤트 상세 보기
|
// 이벤트 상세 보기
|
||||||
|
// 이벤트 상세보기 클릭 시 GA 이벤트 추적
|
||||||
const viewEventDetails = async (eventId) => {
|
const viewEventDetails = async (eventId) => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('view_event_details', {
|
||||||
|
event_category: '이벤트캘린더',
|
||||||
|
event_label: '이벤트 상세보기',
|
||||||
|
value: eventId
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
selectedEvent.value = await eventService.getEventById(eventId);
|
selectedEvent.value = await eventService.getEventById(eventId);
|
||||||
eventDetailsDialog.value = true;
|
eventDetailsDialog.value = true;
|
||||||
@@ -140,7 +162,13 @@ const removeParticipant = async (participant) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 이벤트 관리 페이지로 이동
|
// 이벤트 관리 페이지로 이동
|
||||||
|
// 이벤트관리 이동 버튼 클릭 시 GA 이벤트 추적
|
||||||
const navigateToEventManagement = () => {
|
const navigateToEventManagement = () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('go_to_event_management', {
|
||||||
|
event_category: '이벤트캘린더',
|
||||||
|
event_label: '이벤트관리 이동'
|
||||||
|
});
|
||||||
router.push('/club/events');
|
router.push('/club/events');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { getEventTypeLabel, getEventStatusLabel, getStatusSeverity } from '@/utils/enumMappings';
|
import { getEventTypeLabel, getEventStatusLabel, getStatusSeverity } from '@/utils/enumMappings';
|
||||||
import { ref, onMounted, computed } from 'vue';
|
import { ref, onMounted, computed } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useClubStore } from '@/stores/clubStore';
|
import { useClubStore } from '@/stores/clubStore';
|
||||||
@@ -203,7 +204,14 @@ const fetchClubMembers = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 컴포넌트 마운트 시 데이터 로드
|
// 컴포넌트 마운트 시 데이터 로드
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '이벤트관리',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
if (!clubId.value) {
|
if (!clubId.value) {
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
@@ -265,7 +273,14 @@ const editEvent = (eventData) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 이벤트 상세 정보 보기
|
// 이벤트 상세 정보 보기
|
||||||
|
// 이벤트 상세보기 클릭 시 GA 이벤트 추적
|
||||||
const viewEventDetails = async (eventData) => {
|
const viewEventDetails = async (eventData) => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('view_event_details', {
|
||||||
|
event_category: '이벤트관리',
|
||||||
|
event_label: '이벤트 상세보기',
|
||||||
|
value: eventData.id
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
const response = await eventService.getEventById(eventData.id);
|
const response = await eventService.getEventById(eventData.id);
|
||||||
event.value = response;
|
event.value = response;
|
||||||
@@ -302,9 +317,16 @@ const confirmDeleteEvent = (eventData) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 이벤트 저장
|
// 이벤트 저장
|
||||||
|
// 이벤트 저장(생성/수정) 시 GA 이벤트 추적
|
||||||
const saveEvent = async (eventData) => {
|
const saveEvent = async (eventData) => {
|
||||||
|
const gtag = useGtag();
|
||||||
try {
|
try {
|
||||||
if (eventData.id) {
|
if (eventData.id) {
|
||||||
|
gtag.event('edit_event', {
|
||||||
|
event_category: '이벤트관리',
|
||||||
|
event_label: '이벤트 수정',
|
||||||
|
value: eventData.id
|
||||||
|
});
|
||||||
// 이벤트 수정
|
// 이벤트 수정
|
||||||
const response = await eventService.updateEvent({
|
const response = await eventService.updateEvent({
|
||||||
...eventData,
|
...eventData,
|
||||||
@@ -312,6 +334,10 @@ const saveEvent = async (eventData) => {
|
|||||||
});
|
});
|
||||||
await fetchEvents(); // 목록 갱신
|
await fetchEvents(); // 목록 갱신
|
||||||
} else {
|
} else {
|
||||||
|
gtag.event('create_event', {
|
||||||
|
event_category: '이벤트관리',
|
||||||
|
event_label: '이벤트 생성'
|
||||||
|
});
|
||||||
// 이벤트 생성
|
// 이벤트 생성
|
||||||
const response = await eventService.createEvent({
|
const response = await eventService.createEvent({
|
||||||
...eventData,
|
...eventData,
|
||||||
@@ -327,6 +353,10 @@ const saveEvent = async (eventData) => {
|
|||||||
});
|
});
|
||||||
hideDialog();
|
hideDialog();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
gtag.event('event_save_fail', {
|
||||||
|
event_category: '이벤트관리',
|
||||||
|
event_label: eventData.id ? '이벤트 수정 실패' : '이벤트 생성 실패'
|
||||||
|
});
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
summary: '오류',
|
summary: '오류',
|
||||||
@@ -337,17 +367,22 @@ const saveEvent = async (eventData) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 이벤트 삭제
|
// 이벤트 삭제
|
||||||
|
// 이벤트 삭제 시 GA 이벤트 추적
|
||||||
const deleteEvent = async () => {
|
const deleteEvent = async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
try {
|
try {
|
||||||
await eventService.deleteEvent(clubId.value, event.value.id);
|
await eventService.deleteEvent(clubId.value, event.value.id);
|
||||||
|
gtag.event('delete_event', {
|
||||||
|
event_category: '이벤트관리',
|
||||||
|
event_label: '이벤트 삭제',
|
||||||
|
value: event.value.id
|
||||||
|
});
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: 'success',
|
severity: 'success',
|
||||||
summary: '성공',
|
summary: '성공',
|
||||||
detail: '이벤트가 삭제되었습니다.',
|
detail: '이벤트가 삭제되었습니다.',
|
||||||
life: 3000
|
life: 3000
|
||||||
});
|
});
|
||||||
|
|
||||||
deleteEventDialog.value = false;
|
deleteEventDialog.value = false;
|
||||||
const index = events.value.findIndex(e => e.id === event.value.id);
|
const index = events.value.findIndex(e => e.id === event.value.id);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
@@ -355,6 +390,11 @@ const deleteEvent = async () => {
|
|||||||
}
|
}
|
||||||
event.value = {};
|
event.value = {};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
gtag.event('delete_event_fail', {
|
||||||
|
event_category: '이벤트관리',
|
||||||
|
event_label: '이벤트 삭제 실패',
|
||||||
|
value: event.value.id
|
||||||
|
});
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
summary: '오류',
|
summary: '오류',
|
||||||
@@ -398,7 +438,13 @@ const goToScoreEntry = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 이벤트 캘린더 페이지로 이동
|
// 이벤트 캘린더 페이지로 이동
|
||||||
|
// 캘린더 이동 버튼 클릭 시 GA 이벤트 추적
|
||||||
const navigateToCalendar = () => {
|
const navigateToCalendar = () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('go_to_calendar', {
|
||||||
|
event_category: '이벤트관리',
|
||||||
|
event_label: '캘린더 이동'
|
||||||
|
});
|
||||||
const url = `/club/calendar?clubId=${clubId.value}`;
|
const url = `/club/calendar?clubId=${clubId.value}`;
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -190,6 +190,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { ref, reactive, computed, onMounted, watch } from 'vue';
|
import { ref, reactive, computed, onMounted, watch } from 'vue';
|
||||||
import clubService from '@/services/clubService';
|
import clubService from '@/services/clubService';
|
||||||
import { useClubStore } from '@/stores/clubStore';
|
import { useClubStore } from '@/stores/clubStore';
|
||||||
@@ -368,7 +369,8 @@ const loadMembers = async () => {
|
|||||||
|
|
||||||
// 새 회원 추가 다이얼로그 열기
|
// 새 회원 추가 다이얼로그 열기
|
||||||
const openNewMemberDialog = () => {
|
const openNewMemberDialog = () => {
|
||||||
member.value = {
|
dialogMode.value = 'new';
|
||||||
|
member.value = {
|
||||||
name: '',
|
name: '',
|
||||||
gender: null,
|
gender: null,
|
||||||
memberTypeObj: null,
|
memberTypeObj: null,
|
||||||
@@ -376,7 +378,6 @@ const openNewMemberDialog = () => {
|
|||||||
email: '',
|
email: '',
|
||||||
handicap: 0
|
handicap: 0
|
||||||
};
|
};
|
||||||
dialogMode.value = 'new';
|
|
||||||
memberDialog.value = true;
|
memberDialog.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -392,6 +393,8 @@ watch(() => member.value.gender, (newGender) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 회원 수정 다이얼로그 열기
|
// 회원 수정 다이얼로그 열기
|
||||||
|
const gtag = useGtag();
|
||||||
|
|
||||||
const editMember = (data) => {
|
const editMember = (data) => {
|
||||||
member.value = {
|
member.value = {
|
||||||
...data
|
...data
|
||||||
@@ -410,12 +413,18 @@ const hideDialog = () => {
|
|||||||
const saveMember = async () => {
|
const saveMember = async () => {
|
||||||
try {
|
try {
|
||||||
const memberData = { ...member.value };
|
const memberData = { ...member.value };
|
||||||
|
|
||||||
const isNew = dialogMode.value === 'new';
|
const isNew = dialogMode.value === 'new';
|
||||||
const response = isNew
|
const response = isNew
|
||||||
? await clubService.addClubMember(clubId.value, memberData)
|
? await clubService.addClubMember(clubId.value, memberData)
|
||||||
: await clubService.updateClubMember(clubId.value, memberData.id, 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({
|
toast.add({
|
||||||
severity: 'success',
|
severity: 'success',
|
||||||
summary: '성공',
|
summary: '성공',
|
||||||
@@ -444,6 +453,12 @@ const deleteMember = async () => {
|
|||||||
try {
|
try {
|
||||||
await clubService.deleteClubMember(clubId.value, selectedMember.value.id);
|
await clubService.deleteClubMember(clubId.value, selectedMember.value.id);
|
||||||
deleteDialog.value = false;
|
deleteDialog.value = false;
|
||||||
|
// Google Analytics 이벤트 추적 - 회원 삭제
|
||||||
|
gtag.event('delete_member', {
|
||||||
|
'event_category': '회원관리',
|
||||||
|
'event_label': '회원 삭제',
|
||||||
|
'value': 1
|
||||||
|
});
|
||||||
toast.add({ severity: 'success', summary: '성공', detail: '회원이 삭제되었습니다.', life: 3000 });
|
toast.add({ severity: 'success', summary: '성공', detail: '회원이 삭제되었습니다.', life: 3000 });
|
||||||
await loadMembers();
|
await loadMembers();
|
||||||
} catch (error) {
|
} 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>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ import { ref, reactive, computed, onMounted } from 'vue';
|
|||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import scoreService from '@/services/scoreService';
|
import scoreService from '@/services/scoreService';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -411,7 +412,13 @@ const calculateTotal = (participant) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 모든 점수 저장
|
// 모든 점수 저장
|
||||||
|
// 점수 저장 버튼 클릭 시 GA 이벤트 추적
|
||||||
const saveAllScores = async () => {
|
const saveAllScores = async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('save_scores', {
|
||||||
|
event_category: '점수관리',
|
||||||
|
event_label: '점수 저장'
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await scoreService.saveScores(meetingId.value, participants.value);
|
await scoreService.saveScores(meetingId.value, participants.value);
|
||||||
@@ -425,7 +432,13 @@ const saveAllScores = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 점수 내보내기 다이얼로그 열기
|
// 점수 내보내기 다이얼로그 열기
|
||||||
|
// 점수 내보내기 버튼 클릭 시 GA 이벤트 추적
|
||||||
const exportScores = () => {
|
const exportScores = () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('export_scores', {
|
||||||
|
event_category: '점수관리',
|
||||||
|
event_label: '점수 내보내기'
|
||||||
|
});
|
||||||
exportContent.value = [exportContentOptions.value[0]];
|
exportContent.value = [exportContentOptions.value[0]];
|
||||||
exportDialog.value = true;
|
exportDialog.value = true;
|
||||||
};
|
};
|
||||||
@@ -446,12 +459,25 @@ const downloadExport = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 뒤로 가기
|
// 뒤로 가기
|
||||||
|
// 뒤로가기 버튼 클릭 시 GA 이벤트 추적
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.event('go_back', {
|
||||||
|
event_category: '점수관리',
|
||||||
|
event_label: '뒤로가기'
|
||||||
|
});
|
||||||
router.push('/clubs/meetings');
|
router.push('/clubs/meetings');
|
||||||
};
|
};
|
||||||
|
|
||||||
// 컴포넌트 마운트 시 데이터 로드
|
// 컴포넌트 마운트 시 데이터 로드
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '점수관리',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
if (!clubId.value) {
|
if (!clubId.value) {
|
||||||
toast.add({ severity: 'error', summary: '오류', detail: '클럽 ID가 설정되지 않았습니다.', life: 3000 });
|
toast.add({ severity: 'error', summary: '오류', detail: '클럽 ID가 설정되지 않았습니다.', life: 3000 });
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="period-selector">
|
<div class="period-selector">
|
||||||
<select v-model="selectedPeriod" @change="loadStatistics">
|
<select v-model="selectedPeriod" @change="onPeriodChange">
|
||||||
<option value="30">최근 30일</option>
|
<option value="30">최근 30일</option>
|
||||||
<option value="90">최근 90일</option>
|
<option value="90">최근 90일</option>
|
||||||
<option value="180">최근 180일</option>
|
<option value="180">최근 180일</option>
|
||||||
@@ -184,6 +184,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, onMounted, computed } from 'vue';
|
import { ref, onMounted, computed } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { Bar as BarChart, Line as LineChart } from 'vue-chartjs';
|
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 { Chart as ChartJS, CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend } from 'chart.js';
|
||||||
import apiClient from '@/services/api';
|
import apiClient from '@/services/api';
|
||||||
@@ -194,6 +195,7 @@ export default {
|
|||||||
name: 'Statistics',
|
name: 'Statistics',
|
||||||
components: { BarChart, LineChart },
|
components: { BarChart, LineChart },
|
||||||
setup() {
|
setup() {
|
||||||
|
const gtag = useGtag();
|
||||||
const stats = ref({
|
const stats = ref({
|
||||||
summary: {},
|
summary: {},
|
||||||
scoreDistribution: [],
|
scoreDistribution: [],
|
||||||
@@ -300,9 +302,25 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
// Google Analytics 페이지뷰 추적
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '통계',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
loadStatistics();
|
loadStatistics();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 기간 변경 시 GA 이벤트
|
||||||
|
const onPeriodChange = () => {
|
||||||
|
gtag.event('change_period', {
|
||||||
|
'event_category': '통계',
|
||||||
|
'event_label': selectedPeriod.value + '일',
|
||||||
|
'value': Number(selectedPeriod.value)
|
||||||
|
});
|
||||||
|
loadStatistics();
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stats,
|
stats,
|
||||||
selectedPeriod,
|
selectedPeriod,
|
||||||
@@ -314,7 +332,8 @@ export default {
|
|||||||
attendanceTrendChartData,
|
attendanceTrendChartData,
|
||||||
attendanceTrendChartOptions,
|
attendanceTrendChartOptions,
|
||||||
participantTrendChartData,
|
participantTrendChartData,
|
||||||
getHandicapTrendChartData
|
getHandicapTrendChartData,
|
||||||
|
onPeriodChange
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -765,7 +765,14 @@ function handleGuestAdded(guest) {
|
|||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '이벤트공개페이지',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
const token = sessionStorage.getItem('event_token_' + publicHash);
|
const token = sessionStorage.getItem('event_token_' + publicHash);
|
||||||
if (token) {
|
if (token) {
|
||||||
fetchEventData();
|
fetchEventData();
|
||||||
|
|||||||
@@ -16,13 +16,21 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { useGtag } from 'vue-gtag-next';
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const message = ref('');
|
const message = ref('');
|
||||||
|
|
||||||
|
// 페이지 진입 시 Google Analytics 페이지뷰 추적
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const gtag = useGtag();
|
||||||
|
gtag.pageview({
|
||||||
|
page_title: '결제실패',
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
page_location: window.location.href
|
||||||
|
});
|
||||||
// URL에서 메시지 가져오기
|
// URL에서 메시지 가져오기
|
||||||
message.value = route.query.message || '결제가 취소되었습니다.';
|
message.value = route.query.message || '결제가 취소되었습니다.';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user