Merge branch 'feature/yongpxu-dev' into develop
This commit is contained in:
@@ -59,7 +59,7 @@ export const featureCategories: FeatureCard[] = [
|
||||
"标签化精准推送",
|
||||
"接待模式切换",
|
||||
],
|
||||
path: "/pc/powerCenter/ai-reception",
|
||||
path: "/pc/commonConfigss",
|
||||
},
|
||||
// {
|
||||
// id: "content-library",
|
||||
|
||||
495
Touchkebao/提示词/功能架构.md
Normal file
495
Touchkebao/提示词/功能架构.md
Normal file
@@ -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`(标题“触客宝”等)
|
||||
- 中间区域通过 `<Outlet />` 渲染子路由页面
|
||||
|
||||
---
|
||||
|
||||
## 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 <token>`
|
||||
|
||||
- **响应拦截器逻辑**
|
||||
- 统一假设服务端返回结构:`{ 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, timestamp>)记录请求
|
||||
- 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<T>`
|
||||
- 对 Dexie 的 `Table<T>` 封装:
|
||||
- 增删改查、批量插入/更新、条件查询、分页、排序、统计
|
||||
- 支持 `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 + <Outlet/>) |
|
||||
| |- /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 的基础材料。
|
||||
523
Touchkebao/提示词/触客宝功能逻辑流程图.md
Normal file
523
Touchkebao/提示词/触客宝功能逻辑流程图.md
Normal file
@@ -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
|
||||
<ConfigProvider zhCN>
|
||||
<QueryProvider>
|
||||
<App />
|
||||
</QueryProvider>
|
||||
</ConfigProvider>
|
||||
|
|
||||
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
|
||||
-> 用 <PermissionRoute> 包裹
|
||||
否则
|
||||
-> 直接使用 route.element
|
||||
|
|
||||
v
|
||||
追加 404 路由 { path: "*", element: <NotFound /> }
|
||||
|
|
||||
v
|
||||
useRoutes(routes) 生成路由树并渲染
|
||||
```
|
||||
|
||||
### 2.2 权限路由(登录 & 角色校验)
|
||||
|
||||
```text
|
||||
用户访问受保护路由 (route.auth = true)
|
||||
|
|
||||
v
|
||||
渲染 <PermissionRoute requiredRole={...}>
|
||||
|
|
||||
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: <CkboxPage />, children: [...]
|
||||
|
|
||||
v
|
||||
渲染 CkboxPage:
|
||||
<Layout header={<NavCommon title="触客宝" />}>
|
||||
<Outlet /> // 当前为 WeChatPage
|
||||
</Layout>
|
||||
|
|
||||
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 重连策略等)的专门流程图,可以在此文档基础上再拆分子章节。
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "nkebao"
|
||||
},
|
||||
{
|
||||
"path": "Cunkebao"
|
||||
},
|
||||
{
|
||||
"path": "../../MySelf/好版登项目/好版登小程序"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
Reference in New Issue
Block a user