hookehuyr

feat(埋点): 添加登录页面的埋点功能

在登录页面添加用户行为埋点跟踪,包括页面浏览、协议链接点击、确认按钮点击、验证码发送和登录按钮点击事件
新增useTracking composable用于统一处理埋点逻辑
/*
* @Date: 2025-12-24 13:50:03
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-12-24 14:19:52
* @FilePath: /mlaj/src/composables/useTracking.js
* @Description: 埋点 Composable, 模拟埋点接口请求
*/
/**
* 模拟埋点接口请求
* @param {Object} data 埋点数据
* @returns {Promise}
*/
const mockTrackRequest = (data) => {
return new Promise((resolve) => {
// 模拟网络延迟
setTimeout(() => {
resolve({ code: 200, message: 'success' })
}, 300)
})
}
/**
* 埋点 Composable
* @returns {Object} 包含埋点方法的对象
*/
export function useTracking() {
/**
* 上报埋点事件
* @param {string} eventType - 事件类型 (如 'page_view', 'click', 'custom', 'error')
* @param {string} actionName - 动作名称 (如 'login_btn_click', 'banner_view')
* @param {Object} [extraData={}] - 额外参数 (业务相关的数据)
*/
const trackEvent = async (eventType, actionName, extraData = {}) => {
// 获取当前页面路径 (简单获取,如果在组件setup中使用window.location)
const pagePath = window.location.pathname + window.location.hash
const payload = {
event_type: eventType,
action_name: actionName,
page_path: pagePath,
timestamp: Date.now(),
extra_data: extraData,
// 这里可以扩展更多公共参数,如:
// device_id: '...',
// user_id: '...',
// platform: 'h5'
}
try {
await mockTrackRequest(payload)
} catch (error) {
console.error('埋点上报失败:', error)
}
}
/**
* 快捷方法:页面浏览埋点
* @param {string} [pageName] - 页面名称
* @param {Object} [extraData] - 额外参数
*/
const trackPageView = (pageName, extraData = {}) => {
trackEvent('page_view', 'view', {
page_name: pageName,
...extraData
})
}
/**
* 快捷方法:点击事件埋点
* @param {string} elementName - 元素名称/动作名称
* @param {Object} [extraData] - 额外参数
*/
const trackClick = (elementName, extraData = {}) => {
trackEvent('click', elementName, extraData)
}
return {
trackEvent,
trackPageView,
trackClick
}
}
......@@ -50,7 +50,7 @@
点击“下一步”,即表示您同意我们的
<br />
<span class="text-[#FFDD01] cursor-pointer hover:opacity-80 transition-opacity"
@click="showAgreement = true">《美乐爱觉宇宙用户协议》</span>
@click="showAgreement = true; trackClick('view_agreement_link')">《美乐爱觉宇宙用户协议》</span>
</div>
</FrostedGlass>
</div>
......@@ -74,7 +74,7 @@
</div>
<div class="p-4 border-t border-gray-100 bg-white safe-area-bottom">
<van-button block round type="primary" color="linear-gradient(to right, #FFDD01, #E5C600)"
class="!text-white !font-bold !h-[44px]" @click="showAgreement = false">
class="!text-white !font-bold !h-[44px]" @click="showAgreement = false; trackClick('agreement_confirm_btn')">
我已阅读并同意
</van-button>
</div>
......@@ -84,11 +84,12 @@
</template>
<script setup>
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ref, computed, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { showToast } from 'vant'
import { useTitle } from '@vueuse/core'
import { smsAPI } from '@/api/common'
import { useTracking } from '@/composables/useTracking'
const titleImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title01@2x.png'
const bgImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/bg01@2x.png'
......@@ -98,6 +99,14 @@ const $route = useRoute()
const $router = useRouter()
useTitle($route.meta.title)
// TAG: 埋点
const { trackPageView, trackClick } = useTracking()
onMounted(() => {
// TAG: 埋点, 登录页面加载
trackPageView('login_page')
})
// Form Data
const phone = ref('')
const code = ref('')
......@@ -112,6 +121,9 @@ let timer = null
* @description 发送验证码
*/
const handleSendCode = async () => {
// TAG: 埋点, 获取验证码按钮点击
trackClick('send_code_btn', { phone: phone.value })
if (!phone.value) {
showToast('请输入手机号')
return
......@@ -150,6 +162,9 @@ const handleSendCode = async () => {
* @description 登录/下一步
*/
const handleLogin = () => {
// TAG: 埋点, 登录/下一步按钮点击
trackClick('login_next_btn', { phone: phone.value })
if (!phone.value) {
showToast('请输入手机号')
return
......