Browse Source

feat(app): 添加页面浏览数据分析功能

- 新增 useAnalysis 组合式函数用于页面浏览数据采集
- 在 App.vue 中集成全局分析逻辑
- 在活动详情、材料详情、我的页面等具体页面中集成分析功能
- 添加浏览记录 API 及相关枚举类型
EvilDragon 2 months ago
parent
commit
b90700adc0

+ 3 - 0
packages/app/src/App.vue

@@ -1,5 +1,8 @@
 <script setup lang="ts">
 import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
+import { useAnalysis } from '@/composables/analysis'
+
+useAnalysis(true, true)
 
 onLaunch(() => {
   console.log('App Launch')

+ 74 - 0
packages/app/src/composables/analysis.ts

@@ -0,0 +1,74 @@
+import { createBrowseHistory, createBrowseRecord } from '@/core/libs/requests'
+import { useUserStore } from '@/store'
+import { storeToRefs } from 'pinia'
+import dayjs from 'dayjs'
+
+export enum AnalysisEventType {
+  LaunchApp = 4,
+  /**
+   * 发布圈子
+   */
+  PublishCircle = 5,
+  /**
+   * 浏览页面
+   */
+  ViewPage = 3,
+}
+export const useAnalysis = (automatic: boolean, isApp = false) => {
+  const userStore = useUserStore()
+  const { userInfo, isLogined } = storeToRefs(userStore)
+  const viewDuration = ref(0)
+  const viewStartAt = ref<Date>()
+  const option = ref<Record<string, any>>({})
+
+  const report = async (type) => {
+    const duration = automatic
+      ? (viewDuration.value = dayjs().diff(viewStartAt.value, 'second'))
+      : 0
+
+    await createBrowseRecord({
+      stylistId: userInfo.value.userId,
+      bizType: type,
+      duration,
+      ...option.value,
+    })
+    viewDuration.value = 0
+    viewStartAt.value = undefined
+    option.value = {}
+  }
+
+  onLaunch(async () => {
+    // if (automatic && isLogined) {
+    //   await createBrowseRecord({
+    //     stylistId: userInfo.value.userId,
+    //     bizType: AnalysisEventType.LaunchApp,
+    //     duration: 1,
+    //   })
+    // }
+  })
+  onLoad(() => {
+    console.log('analysis')
+  })
+  onShow(() => {
+    console.log('show')
+    if (automatic) {
+      viewStartAt.value = new Date()
+      // if (isApp) {
+      //
+      // }
+    }
+  })
+  onHide(async () => {
+    if (automatic) {
+      if (isApp) {
+        await report(AnalysisEventType.LaunchApp)
+      }
+    }
+  })
+  onUnload(async () => {
+    if (automatic) {
+      await report(AnalysisEventType.ViewPage)
+    }
+  })
+  return { option, report }
+}

+ 5 - 0
packages/app/src/core/libs/requests.ts

@@ -794,6 +794,11 @@ export const createBrowseHistory = (data: {
    */
   duration?: string
 }) => httpPost('/app-api/member/designer/browseHistory', data)
+/**
+ * 浏览记录
+ */
+export const createBrowseRecord = (data: any) =>
+  httpPost('/app-api/member/browse-record/create', data)
 export const getBrowseHistories = (query) =>
   httpGet<
     ResPageData<{

+ 5 - 0
packages/app/src/pages/home/activity/detail/index.vue

@@ -43,6 +43,7 @@ import TooltipEvo from '@/components/tooltip-evo.vue'
 import ActivityAsOf from '../../components/activity-as-of.vue'
 import images from '@designer-hub/assets/src/libs/assets/images'
 import { usePermissions } from '../../../../composables/permissions'
+import { useAnalysis } from '@/composables/analysis'
 const themeVars = ref<ConfigProviderThemeVars>({
   tableBorderColor: 'white',
   tabsNavLineBgColor: 'white',
@@ -50,6 +51,7 @@ const themeVars = ref<ConfigProviderThemeVars>({
 })
 const router = useRouter()
 const { clickByPermission } = usePermissions()
+const { option } = useAnalysis(true, false)
 const id = ref()
 const type = ref<'activity' | 'studyTour'>()
 const activityTypes = ref({ activity: '活动', studyTour: '游学' })
@@ -182,6 +184,9 @@ onLoad(async (query: { id: string; type: 'activity' | 'studyTour' }) => {
     signUpsReq.value = () => getStudyTourSignups({ studyId: id.value })
   }
   await setData()
+  option.value = {
+    remark: `最近浏览${{ activity: '活动', studyTour: '游学' }[type.value]}: ${data.value.name}`,
+  }
   const { path } = await uni.getImageInfo({ src: data.value.backgroundUrl })
   const ctx = uni.createCanvasContext('firstCanvas')
   uni

+ 5 - 0
packages/app/src/pages/material/detail/index.vue

@@ -12,8 +12,10 @@ import { handleCall, openLocation, previewImage } from '../../../core/utils/comm
 import router from '@designer-hub/assets/src/assets/svgs/router'
 import { isVideoUrl } from 'wot-design-uni/components/common/util'
 import { useUserStore } from '@/store'
+import { AnalysisEventType, useAnalysis } from '@/composables/analysis'
 
 const userStore = useUserStore()
+const { option } = useAnalysis(true, false)
 const id = ref()
 const { data, run: setData } = useRequest(() => getMaterialDetail({ id: id.value }))
 const { data: materialHomePageData, run: setMaterialHomePageData } = useRequest(
@@ -71,6 +73,9 @@ const handleDownload = () => {
 onLoad(async (query: { id: number }) => {
   id.value = query.id
   await setData()
+  option.value = {
+    remark: `最近浏览品牌: ${data.value?.materialsName}`,
+  }
   await setMaterialHomePageData()
   console.log(data.value)
   await Promise.all([

+ 6 - 0
packages/app/src/pages/mine/index.vue

@@ -26,7 +26,9 @@ import { NetImages } from '../../core/libs/net-images'
 import { qrCodeString2Object, requestToast, toQrCodeString } from '../../core/utils/common'
 import { QrCodeBusinessType } from '../../core/libs/enums'
 import { usePermissions } from '../../composables/permissions'
+import {AnalysisEventType, useAnalysis} from "@/composables/analysis";
 
+const {option, report} = useAnalysis(false)
 const router = useRouter()
 const userStore = useUserStore()
 const { isLogined, userInfo } = storeToRefs(userStore)
@@ -181,6 +183,10 @@ const handleClickScan = async () => {
     if (!features.value.checkInAtStoreTask) return router.push('/pages/mine/authentication/index')
     try {
       await storeAndPunchIn({ id: options.id })
+      option.value = {
+        remark: `最近到店品牌: ${options.name}`,
+      }
+      report(AnalysisEventType.ViewPage)
       // await storeAndPunchIn({ id: 24 })
       router.push(`/pages/mine/scan/result/index?result=${result}`)
     } catch (e) {

+ 3 - 0
packages/app/src/pages/publish/moment/index.vue

@@ -21,7 +21,9 @@ import { requestToast, toast } from '../../../core/utils/common'
 import { messages } from '../../../core/libs/messages'
 import { DataFormSchema } from '../../../components/data-form'
 import { ComponentExposed } from 'vue-component-type-helpers'
+import {AnalysisEventType, useAnalysis} from '@/composables/analysis'
 
+const { report } = useAnalysis(false)
 const router = useRouter()
 const userStore = useUserStore()
 const { userInfo } = storeToRefs(userStore)
@@ -123,6 +125,7 @@ const handleSubmit = async () => {
       publishing.value = false
       router.back()
     }, duration)
+    await report(AnalysisEventType.PublishCircle)
     // publishing.value = false
     // router.back()
   }

+ 6 - 0
packages/merchant/src/components/list-helper-evo.vue

@@ -51,6 +51,12 @@ watch(
     await setData()
   },
 )
+watch(
+  () => props.items,
+  () => {
+    data.value = props.items
+  },
+)
 defineExpose({
   reload: async () => {
     await setData()

+ 2 - 1
packages/merchant/src/pages/agent/designer/detail.vue

@@ -115,6 +115,7 @@ onLoad(async (query) => {
   id.value = query?.id
   await setData()
   await Promise.all([setBrowseRecordCount()])
+  console.log(browseRecordCount.value)
 })
 </script>
 
@@ -253,7 +254,7 @@ onLoad(async (query) => {
                     <div class="text-black/90 text-lg font-bold font-['D-DIN_Exp'] leading-normal">
                       {{ item.value }}
                     </div>
-                    <div class="flex items-center gap-1">
+                    <div class="flex items-center gap-1 whitespace-nowrap">
                       <div
                         class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-none"
                       >