From 7a89b80c8f53c8e22b1380dc857a30b2e534bcb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=98=E9=A3=8E?= Date: Tue, 23 Dec 2025 11:52:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=85=8D=E7=BD=AE=E6=8C=AA=E5=88=B0?= =?UTF-8?q?=E5=A4=96=E8=BE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/pc/ckbox/powerCenter/index.data.tsx | 2 +- Touchkebao/提示词/功能架构.md | 495 +++++++++++++++++ Touchkebao/提示词/触客宝功能逻辑流程图.md | 523 ++++++++++++++++++ 3 files changed, 1019 insertions(+), 1 deletion(-) create mode 100644 Touchkebao/提示词/功能架构.md create mode 100644 Touchkebao/提示词/触客宝功能逻辑流程图.md diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/index.data.tsx b/Touchkebao/src/pages/pc/ckbox/powerCenter/index.data.tsx index 7c301af7..63f5827d 100644 --- a/Touchkebao/src/pages/pc/ckbox/powerCenter/index.data.tsx +++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/index.data.tsx @@ -59,7 +59,7 @@ export const featureCategories: FeatureCard[] = [ "标签化精准推送", "接待模式切换", ], - path: "/pc/powerCenter/ai-reception", + path: "/pc/commonConfigss", }, // { // id: "content-library", diff --git a/Touchkebao/提示词/功能架构.md b/Touchkebao/提示词/功能架构.md new file mode 100644 index 00000000..5d12750b --- /dev/null +++ b/Touchkebao/提示词/功能架构.md @@ -0,0 +1,495 @@ +# 触客宝(Touchkebao)功能架构 + +> 本文档描述当前 Touchkebao 前端工程在 **页面路由、状态管理、数据访问、本地缓存和核心业务模块** 维度的功能架构,并附带 ASCII 线框图,便于沟通与扩展设计。 + +## 1. 技术栈与整体结构 + +- **基础框架** + - **React 18 + TypeScript**:单页应用(SPA) + - **Vite**:构建与开发服务器(入口 `src/main.tsx`) + - **UI 组件** + - PC 端:`antd` + - 移动端:`antd-mobile` + - **状态管理**:`zustand`(含自定义持久化封装) + - **请求与数据** + - HTTP:`axios` + 统一封装 `api/request.ts` + - 本地缓存:`Dexie`(IndexedDB,统一封装在 `utils/db.ts`) + - **监控与稳定性** + - `@sentry/react`:初始化于 `main.tsx`,并通过 `App.tsx` 中的 `ErrorBoundary` 做兜底 + - 自定义错误提示与 Toast(`antd-mobile`) + +- **入口初始化流程** + - `src/main.tsx` + - 初始化 Sentry(必须在其他逻辑前) + - 设置 `dayjs` 中文 + - 调用 `initializeDatabaseFromPersistedUser()`: + - 从持久化的 user-store 中恢复上次登录用户 + - 以 `userId` 为维度初始化 Dexie 数据库 + - 渲染根组件: + - `ConfigProvider`(antd 中文配置) + - `QueryProvider`(React Query 统一数据请求层) + - `App` + - `src/App.tsx` + - 使用 `Sentry.ErrorBoundary` 包裹整个应用 + - 内部渲染: + - `AppRouter`(统一路由系统) + - `UpdateNotification`(版本更新提醒,支持自动刷新) + +--- + +## 2. 路由 & 页面模块架构 + +路由集中于 `src/router` 目录,通过 `import.meta.glob` 动态加载模块。 + +### 2.1 路由整体 + +- **核心文件** + - `router/index.tsx` + - 使用 `import.meta.glob("./module/*.{ts,tsx}", { eager: true })` 自动导入所有路由模块 + - 聚合得到 `routes: RouteObject[]` + - 对 `auth: true` 的路由包装 `PermissionRoute` + - 追加通配符 `*` → `404` 页 + - 使用 `BrowserRouter + useRoutes` 渲染 + - `router/permissionRoute.tsx` + - 依赖 `useUserStore` 提供的 `user` 与 `isLoggedIn` + - 未登录时记录当前 `pathname + search`,跳转至 `/login?returnUrl=...` + - 当路由声明 `requiredRole` 时,校验 `user.isAdmin === 1`,否则跳转首页 `/` + +- **路由模块划分** + - `router/module/common.tsx` + - `/` → `Index` 首页:根据终端类型跳转: + - 移动端 → `/mobile/dashboard` + - PC 端 → `/pc/weChat` + - `/login` → 登录页(免登录) + - `/guide` → 产品引导页(需要登录) + - `/init` → iframe 初始化页(嵌入其他系统对接) + - `router/module/pc.tsx` + - `/pc` → `CkboxPage`(PC 端总布局,内含顶部导航) + - 子路由(均需要登录): + - `/pc/commonConfig` → 通用配置中心 + - `/pc/dashboard` → 数据看板 + - `/pc/weChat` → 微信客服工作台(核心聊天场景) + - `/pc/powerCenter` → 能力中心(导航页) + - `/pc/powerCenter/customer-management` → 客户管理 + - `/pc/powerCenter/communication-record` → 沟通记录 + - `/pc/powerCenter/content-management` → 内容管理 & 朋友圈发布 + - `/pc/powerCenter/ai-training` → AI 训练/话术配置 + - `/pc/powerCenter/auto-greeting` → 自动欢迎与自动打招呼 + - `/pc/powerCenter/message-push-assistant` → 消息推送助手 + - `/pc/powerCenter/message-push-assistant/create-push-task/:pushType` → 新建推送任务多步骤向导 + - `/pc/powerCenter/data-statistics` → 数据统计 + - `/pc/powerCenter/push-history` → 推送历史 + - `router/module/mobile.tsx` + - `/profile` → 移动端个人中心/设置页(需要登录) + +### 2.2 页面布局与导航 + +- **PC 布局(`components/Layout`)** + - `Layout.tsx / LayoutFiexd.tsx` + - 支持传入自定义 header(如 `NavCommon`) + - 标准结构: + - 顶部:产品标题、用户信息、全局操作区 + - 中间:左右结构(侧边栏 + 主内容) + +- **PC 触客宝主页面(`pages/pc/ckbox/index.tsx` 及子模块)** + - `CkboxPage`: + - 使用 `Layout` 作为整体页面容器 + - header 为 `NavCommon`(标题“触客宝”等) + - 中间区域通过 `` 渲染子路由页面 + +--- + +## 3. 状态管理架构(Zustand) + +### 3.1 Store 组织方式 + +- **统一出口**:`src/store/index.ts` + - 导出: + - `useUserStore`(用户) + - `useAppStore`(应用级状态) + - `useSettingsStore`(个性化设置) + - `useWebSocketStore`(WebSocket 连接与命令) + - 各种 `createPersistStore`、`persistUtils` 工具 + - 提供: + - `getStores()`:一次性获取所有 store 状态 + - `subscribeToAllStores()`:统一订阅所有 store 变更 + +- **业务模块 Store(节选)** + - `store/module/user.ts` + - 用户信息(id、名字、角色、isAdmin 等) + - 登录状态 `isLoggedIn` 与 token + - 使用 `persist` 中间件,存入 localStorage + - `store/module/app.ts` + - 全局 loading、布局属性、全局配置开关等 + - `store/module/settings.ts` + - 主题、表格密度等个性化设置 + - `store/module/websocket/websocket.ts` + - WebSocket 连接状态(已连接/重连中等) + - `sendCommand` 封装(如 `CmdSendMessage`) + - `store/module/weChat/*` + - 好友/群列表、客户、当前选中会话 + - 聊天消息、分页、群成员 + - AI 对话相关状态与逻辑(见 6 章节) + +### 3.2 权限与登录态 + +- `PermissionRoute` 通过 `useUserStore` 读取: + - `isLoggedIn`:控制是否自动跳转登录页 + - `user.isAdmin`:用于路由级别的角色校验 +- 登录成功后: + - 持久化 user store,以便刷新后仍可恢复 + - `initializeDatabaseFromPersistedUser` 读取该信息并初始化 IndexedDB + +--- + +## 4. 数据访问层(API 封装) + +### 4.1 通用请求封装(`api/request.ts`) + +- **Axios 实例配置** + - `baseURL`:优先取环境变量 `VITE_API_BASE_URL`,否则 `/api` + - 默认 `timeout`:20 秒 + - 默认请求头:`Content-Type: application/json` + - 请求拦截器: + - 从 `useUserStore.getState()` 中读取 `token` + - 自动附加 `Authorization: Bearer ` + +- **响应拦截器逻辑** + - 统一假设服务端返回结构:`{ code, success, msg, data }` + - 判断业务成功: + - 优先看 `code === 200` + - 或 `success === true` + - 若都无,则认为是“透明透传”结构,直接返回原数据 + - 业务失败处理: + - 如果 `code === 401`: + - 清理本地 `token` + - 计算当前路径 `pathname + search` + - 重定向到 `/login?redirect=当前路径` + - 其它错误: + - 根据 `ERROR_SILENT_URLS` 白名单控制是否显示错误 Toast + - 使用 `Toast.show({content: msg || "接口错误"})` 提示 + - 网络错误: + - 仍带白名单控制 + - 默认展示 `"网络异常"` 提示 + +- **请求防抖机制** + - 使用 `debounceMap`(Map)记录请求 + - key 由 `method + url + data` 组成 + - 默认间隔 `DEFAULT_DEBOUNCE_GAP = 1000ms` + - 可通过 `config.debounce = false` 关闭 + - 高频接口白名单 `NO_DEBOUNCE_URLS`(好友/群列表、消息列表)不走防抖 + +- **统一导出函数** + - `request(url, data?, method = "GET", config?, debounceGap?)` + - 自动区分 GET(用 `params`)与非 GET(用 `data`) + - 自动处理 FormData(移除默认 `Content-Type`) + +### 4.2 文件上传封装(`api/common.ts`) + +- `uploadFile(file, uploadUrl = "/v1/attachment/upload")` + - 使用原生 `FormData` 封装文件 + - 根据用户 token 设置 `Authorization` 头 + - 返回后端 `data.url` 作为上传结果 + +### 4.3 业务 API 模块 + +- `api/ai.ts` + - `dataProcessing(params)`:新消息到达后进行预处理(发送到存客宝后台) + - `aiChat(params)`:根据上下文消息生成 AI 回复内容 +- `api/module/wechat.ts` + - 聊天消息列表、群成员、好友/群列表等接口 +- `api/module/group.ts` + - 分组/标签等管理类接口 + +--- + +## 5. 本地数据库架构(IndexedDB + Dexie) + +### 5.1 数据库设计(`utils/db.ts`) + +- **数据库命名** + - 前缀:`CunkebaoDatabase` + - 最终库名:`CunkebaoDatabase_${userId}` + - 每个登录用户一个独立数据库,实现物理隔离 + +- **核心表结构(统一 friend / group 模型)** + - `ChatSession`(会话表) + - `serverId`:主键(使用服务端的 id) + - `userId`:本地用户 ID,用于多用户隔离 + - `type`:`"friend" | "group"` + - 通用字段:`wechatAccountId, nickname, avatar, content, lastUpdateTime` 等 + - 配置字段:`config.unreadCount, config.top` + - 排序字段:`sortKey` + - 扩展字段:`extendFields`(字符串 JSON) + - `Contact`(统一联系人表) + - `serverId`:主键 + - `userId`:用户 ID + - `type`:`"friend" | "group"` + - 通用信息:昵称、备注、头像、地区、签名、搜索 key 等 + - 标签/分组:`groupId` + - 扩展结构:`extendFields` + - `ContactLabelMap`(联系人与标签映射表) + - `serverId`:`${contactId}_${labelId}` + - `labelId`、`contactId`、`contactType` + - 用于按标签筛选联系人、统计 + - `UserLoginRecord`(登录记录表) + - `serverId`: `user_${userId}` + - `lastLoginTime`、`loginCount`、`lastActiveTime` 等 + +- **索引设计** + - 常用组合索引: + - `[userId+type]` + - `[userId+wechatAccountId]` + - `[userId+lastUpdateTime]` + - `sortKey / searchKey` 等 + - 方便实现: + - 会话按更新时间与置顶排序 + - 联系人/会话按关键字搜索 + - 用户/标签多维度筛选 + +### 5.2 数据库管理与代理 + +- `DatabaseManager` + - 负责: + - 根据 `userId` 打开/切换数据库实例 + - 维护 `currentDb` 与 `currentUserId` + - 提供 `ensureDatabase(userId)`、`getCurrentDatabase()` 等方法 + - 支持检测是否已初始化(`isInitialized`)和关闭数据库(`closeCurrentDatabase`) + +- 启动恢复逻辑 + - `initializeDatabaseFromPersistedUser()` + - 读取持久化 user-store(`PERSIST_KEYS.USER_STORE`) + - 解析得到 `user.id` 作为当前 userId + - 调用 `databaseManager.ensureDatabase(userId)` 初始化数据库 + +- 数据库代理对象 + - 使用 `Proxy` 将 `db` 暴露为“当前数据库”的代理 + - 调用侧无需感知内部的实例切换逻辑 + +- 通用 `DatabaseService` + - 对 Dexie 的 `Table` 封装: + - 增删改查、批量插入/更新、条件查询、分页、排序、统计 + - 支持 `createWithServerId` / `createManyWithServerId`,与接口 ID 对齐 + - 基于该服务构建: + - `chatSessionService` + - `contactUnifiedService` + - `contactLabelMapService` + - `userLoginRecordService` + +--- + +## 6. 核心业务:微信客服工作台 + +### 6.1 页面结构(/pc/weChat) + +- 路由:`/pc/weChat` → `pages/pc/ckbox/weChat` +- 典型三栏布局: + 1. 左侧侧边栏 `SidebarMenu` + - 会话列表 MessageList(虚拟列表 + 未读数) + - 好友/群/客户切换 + - 朋友圈入口 + - 添加好友/新建会话入口 + 2. 中间聊天窗口 `ChatWindow` + - 消息列表(`VirtualizedMessageList`) + - 文本、图片、语音、视频、小程序、红包、转账等多种消息类型组件 + - 输入区 `MessageEnter` + - 文本输入框 + - Emoji 表情(`EmojiSeclection`) + - 文件/图片/语音/视频上传(复用 `components/Upload` 系列) + - 支持 AI 建议文案自动填充(quoteMessageContent) + - 辅助弹窗: + - 聊天记录搜索 `ChatRecordSearch` + - 转发消息 `TransmitModal` + - 待办/提醒 `TodoListModal` + 3. 右侧信息栏 `ProfileCard` + - 客户画像与标签 + - 朋友圈动态(`FriendsCicle`) + - 快捷话术(`QuickWords`) + - 与当前会话相关的附加信息 + +### 6.2 微信 Store(`store/module/weChat/weChat.ts`) + +> 使用 `zustand + persist` 管理微信聊天域内的复杂状态。 + +- **状态主体** + - 当前对象与消息: + - `currentContract`: 当前选中的联系人/群(`ContractData | weChatGroup`) + - `currentMessages`: 当前聊天消息数组 + - `currentMessagesPage` / `currentMessagesPageSize` / `currentMessagesHasMore` + - `currentGroupMembers`: 当前群成员列表 + - AI 相关: + - `aiQuoteMessageContent`: AI 接管配置值 + - `quoteMessageContent`: AI 生成的文案草稿,用于填充输入框 + - `isLoadingAiChat`: 是否正在生成 AI 回复 + - 加载与 UI: + - `messagesLoading` / `isLoadingData` + - `showCheckbox`:是否显示多选框 + - `EnterModule`: `"common" | "multipleForwarding"` 等 + - 朋友圈: + - `MomentCommon`: 朋友圈列表 + - `MomentCommonLoading`: 加载标记 + +- **关键行为** + - `setCurrentContact(contract)` + - 切换当前会话: + - 清除 AI 请求队列与定时器 + - 重置当前消息与分页状态 + - 清除未读数(调用 `clearUnreadCount1/2`) + - 拉取 AI 配置(`getFriendInjectConfig`) + - 更新当前会话并调用 `loadChatMessages(true)` 拉取首屏消息 + - `loadChatMessages(Init, pageOverride?)` + - 根据当前联系人是好友/群决定调用 `getChatMessages` 或 `getChatroomMessages` + - 统一消息列表结构,并按时间排序 + - 处理分页信息(page/limit/hasMore) + - 首次加载群聊时同步拉取群成员列表 + - `SearchMessage({From, To, keyword, Count})` + - 在当前会话内按时间 + 关键字搜索消息 + - `receivedMsg(message)` + - 当 WebSocket 收到新消息时调用 + - 若消息属于当前会话: + - 使用 **16ms 批量更新队列**,减少 re-render 次数 + - 针对“对方发送的文字消息”,根据当前会话 `aiType` 触发 AI 逻辑: + - 先将消息加入 `pendingMessages` 队列 + - 3 秒内无更多新消息,则批量发送到 `dataProcessing` + - 再调用 `aiChat` 获取 AI 返回内容 + - 若 `aiType === 2`(AI 接管): + - 构造本地“发送中”消息并追加到 `currentMessages` + - 同时通过 WebSocket `CmdSendMessage` 实际发送 + - 若 `aiType === 1`(AI 辅助): + - 将 AI 文案写入 `quoteMessageContent`,MessageEnter 自动填充输入框 + - `manualTriggerAi()` + - 用户手动点击“智能回复”等按钮,主动触发 AI 回复流程 + +--- + +## 7. 通用组件与能力模块 + +- **选择器组件** + - `AccountSelection / DeviceSelection / ContentSelection / FriendSelection / GroupSelection / PoolSelection / MemberSelection / TwoColumnSelection` + - 特点: + - 支持弹窗选择、多选、搜索 + - 复用同一 API 与数据结构 + - 应用于内容管理、推送任务、新建沟通等多处业务场景 + +- **上传组件** + - 位于 `components/Upload/*` + - 包含: + - `ImageUpload, FileUpload, VideoUpload, AudioUpload, AvatarUpload, ChatFileUpload, SimpleFileUpload, MainImgUpload` + - 与 `uploadFile`(或独立 axios 调用)结合,支持多文件类型与进度回调 + +- **虚拟列表组件** + - `VirtualContactList, VirtualSessionList, VirtualMessageList, InfiniteList` + - 依托 `react-window` 等,实现上万级数据的高性能渲染 + +- **图表组件** + - `LineChart, LineChart2` + - 基于 `echarts-for-react`,主要用于看板与数据统计模块 + +--- + +## 8. ASCII 架构 & 页面线框图 + +### 8.1 系统高层功能架构(模块关系) + +```text ++-------------------------------------------------------------+ +| Touchkebao SPA | +| (React + TS + Vite, Antd, Antd-Mobile, Zustand, Dexie) | ++--------------------------+----------------------------------+ + | + v ++-------------------------------------------------------------+ +| App Shell | +| - App.tsx | +| - Sentry.ErrorBoundary | +| - AppRouter (BrowserRouter + useRoutes) | ++--------------------------+----------------------------------+ + | + v ++-------------------------------------------------------------+ +| Router 层 | +| - / -> Index (设备判断, 跳 /pc/weChat or /mobile) | +| - /login -> Login | +| - /guide -> Guide (auth) | +| - /init -> Iframe Init | +| - /pc/... -> PC 工作台模块 | +| - /profile -> Mobile Profile (auth) | +| - * -> 404 | +| 权限: PermissionRoute + useUserStore | ++--------------------------+----------------------------------+ + | + v ++-------------------------------------------------------------+ +| 业务模块(PC) | +| /pc (CkboxPage: Layout + NavCommon + ) | +| |- /pc/weChat -> 微信客服工作台 | +| |- /pc/dashboard -> 数据看板 | +| |- /pc/commonConfig -> 通用配置 | +| |- /pc/powerCenter/... -> 能力中心子模块 | ++--------------------------+----------------------------------+ + | + v ++-------------------------------------------------------------+ +| 状态与数据层 | +| - zustand stores | +| * user/app/settings/websocket | +| * weChat store (聊天状态 + AI 队列) | +| - api/request.ts (Axios 封装 + Token + 防抖 + Toast) | +| - api/ai.ts, api/module/wechat.ts, group.ts 等 | +| - Dexie IndexedDB (db.ts) | +| * chatSessions / contactsUnified / contactLabelMap | +| * userLoginRecords | ++-------------------------------------------------------------+ +``` + +### 8.2 PC 微信客服工作台页面线框(/pc/weChat) + +```text ++-----------------------------------------------------------------------------------+ +| 顶部导航 NavCommon | +| [ 触客宝 | 用户信息 | 其他入口 ] | ++-----------------------------------------------------------------------------------+ +| | +| +------------------------+------------------------------------+----------------+ | +| | 左侧侧边栏 SidebarMenu | 中间聊天窗口 ChatWindow | 右侧信息栏 | | +| | | | ProfileCard 等 | | +| | - 账号/设备切换 | +------------------------------+ | | | +| | - 会话列表 MessageList| | 聊天消息列表 MessageList | | - 客户画像 | | +| | * 虚拟滚动 | | (VirtualizedMessageList) | | - 朋友圈动态 | | +| | * 未读数 | | - 文本/图片/语音/视频/... | | - 快捷话术 | | +| | - 好友/群/客户列表 | | - 各种系统消息类型组件 | | - AI 配置 | | +| | - 朋友圈入口 | +------------------------------+ | | | +| | - 添加好友/发起会话 | | 输入区 MessageEnter | | | | +| | | | - 文本输入 | | | | +| | | | - 表情 EmojiPicker | | | | +| | | | - 文件/图片/语音/视频上传 | | | | +| | | | - AI 建议文案 (quote…) | | | | +| +------------------------+------------------------------------+----------------+ | +| | ++-----------------------------------------------------------------------------------+ +| 底部(可选):全局提示 / 更新提示 UpdateNotification | ++-----------------------------------------------------------------------------------+ +``` + +### 8.3 PowerCenter 能力中心线框(简版) + +```text ++----------------------------------------------------------------------------+ +| /pc/powerCenter | ++----------------------------------------------------------------------------+ +| 顶部:Tab / 菜单导航 | +| [ 客户管理 ] [ 沟通记录 ] [ 内容管理 ] [ AI 训练 ] [ 自动欢迎 ] [ 推送助手 ] ... | ++----------------------------------------------------------------------------+ +| 内容区:根据当前子路由渲染 | +| - 客户管理: 列表 + 筛选 + 详情侧滑抽屉 | +| - 沟通记录: 时间线/列表 + 搜索 | +| - 内容管理: 素材列表 + 编辑弹窗 + 预览 + 定时发布配置 | +| - AI 训练: 话术库配置、模型参数设置 | +| - 自动欢迎: 规则列表 + 开关 + 编辑 | +| - 推送助手: 创建推送任务多步骤向导(选择账号 -> 选人群 -> 配置内容 -> 发送) | ++----------------------------------------------------------------------------+ +``` + +--- + +以上内容即为当前 Touchkebao 前端工程的高层功能架构说明,可作为后续架构演进、文档输出、分享 PPT 的基础材料。 diff --git a/Touchkebao/提示词/触客宝功能逻辑流程图.md b/Touchkebao/提示词/触客宝功能逻辑流程图.md new file mode 100644 index 00000000..94ca709e --- /dev/null +++ b/Touchkebao/提示词/触客宝功能逻辑流程图.md @@ -0,0 +1,523 @@ +## 触客宝功能逻辑实现流程图 + +> 本文档基于《触客宝功能架构》整理关键业务链路的**实现流程**,以文本 + ASCII 流程图的形式展示前端在不同场景下的调用关系,便于开发/排查问题与架构沟通。 + +--- + +## 一、应用启动 & 初始化流程 + +### 1.1 启动总体流程 + +```text +浏览器访问页面 + | + v +加载 index.html & Vite 入口脚本 + | + v +执行 src/main.tsx + | + v +初始化 Sentry (initSentry) + | + v +initializeDatabaseFromPersistedUser() + | + +-- 读取 localStorage 中 USER_STORE + | | + | +-- 无用户信息 -> 不初始化 DB -> 返回 null + | | + | +-- 有用户信息 -> 解析 user.id -> ensureDatabase(userId) + | | + | +-- DatabaseManager 创建/打开 Dexie DB + | + v +创建 React Root + | + v + + + + + + | + v +App.tsx 内部: + Sentry.ErrorBoundary 包裹 AppRouter + UpdateNotification +``` + +--- + +## 二、路由跳转 & 权限控制流程 + +### 2.1 路由解析与渲染 + +```text +AppRouter 渲染 + | + v +import.meta.glob("./module/*.{ts,tsx}") + | + v +收集所有路由模块 default 导出路由数组 + | + v +组合得到 routes[] + | + v +对每个 route: + 如果 route.auth === true + -> 用 包裹 + 否则 + -> 直接使用 route.element + | + v +追加 404 路由 { path: "*", element: } + | + v +useRoutes(routes) 生成路由树并渲染 +``` + +### 2.2 权限路由(登录 & 角色校验) + +```text +用户访问受保护路由 (route.auth = true) + | + v +渲染 + | + v +从 useUserStore 读取 user, isLoggedIn + | + +-- 若 !isLoggedIn 或 !user + | | + | +-- 记录当前路径 currentPath = pathname + search + | | + | +-- navigate("/login?returnUrl=" + encodeURIComponent(currentPath)) + | | + | +-- 不渲染子组件 (return null) + | + +-- 若 requiredRole 存在 且 user.isAdmin !== 1 + | | + | +-- navigate("/") + | +-- return null + | + +-- 否则 (已登录 & 权限满足) + | + +-- 渲染 children (真正的业务页面) +``` + +--- + +## 三、首页访问 & 端类型分流流程 + +### 3.1 `/` 首页逻辑 + +```text +用户访问 "/" 路径 + | + v +渲染 IndexPage (pages/index.tsx) + | + v +useEffect(() => { + 判断是否移动端: + - UA 匹配移动端关键字 + - 或 window.innerWidth <= 768 +}) + | + +-- 若 isMobile === true + | | + | +-- navigate("/mobile/dashboard") + | + +-- 若 isMobile === false + | + +-- navigate("/pc/weChat") + | + v +页面本身只渲染简单 "首页" 占位,主要职责是分流 +``` + +--- + +## 四、登录流程 & 本地缓存初始化 + +> 下面为前端视角,后端返回细节略去,仅关注状态/存储/跳转。 + +```text +用户在 /login 输入账号密码 + | + v +点击登录按钮 -> 触发登录 API + | + v +调用 request("/login", formData, "POST") + | + v +Axios 请求拦截器: + - 若有 token 则附加 Authorization (首次通常无) + | + v +服务器返回登录结果 { code/success, data: { user, token } } + | + v +响应拦截器: + - 判断业务成功 + - 返回 data (user, token) + | + v +前端登录逻辑: + - 调用 useUserStore.setState(): + * 保存 user 信息 + * 保存 token + * 标记 isLoggedIn = true + - 按 returnUrl 或默认路径跳转: + * 若 URL 中有 ?returnUrl=xxx -> navigate(xxx) + * 否则 -> navigate("/") + | + v +后续刷新页面: + - main.tsx 中 initializeDatabaseFromPersistedUser() + - 根据持久化 user.id 初始化对应 Dexie 数据库 +``` + +--- + +## 五、PC 端微信客服工作台整体流程(/pc/weChat) + +### 5.1 页面三栏布局渲染流程 + +```text +用户访问 "/pc/weChat" + | + v +路由匹配 pc.tsx 中: + path: "/pc", element: , children: [...] + | + v +渲染 CkboxPage: + }> + // 当前为 WeChatPage + + | + v +WeChatPage 内部: + - 左侧 SidebarMenu (会话列表 / 联系人列表 / 朋友圈入口) + - 中间 ChatWindow (消息列表 + 输入框) + - 右侧 ProfileCard 等(客户画像/朋友圈/话术等) +``` + +### 5.2 选择会话 & 加载消息流程 + +```text +用户在 SidebarMenu 中点击某个好友/群聊 + | + v +onContactClick(contact) 触发 + | + v +useWeChatStore.setCurrentContact(contact) + | + v +setCurrentContact 内部逻辑: + 1) 清除 AI 请求定时器 & 队列 (防止跨会话 AI 干扰) + 2) 重置当前聊天状态: + - currentMessages = [] + - currentMessagesPage = 1 + - currentMessagesHasMore = true + - isLoadingAiChat = false + 3) 构造 params: + - 单聊: wechatFriendId = contact.id + - 群聊: wechatChatroomId = contact.id + 4) 调用 clearUnreadCount1/2 清空未读 + 5) 调用 getFriendInjectConfig 获取 AI 配置 + -> 更新 aiQuoteMessageContent + 6) 更新 currentContract = contact + 并更新 currentMessagesRequestId + 7) 调用 updateConfig({ id: contact.id, config: { chat: true } }) + 8) 调用 state.loadChatMessages(true) 拉取首屏消息 +``` + +### 5.3 拉取聊天消息流程(首屏 & 翻页) + +```text +调用 loadChatMessages(Init, pageOverride?) + | + v +从 store 读取: + - currentContract + - currentMessagesPage / PageSize / HasMore + - currentMessagesRequestId + | + +-- 若无 currentContract 或 id -> 直接返回 + +-- 若 !Init 且 !HasMore -> 不再请求 + +-- 若 messagesLoading && !Init -> 避免并发重复加载 + | + v +计算 nextPage: + - Init === true ? 1 : (pageOverride || currentPage + 1) + limit = currentMessagesPageSize (默认 20) + | + v +构造请求参数 params: + - wechatAccountId: contact.wechatAccountId + - page, limit + - 单聊: wechatFriendId = contact.id + - 群聊: wechatChatroomId = contact.id + | + v +根据是否群聊: + - 群聊: 调用 getChatroomMessages(params) + - 单聊: 调用 getChatMessages(params) + | + v +normalizeMessages(response) 标准化为数组 + | + v +sortMessagesByTime(messages) 统一按时间排序 + | + v +resolvePaginationState(response, page, limit, listLength) + | + v +若 Init 且为群聊: + - 额外调用 getGroupMembers({ id: contact.id }) + | + v +set(state => { + 若 currentMessagesRequestId 未变化 && currentContract.id 未变化 + - Init: currentMessages = sortedMessages + - 非 Init: currentMessages = [...sortedMessages, ...原有] + - 更新 currentGroupMembers (群聊首屏时) + - 更新 page / limit / hasMore +}) +``` + +--- + +## 六、新消息接收 & AI 自动回复流程 + +### 6.1 新消息接收(WebSocket → Store) + +```text +WebSocket 收到新消息 (CmdNewMessage) + | + v +WebSocket 层解析消息 -> 调用 useWeChatStore.receivedMsg(message) + | + v +receivedMsg(message) 内部: + 1) 判断消息归属: + - getMessageId = message.wechatChatroomId || message.wechatFriendId + - isWechatGroup = !!message.wechatChatroomId + 2) 判断是否为当前选中会话: + - 若 currentContract && currentContract.id == getMessageId + -> 进入“当前会话处理分支” + - 否则 + -> 当前函数不更新会话列表,MessageList 通过其他事件更新 +``` + +### 6.2 当前会话消息的批量渲染优化 + +```text +当前会话处理分支: + | + v +将 message 推入 messageBatchQueue + | + v +若已有 messageBatchTimer: + -> clearTimeout(messageBatchTimer) + | + v +设置新的 messageBatchTimer (延迟 ~16ms): + | + v +定时器触发: + - 拷贝 messageBatchQueue -> messagesToAdd + - 清空 messageBatchQueue + - set(state => { + currentMessages = [...state.currentMessages, ...messagesToAdd] + }) + | + v +实现一帧内多条消息合并更新,降低渲染压力 +``` + +### 6.3 AI 自动回复决策流程 + +```text +在 receivedMsg 中 (仍然是当前会话分支): + | + v +若 message.msgType === 1 (文字) 且 !message.isSend + 且 currentContract.aiType in [1, 2] + | + v +AI 触发逻辑: + 1) 若存在 aiRequestTimer 或 currentAiGenerationId: + - 调用 clearAiRequestQueue("收到新消息") + - 清除上一次 AI 请求状态 + 2) 将当前 message 加入 pendingMessages 队列 + 3) set({ isLoadingAiChat: true }) + 4) 启动 aiRequestTimer (延迟 AI_REQUEST_DELAY=3000ms): + | + v + 定时器回调: + - 复制 pendingMessages -> messagesToProcess + - 清空 pendingMessages, 清除 aiRequestTimer + - 生成 generationId = generateAiId() + - currentAiGenerationId = generationId + - 构造 dataProcessing 参数: + * type: "CmdNewMessage" + * wechatAccountId + * chatroomMessage 或 friendMessage = messagesToProcess + - 调用 dataProcessing(params) + - 若 dataProcessingResult 不为成功标志 (注意实际判断逻辑) + -> 取最后一条消息 lastMessage + -> 调用 aiChat({ friendId/getMessageId, wechatAccountId, message: lastMessage }) + -> 得到 aiResponseContent + -> 若 currentAiGenerationId 仍等于 generationId (确保未被取消) + | + v + 根据 aiType 分支: + - aiType === 2 (AI 接管模式) + * 构造本地发送消息 localMessage + * 将 localMessage append 到 currentMessages + * 调用 useWebSocketStore.sendCommand("CmdSendMessage", {...}) + * set({ isLoadingAiChat: false }) + * 清空 currentAiGenerationId + - aiType === 1 (AI 辅助模式) + * set({ + quoteMessageContent: aiResponseContent, + isLoadingAiChat: false + }) + * 清空 currentAiGenerationId + - 若中途任何错误: + -> 打印错误日志 + -> set({ isLoadingAiChat: false }) + -> currentAiGenerationId = null +``` + +### 6.4 手动触发 AI 回复流程 + +```text +用户在 UI 中点击“智能回复”按钮 + | + v +调用 manualTriggerAi() + | + v +manualTriggerAi 逻辑: + 1) 读取 currentContract, currentMessages + 2) 若无 currentContract 或 currentMessages 为空 -> 返回 false + 3) 校验 aiType in [1, 2],否则不触发 + 4) 若已有 aiRequestTimer 或 currentAiGenerationId: + -> clearAiRequestQueue("手动重新生成") + 5) 从 currentMessages 中过滤最近 5 条对方文本消息 recentMessages + 6) set({ isLoadingAiChat: true }) + 7) 生成 generationId, 记录到 currentAiGenerationId + 8) 调用 aiChat({ friendId, wechatAccountId, message: lastMessage }) + 9) 根据 aiType: + - aiType === 2: + * 构造本地消息 localMessage,append 到 currentMessages + * sendCommand("CmdSendMessage", {...}) + * set({ isLoadingAiChat: false }) + - aiType === 1: + * updateQuoteMessageContent(aiResponseContent) + * set({ isLoadingAiChat: false }) + 10) 清空 currentAiGenerationId +``` + +--- + +## 七、消息搜索 & 历史记录查看流程 + +```text +用户在聊天窗口打开“聊天记录搜索”面板 + | + v +选择时间范围 (From, To)、输入关键字 keyword、设置数量 Count + | + v +调用 useWeChatStore.SearchMessage({ From, To, keyword, Count }) + | + v +SearchMessage 内部: + 1) set({ messagesLoading: true }) + 2) 判断当前会话是群聊还是单聊 + 3) 构造 params: + - wechatAccountId + - keyword + - From, To + - page = 1 + - limit = Count + - 单聊: wechatFriendId + - 群聊: wechatChatroomId + 4) 调用对应 API: + - 群聊: getChatroomMessages(params) + getGroupMembers({ id }) + - 单聊: getChatMessages(params) + 5) 对返回结果: + - normalizeMessages -> sortMessagesByTime + - set({ + currentMessages, + currentGroupMembers (群聊), + currentMessagesPage = 1, + currentMessagesHasMore = false, + currentMessagesPageSize = Count + }) + 6) finally: set({ messagesLoading: false }) +``` + +--- + +## 八、PowerCenter 能力中心典型流程(示例:创建消息推送任务) + +> 这里只给出“消息推送助手”的高层流程,实际每个步骤内部还会调用共用选择组件和上传组件。 + +```text +用户访问 "/pc/powerCenter/message-push-assistant" + | + v +展示推送任务列表 + “新建推送任务”按钮 + | + v +点击“新建推送任务” + | + v +navigate("/pc/powerCenter/message-push-assistant/create-push-task/:pushType") + | + v +渲染 CreatePushTask 页面 (多步骤向导): + Step 1: StepSelectAccount + - 使用 AccountSelection / DeviceSelection 组件 + - 选择推送使用的微信/设备账号 + Step 2: StepSelectContacts + - 调用联系人/分组相关 API + - 使用 FriendSelection / GroupSelection / PoolSelection 等组件 + - 支持搜索/筛选与多选 + Step 3: StepPushParams + - 设置推送参数 (时间、频次、规则等) + Step 4: StepSendMessage + - 选择消息内容: + * 直接输入文本 + * 从内容库选择: ContentSelection + 内容管理 API + - 支持图片/文件/视频等资源上传 (复用 Upload 组件) + | + v +完成配置 -> 点击“创建任务” + | + v +调用创建任务 API + | + v +成功后: + - 弹出成功提示 + - 跳转回任务列表或详情页 + - 列表数据可能通过 React Query 或手动刷新获取最新状态 +``` + +--- + +以上流程图覆盖了应用启动、路由与权限、登录、PC 微信客服工作台、AI 自动回复、消息搜索以及能力中心中一个典型场景的端到端逻辑,可作为排查问题和设计新功能时的“全局参考图”。 +如需更详细的**时序图(Sequence Diagram)**或针对某个子模块(例如 IndexedDB 同步、WebSocket 重连策略等)的专门流程图,可以在此文档基础上再拆分子章节。