diff --git a/src/genernal-business/session.md b/src/genernal-business/session.md new file mode 100644 index 0000000..8429065 --- /dev/null +++ b/src/genernal-business/session.md @@ -0,0 +1,1478 @@ +# 会话与消息功能文档 + +## 1. 功能概述 + +参考自:`oak-general-business/src/entities/Session.ts`、`oak-general-business/src/entities/SessionMessage.ts`、`oak-general-business/src/entities/Message.ts`、`oak-general-business/src/entities/Notification.ts` + +### 1.1 功能目的 + +会话与消息功能是 oak-general-business 中的核心通信模块,提供了完整的用户间交互和系统通知能力。该功能模块主要解决以下问题: + +1. **用户会话管理**:支持用户与不同实体(应用、用户等)之间建立对话会话 +2. **实时消息收发**:支持文本、图片、语音、视频等多种消息类型的即时通讯 +3. **多渠道消息推送**:支持微信小程序、公众号、短信、邮件等多种渠道的消息通知 +4. **系统消息管理**:提供统一的系统级消息推送和管理能力 +5. **消息状态追踪**:跟踪消息的发送状态和用户阅读状态 + +### 1.2 应用场景 + +- **客服系统**:用户与客服之间的在线咨询和沟通 +- **微信生态集成**:与微信公众号、小程序的客服消息互通 +- **系统通知**:订单状态变更、活动提醒等业务通知 +- **消息提醒**:通过多渠道向用户推送重要信息 +- **用户互动**:用户之间的私信和交流 + +### 1.3 核心价值 + +1. **统一的消息架构**:将会话消息和系统通知统一管理,简化开发复杂度 +2. **多渠道适配**:自动根据用户配置和消息优先级选择合适的推送渠道 +3. **微信深度集成**:原生支持微信公众号和小程序的客服消息功能 +4. **灵活的消息模板**:支持不同类型消息使用不同的推送模板 +5. **完整的状态管理**:从消息发送到用户阅读的全流程状态追踪 + +### 1.4 与其他功能模块的关系 + +```mermaid +graph TB + Session[会话模块] --> User[用户系统] + Session --> Application[应用管理] + SessionMessage[会话消息] --> Session + SessionMessage --> WechatUser[微信用户] + SessionMessage --> ExtraFile[文件管理] + + Message[系统消息] --> User + Message --> MessageType[消息类型] + Message --> Platform[平台管理] + + MessageSystem[消息系统连接] --> Message + MessageSystem --> System[系统配置] + + Notification[通知] --> MessageSystem + Notification --> Application + + MessageTypeTemplate[消息模板关联] --> MessageType + MessageTypeTemplate --> WechatTemplate[微信模板] + + MessageTypeSmsTemplate[短信模板关联] --> MessageType + MessageTypeSmsTemplate --> SmsTemplate[短信模板] +``` + +### 1.5 功能特点 + +- ✅ 支持多种消息类型(文本、图片、语音、视频、链接、小程序卡片等) +- ✅ 支持多平台会话(Web、微信公众号、微信小程序) +- ✅ 自动创建和管理会话 +- ✅ 消息实时订阅和推送 +- ✅ 支持消息优先级(高、中、低) +- ✅ 多渠道消息通知(微信、短信、邮件、极光推送等) +- ✅ 消息模板化管理 +- ✅ 消息发送状态跟踪 +- ✅ 消息已读/未读状态管理 +- ✅ 微信客服消息自动回复 + +--- + +## 2. 实体定义详解 + +参考自: +- `oak-general-business/src/entities/Session.ts` +- `oak-general-business/src/entities/SessionMessage.ts` +- `oak-general-business/src/entities/Message.ts` +- `oak-general-business/src/entities/MessageType.ts` +- `oak-general-business/src/entities/MessageSystem.ts` +- `oak-general-business/src/entities/MessageTypeTemplate.ts` +- `oak-general-business/src/entities/MessageTypeSmsTemplate.ts` +- `oak-general-business/src/entities/Notification.ts` + +### 2.1 实体关系图 + +```mermaid +erDiagram + Session ||--o{ SessionMessage : contains + Session }o--|| User : belongs_to + Session }o--|| Entity : associates + + SessionMessage }o--|| Session : belongs_to + SessionMessage }o--o| User : sent_by + SessionMessage }o--o| WechatUser : from_wechat + SessionMessage }o--|| Application : in_app + SessionMessage ||--o{ ExtraFile : has_files + + Message }o--|| User : notifies + Message }o--|| MessageType : has_type + Message }o--o| Platform : targets + Message ||--o{ MessageSystem : distributed_to + + MessageSystem }o--|| Message : belongs_to + MessageSystem }o--|| System : in_system + MessageSystem ||--o{ Notification : generates + + Notification }o--|| MessageSystem : belongs_to + Notification }o--o| Application : via_app + + MessageType ||--o{ MessageTypeTemplate : has_wechat_templates + MessageType ||--o{ MessageTypeSmsTemplate : has_sms_templates + + MessageTypeTemplate }o--|| MessageType : belongs_to + MessageTypeTemplate }o--|| WechatTemplate : uses + + MessageTypeSmsTemplate }o--|| MessageType : belongs_to + MessageTypeSmsTemplate }o--|| SmsTemplate : uses +``` + +### 2.2 Session(会话) + +**实体说明**:用户与特定实体(应用、其他用户等)之间的会话记录。 + +#### 字段定义 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `entity` | `String<32>` | 关联对象类型(如 'application', 'user' 等) | +| `entityId` | `String<64>` | 关联对象ID | +| `user` | `User` | 发送者(当前会话的用户) | +| `lmts` | `Datetime` | 最后一条消息的发送时间 | +| `openId` | `String<32>` | 微信用户openId(用于微信场景) | + +#### 关系定义 + +- `partner`:会话的所有者关系 + +#### 使用说明 + +1. **Web场景**:用户与应用之间建立会话 +2. **微信场景**:通过openId标识微信用户的会话 +3. **自动更新**:当会话中有新消息时,`lmts`字段会自动更新 + +### 2.3 SessionMessage(会话消息) + +**实体说明**:会话中的具体消息内容,支持多种消息类型。 + +#### 字段定义 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `application` | `Application` | 所属应用 | +| `session` | `Session` | 所属会话 | +| `user` | `User` | 发送用户(可选,用于用户发送的消息) | +| `wechatUser` | `WechatUser` | 微信用户(可选,用于微信客服消息) | +| `createTime` | `Datetime` | 发送时间 | +| `type` | `Type` | 消息类型 | +| `text` | `Text` | 文本内容 | +| `files` | `ExtraFile[]` | 附件文件(图片、视频、音频等) | +| `link` | `String<128>` | 链接地址 | +| `aaoe` | `Boolean` | as agent of entity - 是否作为实体的代理发送 | +| `extra` | `Object` | 额外信息(如微信原始数据) | + +#### 消息类型(Type) + +| 值 | 说明 | +|----|------| +| `text` | 文字消息 | +| `image` | 图片消息 | +| `voice` | 音频消息 | +| `video` | 视频消息 | +| `location` | 位置消息 | +| `link` | 图文链接 | +| `event` | 事件消息 | +| `miniprogrampage` | 小程序卡片 | + +#### 关键字段说明 + +- **aaoe(as agent of entity)**: + - `true`:表示这条消息是代表实体(如客服)发送的 + - `false`:表示这是用户发送的消息 + - 用于判断是否需要推送微信客服消息 + +### 2.4 Message(系统消息) + +**实体说明**:系统级消息通知,支持多渠道推送。 + +#### 字段定义 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `entity` | `String<32>` | 关联对象类型 | +| `entityId` | `String<64>` | 关联对象ID | +| `user` | `User` | 接收用户 | +| `type` | `String<64>` | 消息类型(自定义业务类型) | +| `weight` | `Weight` | 消息优先级 | +| `restriction` | `MessageRestriction` | 推送限制条件 | +| `title` | `String<256>` | 消息标题 | +| `content` | `Text` | 消息内容 | +| `data` | `Object` | 透传数据 | +| `router` | `Router` | 目标路由 | +| `platform` | `Platform` | 目标平台 | +| `channels` | `Channels` | 推送渠道列表 | + +#### Action 和 State + +**IAction(发送动作)**: +- `succeed`:发送成功 +- `fail`:发送失败 + +**IState(发送状态)**: +- `sending`:发送中 +- `success`:发送成功 +- `failure`:发送失败 + +**VisitAction(阅读动作)**: +- `visit`:标记为已读 + +**VisitState(阅读状态)**: +- `unvisited`:未读 +- `visited`:已读 + +#### 状态转换图 + +```mermaid +stateDiagram-v2 + [*] --> sending: 创建消息 + sending --> success: succeed + sending --> failure: fail + + state "阅读状态" as visit { + [*] --> unvisited: 初始状态 + unvisited --> visited: visit + } +``` + +#### 消息优先级(Weight) + +| 值 | 说明 | 默认推送渠道 | +|----|------|-------------| +| `high` | 高优先级 | 微信小程序、公众号、短信、邮件 | +| `medium` | 中优先级 | 微信小程序、公众号、邮件 | +| `low` | 低优先级 | 微信小程序、公众号、邮件 | + +#### 推送渠道(Channel) + +| 值 | 说明 | +|----|------| +| `wechatMp` | 微信小程序 | +| `wechatPublic` | 微信公众号 | +| `sms` | 短信 | +| `email` | 邮箱 | +| `jPush` | 极光推送 | +| `jim` | 极光消息 | + +#### Router(路由配置) + +```typescript +type Router = { + pathname: string; // 路由路径 + props?: Record; // 路由参数 + state?: Record; // 路由状态 + isTabBar?: boolean; // 是否为TabBar页面(小程序专用) +}; +``` + +#### MessageRestriction(推送限制) + +```typescript +type MessageRestriction = { + systemIds?: string[]; // 允许推送的系统ID列表 + channels?: Array; // 允许推送的渠道列表 +}; +``` + +### 2.5 MessageType(消息类型) + +**实体说明**:定义业务消息类型,用于关联不同的推送模板。 + +#### 字段定义 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `type` | `String<64>` | 消息类型标识(如 'order_paid', 'event_reminder' 等) | + +### 2.6 MessageSystem(消息系统连接) + +**实体说明**:将消息分发到不同的系统。 + +#### 字段定义 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `message` | `Message` | 关联的消息 | +| `system` | `System` | 目标系统 | + +### 2.7 Notification(通知) + +**实体说明**:具体的渠道推送记录,每个渠道对应一条Notification。 + +#### 字段定义 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `channel` | `Channel` | 推送渠道 | +| `application` | `Application` | 关联应用(可选) | +| `data` | `Object` | 推送数据(渠道特定格式) | +| `messageSystem` | `MessageSystem` | 所属消息系统连接 | +| `data1` | `Object` | 扩展数据1 | +| `data2` | `Object` | 扩展数据2 | +| `templateId` | `String<128>` | 模板ID | + +#### Action 和 State + +**Action**: +- `succeed`:推送成功 +- `fail`:推送失败 + +**State**: +- `sending`:推送中 +- `success`:推送成功 +- `failure`:推送失败 + +### 2.8 MessageTypeTemplate(消息类型与微信模板关联) + +**实体说明**:将业务消息类型与微信公众号模板消息关联。 + +#### 字段定义 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `type` | `String<64>` | 消息类型 | +| `template` | `WechatTemplate` | 微信模板 | + +### 2.9 MessageTypeSmsTemplate(消息类型与短信模板关联) + +**实体说明**:将业务消息类型与短信模板关联。 + +#### 字段定义 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `type` | `String<64>` | 消息类型 | +| `template` | `SmsTemplate` | 短信模板 | + +--- + +## 3. 业务逻辑说明 + +参考自: +- `oak-general-business/src/aspects/session.ts` +- `oak-general-business/src/aspects/sessionMessage.ts` +- `oak-general-business/src/triggers/session.ts` +- `oak-general-business/src/triggers/sessionMessage.ts` +- `oak-general-business/src/triggers/message.ts` + +### 3.1 会话创建流程 + +```mermaid +sequenceDiagram + participant Client as 客户端 + participant Aspect as SessionAspect + participant Trigger as SessionTrigger + participant DB as 数据库 + participant Event as 事件系统 + + Client->>Aspect: createSession(params) + Aspect->>DB: 查询是否存在会话 + alt 会话已存在 + DB-->>Aspect: 返回已有会话 + alt 有新消息(微信场景) + Aspect->>DB: 更新会话(添加新消息) + end + else 会话不存在 + Aspect->>Trigger: beforeCreate触发 + Trigger->>Event: 保存事件订阅key + Trigger-->>Aspect: 继续创建 + Aspect->>DB: 创建新会话 + alt 有初始消息 + Aspect->>DB: 同时创建SessionMessage + end + end + Aspect-->>Client: 返回sessionId +``` + +#### 创建会话的场景 + +**1. Web场景**: +- 用户与应用建立会话 +- 默认使用当前系统的Web应用 +- 支持指定entity和entityId + +**2. 微信公众号/小程序场景**: +- 通过微信回调数据创建会话 +- 使用openId标识微信用户 +- 自动解析消息类型(文本、图片、视频、语音等) +- 自动创建ExtraFile记录(对于媒体消息) + +### 3.2 会话消息发送流程 + +```mermaid +flowchart TD + A[创建SessionMessage] --> B{触发beforeCreate} + B --> C[保存事件订阅key] + C --> D[写入数据库] + D --> E{触发afterCreate} + E --> F[更新Session的lmts] + F --> G{触发commit} + G --> H{检查aaoe标记} + H -->|aaoe=true| I[查询用户最后一条消息] + H -->|aaoe=false| Z[结束] + I --> J{48小时内有用户消息?} + J -->|是| K[获取应用配置] + J -->|否| Z + K --> L{消息类型} + L -->|text| M[调用微信客服消息API发送文本] + L -->|image| N[调用微信客服消息API发送图片] + L -->|其他| O[暂不支持] + M --> Z + N --> Z + O --> Z +``` + +#### 关键业务规则 + +1. **事件订阅**: + - 每次创建SessionMessage时触发数据订阅事件 + - 订阅key格式:`sessionMessageList-{sessionId}` + - 用于前端实时刷新消息列表 + +2. **自动更新会话时间**: + - 每次创建新消息后,自动更新Session的`lmts`字段 + - 用于会话列表排序 + +3. **微信客服消息推送**: + - 仅当`aaoe=true`时(代表实体发送)才推送 + - 需要48小时内有用户消息(微信限制) + - 目前支持文本和图片两种类型 + +### 3.3 系统消息推送流程 + +```mermaid +flowchart TD + A[创建Message] --> B{触发beforeCreate} + B --> C[获取用户关联的System] + C --> D{根据restriction过滤System} + D --> E[根据weight和channels确定推送渠道] + E --> F{遍历System和Channel} + + F --> G1{微信小程序?} + G1 -->|是| H1[查询用户WechatUser] + H1 --> I1[查找MessageTypeTemplate] + I1 --> J1{有openId且有模板?} + J1 -->|是| K1[调用转换器生成数据] + K1 --> L1[创建Notification] + + F --> G2{微信公众号?} + G2 -->|是| H2[查询用户WechatUser] + H2 --> I2[查找MessageTypeTemplate] + I2 --> J2{有openId且有模板?} + J2 -->|是| K2[调用转换器生成数据] + K2 --> L2[创建Notification] + + F --> G3{短信?} + G3 -->|是| H3[查询用户Mobile] + H3 --> J3{有手机号且有转换器?} + J3 -->|是| K3[调用转换器生成数据] + K3 --> L3[创建Notification] + + F --> G4{邮件?} + G4 -->|是| H4[调用转换器生成数据] + H4 --> L4[创建Notification] + + L1 --> M[创建MessageSystem] + L2 --> M + L3 --> M + L4 --> M + + M --> N[设置Message状态] + N --> O{有通知?} + O -->|是| P[iState=sending] + O -->|否| Q[iState=failure] + + P --> R[写入数据库] + Q --> R +``` + +#### 推送渠道选择逻辑 + +1. **优先级判断**: + - `high`:微信小程序、公众号、短信、邮件 + - `medium`:微信小程序、公众号、邮件 + - `low`:微信小程序、公众号、邮件 + +2. **限制条件过滤**: + - `restriction.systemIds`:仅推送到指定系统 + - `restriction.channels`:仅使用指定渠道 + - `channels`字段:直接指定推送渠道(优先级最高) + +3. **用户条件判断**: + - 微信渠道:需要用户有对应应用的openId + - 短信渠道:需要用户绑定手机号 + - 邮件渠道:需要配置邮件转换器 + +### 3.4 消息转换器机制 + +消息转换器负责将业务消息转换为各个渠道所需的数据格式。 + +#### 转换器接口 + +```typescript +interface MessageNotificationConverter { + type: string; // 消息类型 + toWechatMp?: (message, apps, app, context) => Promise; + toWechatPublic?: (message, apps, app, context) => Promise; + toSms?: (message, context) => Promise; + toEmail?: (message, context) => Promise; +} +``` + +#### 注册转换器 + +```typescript +import { registerMessageNotificationConverters } from 'oak-general-business'; + +registerMessageNotificationConverters([ + { + type: 'order_paid', + toWechatMp: async (message, apps, app, context) => { + return { + // 微信小程序模板消息数据 + }; + }, + toSms: async (message, context) => { + return { + // 短信模板数据 + }; + }, + }, +]); +``` + +### 3.5 Aspect 说明 + +#### SessionAspect + +- **createSession**:创建或获取会话 + - 支持Web、微信公众号、微信小程序场景 + - 自动处理微信回调数据 + - 自动创建初始消息 + +#### SessionMessageAspect + +目前通过组件和直接操作实现,无独立Aspect。 + +### 3.6 Trigger 说明 + +#### Session Triggers + +1. **beforeCreate**: + - 保存会话列表的事件订阅key + - 格式:`sessionList-u-{userId}` + +#### SessionMessage Triggers + +1. **beforeCreate**: + - 保存消息列表的事件订阅key + - 格式:`sessionMessageList-{sessionId}` + +2. **afterCreate**: + - 更新Session的`lmts`字段 + +3. **commit**: + - 检查是否需要推送微信客服消息 + - 根据aaoe标记判断 + - 48小时限制检查 + - 调用微信SDK发送消息 + +#### Message Triggers + +1. **beforeCreate**: + - 创建MessageSystem记录 + - 创建Notification记录 + - 根据用户系统配置和消息限制条件生成推送任务 + - 设置Message的iState状态 + +### 3.7 核心配置常量 + +```typescript +// 事件订阅key +DATA_SUBSCRIBER_KEYS = { + sessionList: 'sessionList', + sessionMessageList: 'sessionMessageList', +} + +// 默认推送渠道矩阵 +InitialChannelByWeightMatrix = { + high: ['wechatMp', 'wechatPublic', 'sms', 'email'], + medium: ['wechatMp', 'wechatPublic', 'email'], + low: ['wechatMp', 'wechatPublic', 'email'], +} +``` + +--- + +## 4. 前端组件使用 + +参考自: +- `oak-general-business/src/components/session/` +- `oak-general-business/src/components/sessionMessage/` +- `oak-general-business/src/components/message/` + +### 4.1 Session 相关组件 + +#### 4.1.1 SessionList(会话列表) + +**导入路径**: +```typescript +import SessionList from 'oak-general-business/es/components/session/list'; +``` + +**组件说明**:显示用户的会话列表,支持实时更新。 + +**Props 接口**: +```typescript +interface SessionListProps { + sessionId?: string; // 默认选中的会话ID + entityFilter?: any; // 实体过滤条件 + entityFilterSubStr?: string; // 实体过滤订阅字符串 + entityDisplay?: (sessions) => any[]; // 自定义显示实体名称 + entityProjection?: any; // 自定义实体投影 +} +``` + +**关键特性**: +- 自动订阅会话列表变化事件 +- 按最后消息时间倒序排列 +- 显示每个会话的最后一条消息 +- 显示用户头像和昵称 +- 支持自定义实体显示方式 + +#### 4.1.2 SessionCell(会话单元格) + +**导入路径**: +```typescript +import SessionCell from 'oak-general-business/es/components/session/cell'; +``` + +**组件说明**:会话列表的单个item显示组件。 + +#### 4.1.3 SessionHeader(会话头部) + +**导入路径**: +```typescript +import SessionHeader from 'oak-general-business/es/components/session/header'; +``` + +**组件说明**:会话详情页的头部组件,显示会话信息。 + +#### 4.1.4 SessionMessageNumber(消息数量) + +**导入路径**: +```typescript +import SessionMessageNumber from 'oak-general-business/es/components/session/messageNumber'; +``` + +**组件说明**:显示会话的未读消息数量。 + +### 4.2 SessionMessage 相关组件 + +#### 4.2.1 SessionMessageList(会话消息列表) + +**导入路径**: +```typescript +import SessionMessageList from 'oak-general-business/es/components/sessionMessage/list'; +``` + +**组件说明**:显示某个会话中的所有消息,支持实时更新和消息发送。 + +**Props 接口**: +```typescript +interface SessionMessageListProps { + sessionId: string; // 会话ID(必需) + isEntity?: boolean; // 是否为实体视角 + dialog?: boolean; // 是否为对话框模式 + entity?: string; // 实体类型 + entityId?: string; // 实体ID + entityDisplay?: (data) => any[]; // 自定义实体显示 + entityProjection?: any; // 自定义实体投影 +} +``` + +**关键特性**: +- 自动订阅会话消息变化事件 +- 支持文本、图片、视频、语音等多种消息类型 +- 消息按时间正序排列 +- 自动滚动到最新消息 +- 支持发送消息(isEntity=true时) +- 实时显示新消息 + +#### 4.2.2 SessionMessageCell(消息单元格) + +**导入路径**: +```typescript +import SessionMessageCell from 'oak-general-business/es/components/sessionMessage/cell'; +``` + +**组件说明**:消息列表的单个消息显示组件。 + +#### 4.2.3 SessionMessageUpsert(消息输入) + +**导入路径**: +```typescript +import SessionMessageUpsert from 'oak-general-business/es/components/sessionMessage/upsert'; +``` + +**组件说明**:发送消息的输入框组件。 + +### 4.3 Message 相关组件 + +#### 4.3.1 MessageList(系统消息列表) + +**导入路径**: +```typescript +import MessageList from 'oak-general-business/es/components/message/list'; +``` + +**组件说明**:显示用户的系统消息列表。 + +**Props 接口**: +```typescript +interface MessageListProps { + // 无特殊props,自动获取当前用户的消息 +} +``` + +**关键特性**: +- 自动获取当前登录用户的消息 +- 支持消息已读标记(visit action) +- 按创建时间倒序排列 +- 点击消息可跳转到详情页 + +#### 4.3.2 MessageDetail(消息详情) + +**导入路径**: +```typescript +import MessageDetail from 'oak-general-business/es/components/message/detail'; +``` + +**组件说明**:显示单条消息的详细内容。 + +#### 4.3.3 MessageCell(消息单元格) + +**导入路径**: +```typescript +import MessageCell from 'oak-general-business/es/components/message/cell'; +``` + +**组件说明**:消息列表的单个item显示组件。 + +#### 4.3.4 MessageSimpleList(简单消息列表) + +**导入路径**: +```typescript +import MessageSimpleList from 'oak-general-business/es/components/message/simpleList'; +``` + +**组件说明**:简化版的消息列表组件。 + +--- + +## 5. 接入指南 + +### 5.1 前置要求 + +接入会话与消息功能前,需要确保以下模块已配置: + +1. **用户系统**:需要用户注册登录功能 +2. **应用管理**:至少配置一个Application +3. **系统配置**:配置System和Platform +4. **微信集成**(可选):如需微信客服消息,需要配置微信应用 + +### 5.2 数据库表 + +功能会自动创建以下数据表,无需手动创建: + +- `session` - 会话表 +- `sessionMessage` - 会话消息表 +- `message` - 系统消息表 +- `messageType` - 消息类型表 +- `messageSystem` - 消息系统连接表 +- `messageTypeTemplate` - 微信模板关联表 +- `messageTypeSmsTemplate` - 短信模板关联表 +- `notification` - 通知表 + +### 5.3 必需页面和路由 + +#### Web 应用 + +```typescript +// 路由配置 +const routes = [ + { + path: '/session', + component: SessionPage, // 会话列表页 + }, + { + path: '/session/:sessionId', + component: SessionDetailPage, // 会话详情页 + }, + { + path: '/message', + component: MessageListPage, // 消息列表页 + }, + { + path: '/message/detail', + component: MessageDetailPage, // 消息详情页 + }, +]; +``` + +#### 微信小程序 + +```json +{ + "pages": [ + "pages/session/index", + "pages/session/detail", + "pages/message/index", + "pages/message/detail" + ] +} +``` + +### 5.4 功能初始化 + +#### 5.4.1 基础会话功能 + +**步骤1:创建会话** + +```typescript +import { createSession } from 'oak-general-business/es/aspects/session'; + +// Web 场景:用户与应用建立会话 +const sessionId = await context.callAspect('session', 'createSession', { + type: 'web', + entity: 'application', + entityId: 'your-app-id', +}); + +// 微信场景:通过回调数据创建 +const sessionId = await context.callAspect('session', 'createSession', { + type: 'wechatPublic', // 或 'wechatMp' + data: wechatEventData, // 微信回调数据 + entity: 'application', + entityId: 'your-wechat-app-id', +}); +``` + +**步骤2:发送消息** + +```typescript +// 用户发送消息 +await context.operate('sessionMessage', { + id: generateNewId(), + action: 'create', + data: { + id: generateNewId(), + sessionId: sessionId, + applicationId: 'your-app-id', + userId: currentUserId, + type: 'text', + text: '你好,我想咨询一下', + aaoe: false, // 用户发送 + createTime: Date.now(), + }, +}); + +// 客服回复消息 +await context.operate('sessionMessage', { + id: generateNewId(), + action: 'create', + data: { + id: generateNewId(), + sessionId: sessionId, + applicationId: 'your-app-id', + userId: adminUserId, + type: 'text', + text: '您好,有什么可以帮您?', + aaoe: true, // 代表实体发送,会触发微信推送 + createTime: Date.now(), + }, +}); +``` + +#### 5.4.2 系统消息推送 + +**步骤1:创建消息类型** + +```typescript +// 创建消息类型 +await context.operate('messageType', { + id: generateNewId(), + action: 'create', + data: { + id: generateNewId(), + type: 'order_paid', // 自定义类型 + }, +}); +``` + +**步骤2:配置消息模板(可选)** + +```typescript +// 关联微信模板 +await context.operate('messageTypeTemplate', { + id: generateNewId(), + action: 'create', + data: { + id: generateNewId(), + type: 'order_paid', + templateId: 'wechat-template-id', + }, +}); + +// 关联短信模板 +await context.operate('messageTypeSmsTemplate', { + id: generateNewId(), + action: 'create', + data: { + id: generateNewId(), + type: 'order_paid', + templateId: 'sms-template-id', + }, +}); +``` + +**步骤3:注册消息转换器** + +```typescript +import { registerMessageNotificationConverters } from 'oak-general-business/es/triggers/message'; + +registerMessageNotificationConverters([ + { + type: 'order_paid', + + // 转换为微信小程序模板消息 + toWechatMp: async (message, apps, app, context) => { + const { data } = message; + return { + keyword1: { value: data.orderNo }, + keyword2: { value: data.amount }, + keyword3: { value: data.payTime }, + }; + }, + + // 转换为微信公众号模板消息 + toWechatPublic: async (message, apps, app, context) => { + const { data } = message; + // 查找跳转的小程序 + const mpApp = apps.find(a => a.type === 'wechatMp'); + return { + data: { + first: { value: '您的订单已支付成功' }, + keyword1: { value: data.orderNo }, + keyword2: { value: data.amount }, + remark: { value: '感谢您的购买' }, + }, + wechatMpAppId: mpApp?.config?.appId, // 跳转小程序 + }; + }, + + // 转换为短信 + toSms: async (message, context) => { + const { user, data } = message; + return { + params: { + orderNo: data.orderNo, + amount: data.amount, + }, + }; + }, + + // 转换为邮件 + toEmail: async (message, context) => { + const { data } = message; + return { + subject: '订单支付成功通知', + content: `您的订单${data.orderNo}已支付${data.amount}元`, + }; + }, + }, +]); +``` + +**步骤4:发送消息** + +```typescript +await context.operate('message', { + id: generateNewId(), + action: 'create', + data: { + id: generateNewId(), + userId: targetUserId, + type: 'order_paid', + weight: 'high', // 高优先级 + title: '订单支付成功', + content: '您的订单已支付成功,我们将尽快为您发货', + data: { + orderNo: 'ORDER123456', + amount: '99.00', + payTime: '2025-01-15 10:30:00', + }, + router: { + pathname: '/order/detail', + props: { orderId: 'order-id-123' }, + }, + // 可选:指定推送渠道 + channels: ['wechatMp', 'sms'], + // 可选:限制推送条件 + restriction: { + systemIds: ['system-id-1'], + channels: ['wechatMp', 'wechatPublic'], + }, + }, +}); +``` + +### 5.5 微信客服消息配置 + +如需使用微信客服消息功能,需要: + +1. **配置微信应用**: + - 在Application中配置微信公众号或小程序 + - 填写appId和appSecret + +2. **配置服务器URL**: + - 设置微信回调服务器地址 + - 配置Token和EncodingAESKey + +3. **启用客服消息**: + - 在微信平台开通客服消息功能 + +4. **处理微信回调**: +```typescript +// 接收微信消息回调 +app.post('/wechat/callback/:appId', async (req, res) => { + const { appId } = req.params; + const wechatData = req.body; + + // 创建会话并处理消息 + const sessionId = await context.callAspect('session', 'createSession', { + type: 'wechatPublic', // 或 'wechatMp' + data: wechatData, + entity: 'application', + entityId: appId, + }); + + res.send('success'); +}); +``` + +### 5.6 实时订阅配置 + +会话和消息功能依赖实时事件订阅,需要配置WebSocket或SSE: + +```typescript +// 前端订阅示例 +const unsubscribe = await oakContext.subscribe([ + 'sessionList-u-{userId}', // 会话列表变化 + 'sessionMessageList-{sessionId}', // 会话消息变化 +], (event) => { + // 刷新数据 + this.refresh(); +}); + +// 组件销毁时取消订阅 +onUnmounted(() => { + unsubscribe(); +}); +``` + +### 5.7 常见配置示例 + +#### 示例1:简单的客服系统 + +```typescript +// 1. 创建会话 +const sessionId = await createSession({ + type: 'web', + entity: 'application', + entityId: appId, +}); + +// 2. 使用组件显示会话 + +``` + +#### 示例2:订单消息通知 + +```typescript +// 1. 注册转换器 +registerMessageNotificationConverters([ + { + type: 'order_status_change', + toWechatMp: async (message) => ({ + keyword1: { value: message.data.orderNo }, + keyword2: { value: message.data.status }, + }), + }, +]); + +// 2. 发送消息 +await context.operate('message', { + action: 'create', + data: { + userId: order.userId, + type: 'order_status_change', + weight: 'medium', + title: '订单状态变更', + content: `您的订单${order.orderNo}状态已变更为${order.status}`, + data: { + orderNo: order.orderNo, + status: order.status, + }, + router: { + pathname: '/order/detail', + props: { orderId: order.id }, + }, + }, +}); +``` + +#### 示例3:多渠道消息推送 + +```typescript +await context.operate('message', { + action: 'create', + data: { + userId: userId, + type: 'urgent_notice', + weight: 'high', // 高优先级 + title: '紧急通知', + content: '系统将于今晚22:00-24:00进行维护', + channels: ['wechatMp', 'wechatPublic', 'sms', 'email'], // 所有渠道 + }, +}); +``` + +--- + +## 6. API 接口说明 + +参考自: +- `oak-general-business/src/aspects/session.ts` +- `oak-general-business/src/aspects/sessionMessage.ts` + +### 6.1 Aspect 方法(前端调用) + +#### 6.1.1 SessionAspect.createSession + +**方法说明**:创建或获取会话 + +**调用方式**: +```typescript +const sessionId = await context.callAspect('session', 'createSession', params); +``` + +**参数(params)**: +```typescript +interface CreateSessionParams { + type: 'web' | 'wechatMp' | 'wechatPublic'; // 应用类型 + entity?: string; // 实体类型(如 'application') + entityId?: string; // 实体ID + data?: WechatPublicEventData | WechatMpEventData; // 微信回调数据(微信场景) +} +``` + +**返回值**: +```typescript +string // sessionId +``` + +**场景1:Web创建会话** +```typescript +const sessionId = await context.callAspect('session', 'createSession', { + type: 'web', + entity: 'application', + entityId: 'app-id-123', +}); +``` + +**场景2:微信公众号创建会话** +```typescript +const sessionId = await context.callAspect('session', 'createSession', { + type: 'wechatPublic', + data: { + ToUserName: 'gh_xxxx', + FromUserName: 'oXXXX', + CreateTime: 1234567890, + MsgType: 'text', + Content: '你好', + MsgId: '123456', + }, + entity: 'application', + entityId: 'wechat-app-id', +}); +``` + +**场景3:微信小程序创建会话** +```typescript +const sessionId = await context.callAspect('session', 'createSession', { + type: 'wechatMp', + data: wechatMpEventData, + entity: 'application', + entityId: 'mp-app-id', +}); +``` + +### 6.2 直接操作实体(CRUD) + +#### 6.2.1 创建会话消息 + +```typescript +await context.operate('sessionMessage', { + id: generateNewId(), + action: 'create', + data: { + id: generateNewId(), + sessionId: 'session-id', + applicationId: 'app-id', + userId: 'user-id', // 可选,用户发送时填写 + wechatUserId: 'wechat-user-id', // 可选,微信回调时填写 + type: 'text', // 'text' | 'image' | 'voice' | 'video' | 'link' | 'miniprogrampage' + text: '消息内容', + aaoe: false, // false=用户发送, true=实体发送(会触发微信推送) + createTime: Date.now(), + }, +}); +``` + +#### 6.2.2 创建系统消息 + +```typescript +await context.operate('message', { + id: generateNewId(), + action: 'create', + data: { + id: generateNewId(), + userId: 'target-user-id', + type: 'custom_message_type', + weight: 'high', // 'high' | 'medium' | 'low' + title: '消息标题', + content: '消息内容', + data: { // 透传数据 + key1: 'value1', + key2: 'value2', + }, + router: { // 跳转路由 + pathname: '/target/page', + props: { id: '123' }, + isTabBar: false, + }, + platformId: 'platform-id', // 可选,指定平台 + channels: ['wechatMp', 'sms'], // 可选,指定渠道 + restriction: { // 可选,推送限制 + systemIds: ['system-1', 'system-2'], + channels: ['wechatMp', 'wechatPublic'], + }, + }, +}); +``` + +#### 6.2.3 标记消息为已读 + +```typescript +await context.operate('message', { + id: generateNewId(), + action: 'visit', + filter: { + id: 'message-id', + }, +}); +``` + +#### 6.2.4 查询会话列表 + +```typescript +const sessions = await context.select('session', { + data: { + id: 1, + entity: 1, + entityId: 1, + lmts: 1, + user: { + id: 1, + name: 1, + nickname: 1, + }, + sessionMessage$session: { + $entity: 'sessionMessage', + data: { + id: 1, + text: 1, + type: 1, + createTime: 1, + }, + sorter: [{ + $attr: { createTime: 1 }, + $direction: 'desc', + }], + count: 1, + }, + }, + filter: { + userId: 'current-user-id', + }, + sorter: [{ + $attr: { lmts: 1 }, + $direction: 'desc', + }], +}); +``` + +#### 6.2.5 查询会话消息列表 + +```typescript +const messages = await context.select('sessionMessage', { + data: { + id: 1, + text: 1, + type: 1, + userId: 1, + createTime: 1, + aaoe: 1, + extraFile$entity: { + $entity: 'extraFile', + data: { + id: 1, + filename: 1, + objectId: 1, + }, + }, + }, + filter: { + sessionId: 'session-id', + }, + sorter: [{ + $attr: { createTime: 1 }, + $direction: 'asc', + }], +}); +``` + +#### 6.2.6 查询系统消息列表 + +```typescript +const messages = await context.select('message', { + data: { + id: 1, + type: 1, + title: 1, + content: 1, + visitState: 1, + iState: 1, + $$createAt$$: 1, + router: 1, + data: 1, + }, + filter: { + userId: 'current-user-id', + visitState: 'unvisited', // 可选,只查询未读 + }, + sorter: [{ + $attr: { $$createAt$$: 1 }, + $direction: 'desc', + }], +}); +``` + +### 6.3 消息转换器注册 + +```typescript +import { registerMessageNotificationConverters } from 'oak-general-business/es/triggers/message'; + +registerMessageNotificationConverters([ + { + type: 'your_message_type', + + // 微信小程序模板消息转换 + toWechatMp: async (message, apps, app, context) => { + return { + keyword1: { value: 'xxx' }, + keyword2: { value: 'xxx' }, + }; + }, + + // 微信公众号模板消息转换 + toWechatPublic: async (message, apps, app, context) => { + return { + data: { + first: { value: 'xxx' }, + keyword1: { value: 'xxx' }, + remark: { value: 'xxx' }, + }, + wechatMpAppId: 'mp-app-id', // 可选,跳转小程序 + }; + }, + + // 短信转换 + toSms: async (message, context) => { + return { + params: { + param1: 'xxx', + param2: 'xxx', + }, + }; + }, + + // 邮件转换 + toEmail: async (message, context) => { + return { + subject: 'xxx', + content: 'xxx', + }; + }, + }, +]); +``` + +--- + +## 7. 附录 + +### 7.1 相关文档 + +- [用户系统功能文档](./用户系统功能文档.md) +- [应用管理功能文档](./应用管理功能文档.md) +- [微信生态功能文档](./微信生态功能文档.md) +- [令牌管理功能文档](./令牌管理功能文档.md) + +### 7.2 更新日志 + +**2025-01-15** +- 初始版本文档编写完成 +- 包含Session、SessionMessage、Message等核心实体说明 +- 包含完整的接入指南和API文档 + +### 8.3 常见问题 + +**Q1: 微信客服消息48小时限制如何处理?** + +A: 目前需要确保在48小时内有用户消息,系统会自动检测。超时后建议使用模板消息替代。 + +**Q2: 如何自定义消息推送渠道?** + +A: 通过注册MessageNotificationConverter实现不同渠道的数据转换。 + +**Q3: 消息已读状态如何追踪?** + +A: Message实体支持visitState和visit action,可以标记消息为已读。 + +**Q4: 如何实现群聊功能?** + +A: 目前不支持群聊,仅支持一对一会话。群聊功能在规划中。 + +**Q5: 消息推送失败如何处理?** + +A: 查看Notification实体的iState状态,failure状态需要手动处理或等待重试机制实现。 + +--- + +*文档版本:v1.0* +*最后更新:2025年1月15日* +*维护者:oak-general-business 团队*