You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
5.5 KiB

  1. import { ref, onMounted, onBeforeUnmount, watch } from "vue";
  2. import { useRouter } from "vue-router";
  3. import {
  4. computedUsersAPI,
  5. useAiGodAPI,
  6. updateStayTimeAPI,
  7. addUsageAPI,
  8. } from "@/api/AIxiaocaishen";
  9. export function useProjectTracking(projectRoutes) {
  10. const router = useRouter();
  11. const entryTime = ref(Date.now());
  12. const isInProject = ref(true);
  13. const hasRecordedEntry = ref(
  14. sessionStorage.getItem("hasRecordedEntry") === "true"
  15. );
  16. // const parentUrl = window.parent.location.href
  17. // console.log('Link平台地址:', parentUrl)
  18. let isPageRefreshing = false; // 标志位:是否刷新页面
  19. // 记录用户进入项目的时间
  20. const recordEntryTime = () => {
  21. if (hasRecordedEntry.value) {
  22. return;
  23. }
  24. entryTime.value = Date.now();
  25. const date = new Date(entryTime.value);
  26. const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1)
  27. .toString()
  28. .padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")} ${date
  29. .getHours()
  30. .toString()
  31. .padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date
  32. .getSeconds()
  33. .toString()
  34. .padStart(2, "0")}`;
  35. sessionStorage.setItem("projectEntryTime", formattedDate);
  36. sessionStorage.setItem("hasRecordedEntry", "true");
  37. isInProject.value = true;
  38. hasRecordedEntry.value = true;
  39. const token = localStorage.getItem("localToken");
  40. if (token) {
  41. const result = useAiGodAPI({
  42. token: token,
  43. });
  44. console.log(result);
  45. // const result2 = addUsageAPI({
  46. // token: token,
  47. // })
  48. // console.log(result2);
  49. } else {
  50. console.log("没有token");
  51. }
  52. console.log("记录首次进入时间:", formattedDate);
  53. };
  54. // 发送追踪数据到后端
  55. const sendTrackingData = async () => {
  56. if (!isInProject.value) return;
  57. const storedEntryTime = sessionStorage.getItem("projectEntryTime");
  58. if (!storedEntryTime) {
  59. console.warn("未找到存储的进入时间,取消发送跟踪数据");
  60. return;
  61. }
  62. let timestamp;
  63. try {
  64. timestamp = new Date(storedEntryTime.replace(" ", "T")).getTime();
  65. if (isNaN(timestamp)) throw new Error("无效日期");
  66. } catch (error) {
  67. console.error("解析存储的进入时间时出错:", error);
  68. return;
  69. }
  70. const exitTime = Date.now();
  71. const duration = Math.floor((exitTime - timestamp) / 1000);
  72. const localToken = localStorage.getItem("localToken");
  73. console.log("进入项目的时间", storedEntryTime);
  74. console.log("停留时间", duration);
  75. const params = {
  76. stayTime: duration,
  77. // loginTime: storedEntryTime,
  78. token: localToken,
  79. };
  80. if (localToken) {
  81. try {
  82. const res = await updateStayTimeAPI(params);
  83. console.log("跟踪数据已发送:", res);
  84. sessionStorage.removeItem("projectEntryTime");
  85. sessionStorage.removeItem("hasRecordedEntry");
  86. isInProject.value = false;
  87. hasRecordedEntry.value = false;
  88. } catch (error) {
  89. console.error("发送跟踪数据失败:", error);
  90. }
  91. }
  92. };
  93. // 页面可见性变化时触发
  94. const handleVisibilityChange = () => {
  95. // console.log(window.location.pathname.includes('duobaoqibing'), '路径是否包含了页面不可见触发')
  96. // if (window.location.pathname.includes('duobaoqibing')) {
  97. // console.log('在 searchCode.html 页面,不发送数据')
  98. // return
  99. // }
  100. if (document.visibilityState === "hidden") {
  101. console.log("页面不可见,用户可能离开或切换标签页");
  102. sendTrackingData();
  103. }
  104. };
  105. // 页面关闭或刷新时触发
  106. const handleBeforeUnload = (event) => {
  107. // console.log(window.location.pathname)
  108. // console.log(
  109. // window.location.pathname.includes('duobaoqibing'),
  110. // '路径是否包含了页面关闭了啦啦啦啦啦啦触发'
  111. // )
  112. // if (window.location.pathname.includes('duobaoqibing')) {
  113. // console.log('在 searchCode.html 页面,不发送数据')
  114. // return
  115. // }
  116. if (isPageRefreshing) {
  117. console.log('页面刷新,不触发数据发送')
  118. return
  119. }
  120. console.log("页面即将关闭或跳转");
  121. sendTrackingData();
  122. };
  123. const handleRefreshDetection = () => {
  124. isPageRefreshing = true;
  125. };
  126. // 监听路由变化
  127. watch(
  128. () => router.currentRoute.value.path,
  129. (newPath) => {
  130. const isProjectRoute = projectRoutes.some((route) =>
  131. newPath.startsWith(route)
  132. );
  133. let isProjectRouteName = projectRoutes[0];
  134. console.log(isProjectRouteName);
  135. // 判断是否是 searchCode.html 的访问
  136. const isSearchCodePage =
  137. window.location.pathname.includes("duobaoqibing");
  138. if (!isProjectRoute && !isSearchCodePage) {
  139. console.log("离开项目路由:", newPath);
  140. sendTrackingData();
  141. } else if (isProjectRouteName && !hasRecordedEntry.value) {
  142. console.log("首次进入项目路由:", newPath);
  143. recordEntryTime();
  144. }
  145. }
  146. );
  147. // 添加事件监听
  148. onMounted(() => {
  149. document.addEventListener("visibilitychange", handleVisibilityChange);
  150. window.addEventListener("beforeunload", handleBeforeUnload);
  151. window.addEventListener("unload", handleRefreshDetection);
  152. });
  153. // 移除事件监听
  154. onBeforeUnmount(() => {
  155. document.removeEventListener("visibilitychange", handleVisibilityChange);
  156. window.removeEventListener("beforeunload", handleBeforeUnload);
  157. window.removeEventListener("unload", handleRefreshDetection);
  158. });
  159. return {
  160. entryTime,
  161. isInProject,
  162. sendTrackingData,
  163. };
  164. }