feat(埋点): 添加用户行为追踪功能
在CompleteInfoPage和PosterPage中添加用户行为埋点 新增trackingAPI接口用于发送埋点数据 移除login页面中旧的埋点逻辑
Showing
4 changed files
with
34 additions
and
21 deletions
| 1 | /* | 1 | /* |
| 2 | * @Date: 2025-12-19 10:43:09 | 2 | * @Date: 2025-12-19 10:43:09 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-12-26 11:44:09 | 4 | + * @LastEditTime: 2025-12-26 16:00:49 |
| 5 | * @FilePath: /mlaj/src/api/recall_users.js | 5 | * @FilePath: /mlaj/src/api/recall_users.js |
| 6 | * @Description: 引入外部接口, 召回旧用户相关接口 | 6 | * @Description: 引入外部接口, 召回旧用户相关接口 |
| 7 | */ | 7 | */ |
| 8 | import { fn, fetch } from './fn'; | 8 | import { fn, fetch } from './fn'; |
| 9 | 9 | ||
| 10 | const Api = { | 10 | const Api = { |
| 11 | - USER_LOGIN: '/srv/?a=user_login', | 11 | + USER_LOGIN: '/srv/?a=desk_calendar&t=login', |
| 12 | USER_INFO: '/srv/?a=desk_calendar&t=user_info', | 12 | USER_INFO: '/srv/?a=desk_calendar&t=user_info', |
| 13 | USER_SEARCH_OLD_ACTIVITY: '/srv/?a=desk_calendar&t=search_old_activity', | 13 | USER_SEARCH_OLD_ACTIVITY: '/srv/?a=desk_calendar&t=search_old_activity', |
| 14 | USER_GET_POSTER: '/srv/?a=desk_calendar&t=get_poster', | 14 | USER_GET_POSTER: '/srv/?a=desk_calendar&t=get_poster', |
| 15 | USER_EDIT_POSTER: '/srv/?a=desk_calendar&t=edit_poster', | 15 | USER_EDIT_POSTER: '/srv/?a=desk_calendar&t=edit_poster', |
| 16 | USER_GET_SUPPLEMENT: '/srv/?a=desk_calendar&t=get_supplement', | 16 | USER_GET_SUPPLEMENT: '/srv/?a=desk_calendar&t=get_supplement', |
| 17 | USER_EDIT_SUPPLEMENT: '/srv/?a=desk_calendar&t=edit_supplement', | 17 | USER_EDIT_SUPPLEMENT: '/srv/?a=desk_calendar&t=edit_supplement', |
| 18 | + USER_TRACKING: '/srv/?a=desk_calendar&t=tracking', | ||
| 18 | } | 19 | } |
| 19 | 20 | ||
| 20 | /** | 21 | /** |
| 21 | * @description: 用户登录 | 22 | * @description: 用户登录 |
| 22 | * @param: mobile 手机号 | 23 | * @param: mobile 手机号 |
| 23 | - * @param: password 用户密码 | 24 | + * @param: sms_code 短信验证码 |
| 25 | + * @param: entry 进入H5的入口。qrcode=扫二维码进入, poster=通过海报进入 | ||
| 26 | + * @param: referrer_user_id 海报创建人ID | ||
| 24 | */ | 27 | */ |
| 25 | export const loginAPI = (params) => fn(fetch.post(Api.USER_LOGIN, params)); | 28 | export const loginAPI = (params) => fn(fetch.post(Api.USER_LOGIN, params)); |
| 26 | 29 | ||
| ... | @@ -69,3 +72,11 @@ export const getSupplementAPI = (params) => fn(fetch.get(Api.USER_GET_SUPPLEMENT | ... | @@ -69,3 +72,11 @@ export const getSupplementAPI = (params) => fn(fetch.get(Api.USER_GET_SUPPLEMENT |
| 69 | * @param: note 补充说明 | 72 | * @param: note 补充说明 |
| 70 | */ | 73 | */ |
| 71 | export const editSupplementAPI = (params) => fn(fetch.post(Api.USER_EDIT_SUPPLEMENT, params)); | 74 | export const editSupplementAPI = (params) => fn(fetch.post(Api.USER_EDIT_SUPPLEMENT, params)); |
| 75 | + | ||
| 76 | +/** | ||
| 77 | + * @description: 埋点 | ||
| 78 | + * @param: event_type 事件类型。edit_user=完善用户信息, share_poster=转发海报 | ||
| 79 | + * @param: campaign_id 活动ID(转发海报时填写) | ||
| 80 | + * @param: stu_uid 学员ID(转发海报时填写) | ||
| 81 | + */ | ||
| 82 | +export const trackingAPI = (params) => fn(fetch.post(Api.USER_TRACKING, params)); | ... | ... |
| ... | @@ -83,7 +83,7 @@ import { useRoute, useRouter } from 'vue-router' | ... | @@ -83,7 +83,7 @@ import { useRoute, useRouter } from 'vue-router' |
| 83 | import { useTitle } from '@vueuse/core' | 83 | import { useTitle } from '@vueuse/core' |
| 84 | import { showToast } from 'vant' | 84 | import { showToast } from 'vant' |
| 85 | import { updateUserInfoAPI } from '@/api/users' | 85 | import { updateUserInfoAPI } from '@/api/users' |
| 86 | -import { searchOldActivityAPI } from '@/api/recall_users' | 86 | +import { searchOldActivityAPI, trackingAPI } from '@/api/recall_users' |
| 87 | 87 | ||
| 88 | const starImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/xing@2x.png' | 88 | const starImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/xing@2x.png' |
| 89 | 89 | ||
| ... | @@ -127,6 +127,10 @@ const handleConfirm = async () => { | ... | @@ -127,6 +127,10 @@ const handleConfirm = async () => { |
| 127 | idcard: form.idCard | 127 | idcard: form.idCard |
| 128 | }) | 128 | }) |
| 129 | if (res.code) { | 129 | if (res.code) { |
| 130 | + // 埋点 | ||
| 131 | + trackingAPI({ | ||
| 132 | + event_type: 'edit_user' | ||
| 133 | + }) | ||
| 130 | const activityRes = await searchOldActivityAPI({ | 134 | const activityRes = await searchOldActivityAPI({ |
| 131 | name: form.name, | 135 | name: form.name, |
| 132 | mobile: form.phone, | 136 | mobile: form.phone, | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-12-23 15:50:59 | 2 | * @Date: 2025-12-23 15:50:59 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-12-25 13:22:42 | 4 | + * @LastEditTime: 2025-12-26 16:06:36 |
| 5 | * @FilePath: /mlaj/src/views/recall/PosterPage.vue | 5 | * @FilePath: /mlaj/src/views/recall/PosterPage.vue |
| 6 | * @Description: 分享海报页面 | 6 | * @Description: 分享海报页面 |
| 7 | --> | 7 | --> |
| ... | @@ -46,7 +46,7 @@ import { showToast, showLoadingToast } from 'vant' | ... | @@ -46,7 +46,7 @@ import { showToast, showLoadingToast } from 'vant' |
| 46 | import { qiniuFileHash } from '@/utils/qiniuFileHash' | 46 | import { qiniuFileHash } from '@/utils/qiniuFileHash' |
| 47 | import { useAuth } from '@/contexts/auth' | 47 | import { useAuth } from '@/contexts/auth' |
| 48 | 48 | ||
| 49 | -import { getPosterAPI, editPosterAPI } from '@/api/recall_users' | 49 | +import { getPosterAPI, editPosterAPI, trackingAPI } from '@/api/recall_users' |
| 50 | 50 | ||
| 51 | const $route = useRoute(); | 51 | const $route = useRoute(); |
| 52 | const $router = useRouter(); | 52 | const $router = useRouter(); |
| ... | @@ -167,6 +167,13 @@ const campaign_id = ref($route.query.campaign_id || '') | ... | @@ -167,6 +167,13 @@ const campaign_id = ref($route.query.campaign_id || '') |
| 167 | const title = ref($route.query.title || '活动海报') | 167 | const title = ref($route.query.title || '活动海报') |
| 168 | 168 | ||
| 169 | onMounted(async () => { | 169 | onMounted(async () => { |
| 170 | + // 埋点 | ||
| 171 | + trackingAPI({ | ||
| 172 | + event_type: 'share_poster', | ||
| 173 | + campaign_id: campaign_id.value, | ||
| 174 | + stu_uid: stu_uid.value | ||
| 175 | + }) | ||
| 176 | + | ||
| 170 | if (stu_uid.value && campaign_id.value) { | 177 | if (stu_uid.value && campaign_id.value) { |
| 171 | const { code, data } = await getPosterAPI({ | 178 | const { code, data } = await getPosterAPI({ |
| 172 | stu_uid: stu_uid.value, | 179 | stu_uid: stu_uid.value, | ... | ... |
| ... | @@ -50,7 +50,7 @@ | ... | @@ -50,7 +50,7 @@ |
| 50 | 点击“下一步”,即表示您同意我们的 | 50 | 点击“下一步”,即表示您同意我们的 |
| 51 | <br /> | 51 | <br /> |
| 52 | <span class="text-[#FFDD01] cursor-pointer hover:opacity-80 transition-opacity" | 52 | <span class="text-[#FFDD01] cursor-pointer hover:opacity-80 transition-opacity" |
| 53 | - @click="showAgreement = true; trackClick('view_agreement_link')">《美乐爱觉宇宙用户协议》</span> | 53 | + @click="showAgreement = true">《美乐爱觉宇宙用户协议》</span> |
| 54 | </div> | 54 | </div> |
| 55 | </FrostedGlass> | 55 | </FrostedGlass> |
| 56 | </div> | 56 | </div> |
| ... | @@ -74,7 +74,7 @@ | ... | @@ -74,7 +74,7 @@ |
| 74 | </div> | 74 | </div> |
| 75 | <div class="p-4 border-t border-gray-100 bg-white safe-area-bottom"> | 75 | <div class="p-4 border-t border-gray-100 bg-white safe-area-bottom"> |
| 76 | <van-button block round type="primary" color="linear-gradient(to right, #FFDD01, #E5C600)" | 76 | <van-button block round type="primary" color="linear-gradient(to right, #FFDD01, #E5C600)" |
| 77 | - class="!text-white !font-bold !h-[44px]" @click="showAgreement = false; trackClick('agreement_confirm_btn')"> | 77 | + class="!text-white !font-bold !h-[44px]" @click="showAgreement = false"> |
| 78 | 我已阅读并同意 | 78 | 我已阅读并同意 |
| 79 | </van-button> | 79 | </van-button> |
| 80 | </div> | 80 | </div> |
| ... | @@ -94,7 +94,7 @@ import VideoBackground from '@/components/ui/VideoBackground.vue' | ... | @@ -94,7 +94,7 @@ import VideoBackground from '@/components/ui/VideoBackground.vue' |
| 94 | // 导入接口 | 94 | // 导入接口 |
| 95 | import { smsAPI } from '@/api/common' | 95 | import { smsAPI } from '@/api/common' |
| 96 | import { loginAPI, userInfoAPI } from '@/api/recall_users' | 96 | import { loginAPI, userInfoAPI } from '@/api/recall_users' |
| 97 | -import { useTracking } from '@/composables/useTracking' | 97 | + |
| 98 | // 导入图片 | 98 | // 导入图片 |
| 99 | const titleImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title01@2x.png' | 99 | const titleImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title01@2x.png' |
| 100 | 100 | ||
| ... | @@ -103,18 +103,15 @@ const $route = useRoute() | ... | @@ -103,18 +103,15 @@ const $route = useRoute() |
| 103 | const $router = useRouter() | 103 | const $router = useRouter() |
| 104 | useTitle('登陆') | 104 | useTitle('登陆') |
| 105 | 105 | ||
| 106 | -// TAG: 埋点 | ||
| 107 | -const { trackPageView, trackClick } = useTracking() | ||
| 108 | - | ||
| 109 | onMounted(() => { | 106 | onMounted(() => { |
| 110 | - // TAG: 埋点, 登录页面加载 | ||
| 111 | - trackPageView('login_page') | ||
| 112 | }) | 107 | }) |
| 113 | 108 | ||
| 114 | // Form Data | 109 | // Form Data |
| 115 | const phone = ref('') | 110 | const phone = ref('') |
| 116 | const code = ref('') | 111 | const code = ref('') |
| 117 | const showAgreement = ref(false) | 112 | const showAgreement = ref(false) |
| 113 | +const entry = ref($route.query.entry || '') | ||
| 114 | +const referrer_user_id = ref($route.query.referrer_user_id || '') | ||
| 118 | 115 | ||
| 119 | // Countdown Logic | 116 | // Countdown Logic |
| 120 | const counting = ref(false) | 117 | const counting = ref(false) |
| ... | @@ -125,9 +122,6 @@ let timer = null | ... | @@ -125,9 +122,6 @@ let timer = null |
| 125 | * @description 发送验证码 | 122 | * @description 发送验证码 |
| 126 | */ | 123 | */ |
| 127 | const handleSendCode = async () => { | 124 | const handleSendCode = async () => { |
| 128 | - // TAG: 埋点, 获取验证码按钮点击 | ||
| 129 | - trackClick('send_code_btn', { phone: phone.value }) | ||
| 130 | - | ||
| 131 | if (!phone.value) { | 125 | if (!phone.value) { |
| 132 | showToast('请输入手机号') | 126 | showToast('请输入手机号') |
| 133 | return | 127 | return |
| ... | @@ -166,9 +160,6 @@ const handleSendCode = async () => { | ... | @@ -166,9 +160,6 @@ const handleSendCode = async () => { |
| 166 | * @description 登录/下一步 | 160 | * @description 登录/下一步 |
| 167 | */ | 161 | */ |
| 168 | const handleLogin = async () => { | 162 | const handleLogin = async () => { |
| 169 | - // TAG: 埋点, 登录/下一步按钮点击 | ||
| 170 | - trackClick('login_next_btn', { phone: phone.value }) | ||
| 171 | - | ||
| 172 | if (!phone.value) { | 163 | if (!phone.value) { |
| 173 | showToast('请输入手机号') | 164 | showToast('请输入手机号') |
| 174 | return | 165 | return |
| ... | @@ -179,7 +170,7 @@ const handleLogin = async () => { | ... | @@ -179,7 +170,7 @@ const handleLogin = async () => { |
| 179 | } | 170 | } |
| 180 | 171 | ||
| 181 | try { | 172 | try { |
| 182 | - const res = await loginAPI({ mobile: phone.value, sms_code: code.value }) | 173 | + const res = await loginAPI({ mobile: phone.value, sms_code: code.value, entry: entry.value, referrer_user_id: referrer_user_id.value }) |
| 183 | if (res.code) { | 174 | if (res.code) { |
| 184 | // 获取data里面的 user_id, HTTP_USER_TOKEN, 并设置到后面所有的请求头里面,headers.User-Id, headers.User-Token | 175 | // 获取data里面的 user_id, HTTP_USER_TOKEN, 并设置到后面所有的请求头里面,headers.User-Id, headers.User-Token |
| 185 | const { user_id, HTTP_USER_TOKEN } = res?.data?.user_info || {}; | 176 | const { user_id, HTTP_USER_TOKEN } = res?.data?.user_info || {}; | ... | ... |
-
Please register or login to post a comment