Browse Source
Merge branch 'hongxilin/hotfix-20250625101643-手机输入法弹出输入框上浮' into ds
songjie/feature-20250628160649-上线前优化
Merge branch 'hongxilin/hotfix-20250625101643-手机输入法弹出输入框上浮' into ds
songjie/feature-20250628160649-上线前优化
3 changed files with 218 additions and 211 deletions
@ -1,173 +1,186 @@ |
|||||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue' |
|
||||
import { useRouter } from 'vue-router' |
|
||||
import { computedUsersAPI, useAiGodAPI, updateStayTimeAPI,addUsageAPI } from '@/api/AIxiaocaishen' |
|
||||
|
import { ref, onMounted, onBeforeUnmount, watch } from "vue"; |
||||
|
import { useRouter } from "vue-router"; |
||||
|
import { |
||||
|
computedUsersAPI, |
||||
|
useAiGodAPI, |
||||
|
updateStayTimeAPI, |
||||
|
addUsageAPI, |
||||
|
} from "@/api/AIxiaocaishen"; |
||||
|
|
||||
export function useProjectTracking(projectRoutes) { |
export function useProjectTracking(projectRoutes) { |
||||
const router = useRouter() |
|
||||
const entryTime = ref(Date.now()) |
|
||||
const isInProject = ref(true) |
|
||||
const hasRecordedEntry = ref(sessionStorage.getItem('hasRecordedEntry') === 'true') |
|
||||
// const parentUrl = window.parent.location.href
|
|
||||
// console.log('Link平台地址:', parentUrl)
|
|
||||
|
|
||||
let isPageRefreshing = false // 标志位:是否刷新页面
|
|
||||
|
|
||||
// 记录用户进入项目的时间
|
|
||||
const recordEntryTime = () => { |
|
||||
if (hasRecordedEntry.value) { |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
entryTime.value = Date.now() |
|
||||
const date = new Date(entryTime.value) |
|
||||
const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1) |
|
||||
.toString() |
|
||||
.padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date |
|
||||
.getHours() |
|
||||
.toString() |
|
||||
.padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date |
|
||||
.getSeconds() |
|
||||
.toString() |
|
||||
.padStart(2, '0')}`
|
|
||||
sessionStorage.setItem('projectEntryTime', formattedDate) |
|
||||
sessionStorage.setItem('hasRecordedEntry', 'true') |
|
||||
isInProject.value = true |
|
||||
hasRecordedEntry.value = true |
|
||||
|
|
||||
const token = localStorage.getItem('localToken') |
|
||||
if (token) { |
|
||||
const result = useAiGodAPI({ |
|
||||
token: token |
|
||||
}) |
|
||||
console.log(result); |
|
||||
// const result2 = addUsageAPI({
|
|
||||
// token: token,
|
|
||||
// })
|
|
||||
// console.log(result2);
|
|
||||
}else{ |
|
||||
console.log('没有token'); |
|
||||
} |
|
||||
console.log('记录首次进入时间:', formattedDate) |
|
||||
} |
|
||||
|
|
||||
// 发送追踪数据到后端
|
|
||||
const sendTrackingData = async () => { |
|
||||
if (!isInProject.value) return |
|
||||
|
|
||||
const storedEntryTime = sessionStorage.getItem('projectEntryTime') |
|
||||
if (!storedEntryTime) { |
|
||||
console.warn('未找到存储的进入时间,取消发送跟踪数据') |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
let timestamp |
|
||||
try { |
|
||||
timestamp = new Date(storedEntryTime.replace(' ', 'T')).getTime() |
|
||||
if (isNaN(timestamp)) throw new Error('无效日期') |
|
||||
} catch (error) { |
|
||||
console.error('解析存储的进入时间时出错:', error) |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
const exitTime = Date.now() |
|
||||
const duration = Math.floor((exitTime - timestamp) / 1000) |
|
||||
const localToken = localStorage.getItem('localToken') |
|
||||
console.log('进入项目的时间', storedEntryTime) |
|
||||
console.log('停留时间', duration) |
|
||||
|
|
||||
const params = { |
|
||||
stayTime: duration, |
|
||||
// loginTime: storedEntryTime,
|
|
||||
token: localToken |
|
||||
} |
|
||||
|
|
||||
if (localToken) { |
|
||||
try { |
|
||||
const res = await updateStayTimeAPI(params) |
|
||||
console.log('跟踪数据已发送:', res) |
|
||||
sessionStorage.removeItem('projectEntryTime') |
|
||||
sessionStorage.removeItem('hasRecordedEntry') |
|
||||
isInProject.value = false |
|
||||
hasRecordedEntry.value = false |
|
||||
} catch (error) { |
|
||||
console.error('发送跟踪数据失败:', error) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 页面可见性变化时触发
|
|
||||
const handleVisibilityChange = () => { |
|
||||
// console.log(window.location.pathname.includes('duobaoqibing'), '路径是否包含了页面不可见触发')
|
|
||||
// if (window.location.pathname.includes('duobaoqibing')) {
|
|
||||
// console.log('在 searchCode.html 页面,不发送数据')
|
|
||||
// return
|
|
||||
// }
|
|
||||
if (document.visibilityState === 'hidden') { |
|
||||
console.log('页面不可见,用户可能离开或切换标签页') |
|
||||
sendTrackingData() |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 页面关闭或刷新时触发
|
|
||||
const handleBeforeUnload = (event) => { |
|
||||
// console.log(window.location.pathname)
|
|
||||
// console.log(
|
|
||||
// window.location.pathname.includes('duobaoqibing'),
|
|
||||
// '路径是否包含了页面关闭了啦啦啦啦啦啦触发'
|
|
||||
// )
|
|
||||
// if (window.location.pathname.includes('duobaoqibing')) {
|
|
||||
// console.log('在 searchCode.html 页面,不发送数据')
|
|
||||
// return
|
|
||||
// }
|
|
||||
if (isPageRefreshing) { |
|
||||
console.log('页面刷新,不触发数据发送') |
|
||||
return |
|
||||
} |
|
||||
localStorage.clear(); |
|
||||
console.log('页面即将关闭或跳转') |
|
||||
sendTrackingData() |
|
||||
} |
|
||||
|
|
||||
const handleRefreshDetection = () => { |
|
||||
isPageRefreshing = true |
|
||||
} |
|
||||
|
|
||||
// 监听路由变化
|
|
||||
watch( |
|
||||
() => router.currentRoute.value.path, |
|
||||
(newPath) => { |
|
||||
const isProjectRoute = projectRoutes.some((route) => newPath.startsWith(route)) |
|
||||
let isProjectRouteName = projectRoutes[0] |
|
||||
console.log(isProjectRouteName) |
|
||||
// 判断是否是 searchCode.html 的访问
|
|
||||
const isSearchCodePage = window.location.pathname.includes('duobaoqibing') |
|
||||
if (!isProjectRoute && !isSearchCodePage) { |
|
||||
console.log('离开项目路由:', newPath) |
|
||||
sendTrackingData() |
|
||||
} else if (isProjectRouteName && !hasRecordedEntry.value) { |
|
||||
console.log('首次进入项目路由:', newPath) |
|
||||
recordEntryTime() |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
// 添加事件监听
|
|
||||
onMounted(() => { |
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange) |
|
||||
window.addEventListener('beforeunload', handleBeforeUnload) |
|
||||
window.addEventListener('unload', handleRefreshDetection) |
|
||||
}) |
|
||||
|
|
||||
// 移除事件监听
|
|
||||
onBeforeUnmount(() => { |
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange) |
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload) |
|
||||
window.removeEventListener('unload', handleRefreshDetection) |
|
||||
}) |
|
||||
|
|
||||
return { |
|
||||
entryTime, |
|
||||
isInProject, |
|
||||
sendTrackingData |
|
||||
} |
|
||||
|
const router = useRouter(); |
||||
|
const entryTime = ref(Date.now()); |
||||
|
const isInProject = ref(true); |
||||
|
const hasRecordedEntry = ref( |
||||
|
sessionStorage.getItem("hasRecordedEntry") === "true" |
||||
|
); |
||||
|
// const parentUrl = window.parent.location.href
|
||||
|
// console.log('Link平台地址:', parentUrl)
|
||||
|
|
||||
|
let isPageRefreshing = false; // 标志位:是否刷新页面
|
||||
|
|
||||
|
// 记录用户进入项目的时间
|
||||
|
const recordEntryTime = () => { |
||||
|
if (hasRecordedEntry.value) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
entryTime.value = Date.now(); |
||||
|
const date = new Date(entryTime.value); |
||||
|
const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1) |
||||
|
.toString() |
||||
|
.padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")} ${date |
||||
|
.getHours() |
||||
|
.toString() |
||||
|
.padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date |
||||
|
.getSeconds() |
||||
|
.toString() |
||||
|
.padStart(2, "0")}`;
|
||||
|
sessionStorage.setItem("projectEntryTime", formattedDate); |
||||
|
sessionStorage.setItem("hasRecordedEntry", "true"); |
||||
|
isInProject.value = true; |
||||
|
hasRecordedEntry.value = true; |
||||
|
|
||||
|
const token = localStorage.getItem("localToken"); |
||||
|
if (token) { |
||||
|
const result = useAiGodAPI({ |
||||
|
token: token, |
||||
|
}); |
||||
|
console.log(result); |
||||
|
// const result2 = addUsageAPI({
|
||||
|
// token: token,
|
||||
|
// })
|
||||
|
// console.log(result2);
|
||||
|
} else { |
||||
|
console.log("没有token"); |
||||
|
} |
||||
|
console.log("记录首次进入时间:", formattedDate); |
||||
|
}; |
||||
|
|
||||
|
// 发送追踪数据到后端
|
||||
|
const sendTrackingData = async () => { |
||||
|
if (!isInProject.value) return; |
||||
|
|
||||
|
const storedEntryTime = sessionStorage.getItem("projectEntryTime"); |
||||
|
if (!storedEntryTime) { |
||||
|
console.warn("未找到存储的进入时间,取消发送跟踪数据"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
let timestamp; |
||||
|
try { |
||||
|
timestamp = new Date(storedEntryTime.replace(" ", "T")).getTime(); |
||||
|
if (isNaN(timestamp)) throw new Error("无效日期"); |
||||
|
} catch (error) { |
||||
|
console.error("解析存储的进入时间时出错:", error); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const exitTime = Date.now(); |
||||
|
const duration = Math.floor((exitTime - timestamp) / 1000); |
||||
|
const localToken = localStorage.getItem("localToken"); |
||||
|
console.log("进入项目的时间", storedEntryTime); |
||||
|
console.log("停留时间", duration); |
||||
|
|
||||
|
const params = { |
||||
|
stayTime: duration, |
||||
|
// loginTime: storedEntryTime,
|
||||
|
token: localToken, |
||||
|
}; |
||||
|
|
||||
|
if (localToken) { |
||||
|
try { |
||||
|
const res = await updateStayTimeAPI(params); |
||||
|
console.log("跟踪数据已发送:", res); |
||||
|
sessionStorage.removeItem("projectEntryTime"); |
||||
|
sessionStorage.removeItem("hasRecordedEntry"); |
||||
|
isInProject.value = false; |
||||
|
hasRecordedEntry.value = false; |
||||
|
} catch (error) { |
||||
|
console.error("发送跟踪数据失败:", error); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 页面可见性变化时触发
|
||||
|
const handleVisibilityChange = () => { |
||||
|
// console.log(window.location.pathname.includes('duobaoqibing'), '路径是否包含了页面不可见触发')
|
||||
|
// if (window.location.pathname.includes('duobaoqibing')) {
|
||||
|
// console.log('在 searchCode.html 页面,不发送数据')
|
||||
|
// return
|
||||
|
// }
|
||||
|
if (document.visibilityState === "hidden") { |
||||
|
console.log("页面不可见,用户可能离开或切换标签页"); |
||||
|
sendTrackingData(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 页面关闭或刷新时触发
|
||||
|
const handleBeforeUnload = (event) => { |
||||
|
// console.log(window.location.pathname)
|
||||
|
// console.log(
|
||||
|
// window.location.pathname.includes('duobaoqibing'),
|
||||
|
// '路径是否包含了页面关闭了啦啦啦啦啦啦触发'
|
||||
|
// )
|
||||
|
// if (window.location.pathname.includes('duobaoqibing')) {
|
||||
|
// console.log('在 searchCode.html 页面,不发送数据')
|
||||
|
// return
|
||||
|
// }
|
||||
|
const isRefresh = |
||||
|
performance.navigation?.type === 1 || |
||||
|
performance.getEntriesByType("navigation")[0]?.type === "reload"; |
||||
|
if (isRefresh) { |
||||
|
console.log("页面刷新,不触发数据发送"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
console.log("页面即将关闭或跳转"); |
||||
|
sendTrackingData(); |
||||
|
}; |
||||
|
|
||||
|
const handleRefreshDetection = () => { |
||||
|
isPageRefreshing = true; |
||||
|
}; |
||||
|
|
||||
|
// 监听路由变化
|
||||
|
watch( |
||||
|
() => router.currentRoute.value.path, |
||||
|
(newPath) => { |
||||
|
const isProjectRoute = projectRoutes.some((route) => |
||||
|
newPath.startsWith(route) |
||||
|
); |
||||
|
let isProjectRouteName = projectRoutes[0]; |
||||
|
console.log(isProjectRouteName); |
||||
|
// 判断是否是 searchCode.html 的访问
|
||||
|
const isSearchCodePage = |
||||
|
window.location.pathname.includes("duobaoqibing"); |
||||
|
if (!isProjectRoute && !isSearchCodePage) { |
||||
|
console.log("离开项目路由:", newPath); |
||||
|
sendTrackingData(); |
||||
|
} else if (isProjectRouteName && !hasRecordedEntry.value) { |
||||
|
console.log("首次进入项目路由:", newPath); |
||||
|
recordEntryTime(); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
// 添加事件监听
|
||||
|
onMounted(() => { |
||||
|
document.addEventListener("visibilitychange", handleVisibilityChange); |
||||
|
window.addEventListener("beforeunload", handleBeforeUnload); |
||||
|
window.addEventListener("unload", handleRefreshDetection); |
||||
|
}); |
||||
|
|
||||
|
// 移除事件监听
|
||||
|
onBeforeUnmount(() => { |
||||
|
document.removeEventListener("visibilitychange", handleVisibilityChange); |
||||
|
window.removeEventListener("beforeunload", handleBeforeUnload); |
||||
|
window.removeEventListener("unload", handleRefreshDetection); |
||||
|
}); |
||||
|
|
||||
|
return { |
||||
|
entryTime, |
||||
|
isInProject, |
||||
|
sendTrackingData, |
||||
|
}; |
||||
} |
} |
@ -1,25 +1,24 @@ |
|||||
import { createApp } from 'vue' |
|
||||
import App from './App.vue' |
|
||||
import router from './router' |
|
||||
import ElementPlus from 'element-plus' |
|
||||
import 'element-plus/dist/index.css' |
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue' |
|
||||
// import 'reset-css';
|
|
||||
import { createPinia } from 'pinia' |
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' |
|
||||
import { useAppBridge } from './assets/js/useAppBridge.js' |
|
||||
const { packageFun, fullClose } = useAppBridge() |
|
||||
|
import { createApp } from "vue"; |
||||
|
import App from "./App.vue"; |
||||
|
import router from "./router"; |
||||
|
import ElementPlus from "element-plus"; |
||||
|
import "element-plus/dist/index.css"; |
||||
|
import * as ElementPlusIconsVue from "@element-plus/icons-vue"; |
||||
|
// import 'reset-css';
|
||||
|
import { createPinia } from "pinia"; |
||||
|
import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; |
||||
|
import { useAppBridge } from "./assets/js/useAppBridge.js"; |
||||
|
const { packageFun, fullClose } = useAppBridge(); |
||||
|
|
||||
|
|
||||
const app = createApp(App) |
|
||||
const pinia = createPinia() |
|
||||
pinia.use(piniaPluginPersistedstate) |
|
||||
|
const app = createApp(App); |
||||
|
const pinia = createPinia(); |
||||
|
pinia.use(piniaPluginPersistedstate); |
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { |
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { |
||||
app.component(key, component) |
|
||||
|
app.component(key, component); |
||||
} |
} |
||||
app.use(router) |
|
||||
app.use(ElementPlus) |
|
||||
app.use(pinia) |
|
||||
app.provide('packageFun', packageFun) |
|
||||
app.provide('fullClose', fullClose) |
|
||||
app.mount('#app') |
|
||||
|
app.use(router); |
||||
|
app.use(ElementPlus); |
||||
|
app.use(pinia); |
||||
|
app.provide("packageFun", packageFun); |
||||
|
app.provide("fullClose", fullClose); |
||||
|
app.mount("#app"); |
Write
Preview
Loading…
Cancel
Save
Reference in new issue