# Data Model: 骑手与用户 IM 即时沟通账号接入
**Phase**: 1 | **Date**: 2026-06-23
## 变更表:info_user(用户信息)
现有用户表,本期**新增两列**存储 IM 平台返回的凭证。
### 新增字段
| 列名 | Java 属性 | 类型 | 可空 | 说明 |
|------|-----------|------|------|------|
| `im_api_key` | `imApiKey` | VARCHAR(64) | 是 | IM 平台 extCreate 返回的 `data.apiKey`(如 `f7a49f9745114462a3333e5698aac9ae`,32 位十六进制)。用户尚未开通 IM 时为 NULL。 |
| `im_user_id` | `imUserId` | BIGINT | 是 | IM 平台 extCreate 返回的 `data.userId`(如 `2069305587785445400`,19 位长整型)。用户尚未开通时为 NULL。 |
### 关系
- 一个 `info_user` 对应 **0 或 1** 组 IM 凭证(imApiKey 与 imUserId 同时为空,或同时有值)。
- 凭证由 IM 平台生成,平台侧不可变;写入后不再更新(幂等返回)。
### 验证规则(来自需求)
- `imApiKey` 非空 ⇔ `imUserId` 非空(成对写入,避免脏数据)。
- 写入前必须 IM 平台 `code == 200` 且 `data` 含非空 apiKey/userId,否则不写库。
- 已有凭证的用户再次调用开通接口:不写库,直接返回现有凭证(幂等)。
### Java 实体改动
`InfoUser.java`(`com.ruoyi.system.domain`)新增:
```java
/** IM 平台 API 密钥(extCreate 返回) */
@Excel(name = "IM apiKey")
private String imApiKey;
/** IM 平台用户ID(extCreate 返回,长整型) */
@Excel(name = "IM userId")
private Long imUserId;
```
> 因实体已用 Lombok `@Data`,无需手写 getter/setter;但该类仍保留大量手写 getter/setter,按现有风格在末尾补 `getImApiKey/setImApiKey`、`getImUserId/setImUserId` 保持一致(可选,@Data 已覆盖)。
### Mapper 改动
`InfoUserMapper.xml` 的 `InfoUserResult` resultMap 新增两行映射:
```xml
```
> `selectInfoUserVo` 为 `select * from info_user`,自动覆盖新列,无需改 SQL。
### SQL 迁移
写入 `updatesql/sql.md`(不直接执行):
```sql
-- 2026-06-23 IM 即时沟通账号接入:info_user 新增 IM 凭证两列
ALTER TABLE info_user ADD COLUMN im_api_key VARCHAR(64) DEFAULT NULL COMMENT 'IM平台API密钥(extCreate返回)';
ALTER TABLE info_user ADD COLUMN im_user_id BIGINT DEFAULT NULL COMMENT 'IM平台用户ID(extCreate返回)';
```
## 新增 VO:ImAccountVo
`com.ruoyi.system.domain.vo.ImAccountVo` —— 开通接口返回体。
| 字段 | 类型 | 说明 |
|------|------|------|
| `apiKey` | String | IM 平台返回的 apiKey |
| `imUserId` | String | IM 平台返回的 userId(**String 规避前端 Long 精度丢失**) |
> service 内部 `InfoUser.imUserId` 为 Long;组装 VO 时 `String.valueOf(imUserId)` 转字符串返回。