feat(admin): 访客详情跨天时间线

- 覆写 detail.vue 占位:档案卡(ID/在线/地理/IP/语言时区/设备/首触来源 utm 标签/
  落地页截断 tooltip)+ 统计 4 项 + 轨迹/会话 Tab
- 轨迹 Tab:按日倒序分组(日期头含会话数)、会话块(时间·来源·active_ms 求和停留)、
  el-timeline 事件行(page_view/page_stay 独立条目/sdk_loaded 图标区分)、
  7/30/90 天切换(reqSeq 守卫)、truncated 提示条、空态
- 会话 Tab:全量会话表,行点击开抽屉看单会话事件序列(getSession)
- keepAlive:onMounted/onActivated/query-watch 三入口统一 ensureLoad,
  loadedVid 去重(query 清空时重置令牌),切访客必刷新
- 顺车 Minor:formatStay 注释与代码对齐;useTable 背对背 if 改 if/else

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-15 21:05:52 +08:00
parent ba31670095
commit ea561c974a
3 changed files with 618 additions and 10 deletions
+4 -5
View File
@@ -404,14 +404,13 @@ function useTableImpl<TApiFn extends (params: any) => Promise<any>>(
return { records: [], total: 0, current: 1, size: 10 }
}
if (!superseded) {
// 状态机:请求失败,进入 error 状态
loadingState.value = 'error'
data.value = []
}
if (superseded) {
// 旧请求的失败交给新请求兜底,不触发错误回调
throw err instanceof Error ? err : new Error(String(err))
} else {
// 状态机:请求失败,进入 error 状态
loadingState.value = 'error'
data.value = []
}
const tableError = handleError(err, '获取表格数据失败')
throw tableError