1. searchExpert新增ConDoctor专家字段:
- 新增ConDoctorMapper直接查询qh_con_doctor表(同库,避免跨模块依赖)
- EmergencyProfessionUser新增17个@TableField(exist=false)字段承载专家数据
- searchExpert方法中批量查询ConDoctor并逐字段填充
- 用户非专家时ConDoctor字段为null
- 更新API文档-移动端接口.md
2. IM签名缓存优化:
- TencentCloudImUtil新增secretKey注入
- Redis key从 silence:im_user_sig:{sdkAppId}:{id}
改为 silence:im_user_sig:{hash(sdkAppId+secretKey)}:{id}
- 解决secretKey变更时旧缓存签名仍被命中导致IM请求失败的问题
Co-Authored-By: Claude <noreply@anthropic.com>
423 lines
15 KiB
Markdown
423 lines
15 KiB
Markdown
# 急救模块移动端 API 文档
|
||
|
||
## 🆕 本次变更(前端联调)
|
||
|
||
| # | 接口 | 变更类型 | 说明 |
|
||
|---|------|:---:|------------------------------------------------------------------------------|
|
||
| 1 | `GET /createGroupMagFirstAider` | **废除** | 已废除,功能由 `createGroupMag` 承接 |
|
||
| 2 | `GET /order/myParticipatedOrders` | **新增** | App端查询当前登录人参与的应急工单列表(sessionNow=1),返回被救助人信息 |
|
||
|
||
|
||
---
|
||
|
||
> **基础信息**
|
||
> 网关地址: `http://{gateway-host}:{port}`(前端加 `/health-emergency` 前缀)
|
||
> 服务直连: `http://{host}:7011`(调试用,不加前缀)
|
||
> 认证方式: 请求头 `X-Access-Token: {token}`
|
||
> Content-Type: `application/json; charset=utf-8`
|
||
> 统一响应格式: `{"success": bool, "message": "...", "code": 200, "result": {...}, "timestamp": ...}`
|
||
> 日期格式: `yyyy-MM-dd HH:mm:ss`(东八区)
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [应急群聊拉人](#1-应急群聊拉人-apiemergency)
|
||
2. [宣教资源](#2-宣教资源-apiemergencyfirstaidresource)
|
||
3. [工单列表](#3-工单列表-apiemergencyorder)
|
||
|
||
---
|
||
|
||
## 1. 应急群聊拉人 `api/emergency`
|
||
|
||
> 网关完整路径: `/health-emergency/api/emergency`
|
||
|
||
### 1.1 搜索专家(专业人员) `GET /order/searchExpert`
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| realname | String | 否 | 姓名,模糊搜索 |
|
||
| centerId | String | 否 | 应急中心ID |
|
||
| excludeSessionId | String | 否 | 群组ID,用于排除已在群中的人 |
|
||
| pageNo | Integer | 否 | 页码,默认1 |
|
||
| pageSize | Integer | 否 | 每页条数,默认10 |
|
||
|
||
```json
|
||
// 响应 result
|
||
{
|
||
"records": [
|
||
{
|
||
"userId": "xxx", "realname": "张医生", "avatar": "https://...",
|
||
"type": "6", "centerId": "xxx",
|
||
"post": "主任医师", "school": "北京大学", "edu": "博士",
|
||
"goodAt": "心血管内科", "deptName": "急诊科", "phone": "13800000001",
|
||
"doctorName": "张医生", "doctorNo": "XJ-001", "photo": "https://...",
|
||
"resourceName": "新疆人民医院", "departmentId": "xxx",
|
||
"departmentName": "急诊科", "doctorTitle": "主任医师",
|
||
"doctorJob": "科长", "doctorStatus": "1", "isAccept": "1",
|
||
"doctorType": "1", "audioStatus": "1", "tfJumpHoliday": "0",
|
||
"experience": "从事心血管内科临床工作20年...",
|
||
"sort": 100, "tfRecommend": "1",
|
||
"introduction": "擅长心血管疾病的诊治..."
|
||
}
|
||
],
|
||
"total": 50, "size": 10, "current": 1
|
||
}
|
||
```
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| userId | 用户ID,邀请时传入 memberList |
|
||
| realname | 姓名 |
|
||
| avatar | 头像 |
|
||
| type | 类型,"6"=专业人员 |
|
||
| centerId | 应急中心ID |
|
||
| post | 职称 |
|
||
| school | 毕业院校 |
|
||
| edu | 学历 |
|
||
| goodAt | 擅长领域 |
|
||
| deptName | 科室 |
|
||
| phone | 手机号 |
|
||
| **↓ 以下字段来源于咨询服务专家表(qh_con_doctor),非专家时为 null** |
|
||
| doctorName | 医生姓名 |
|
||
| doctorNo | 专家编号 |
|
||
| photo | 医生头像 |
|
||
| resourceName | 所属医院名称 |
|
||
| departmentId | 科室ID |
|
||
| departmentName | 科室名称 |
|
||
| doctorTitle | 职务(z_doct_lev 字典) |
|
||
| doctorJob | 职称(z_doct_job 字典) |
|
||
| doctorStatus | 专家状态(doc_status 字典) |
|
||
| isAccept | 是否开启咨询(z_doct_sta 字典: 1开启/3关闭) |
|
||
| doctorType | 专家类型(z_doct_typ 字典: 1收费/2免费/3其他/4义诊) |
|
||
| audioStatus | 是否提供音视频 |
|
||
| tfJumpHoliday | 是否跳过节假日 |
|
||
| experience | 执业经历 |
|
||
| sort | 排序 |
|
||
| tfRecommend | 是否推荐(0否/1是) |
|
||
| introduction | 简介 |
|
||
|
||
### 1.2 搜索员工 `GET /order/searchEmployee`
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| realname | String | 否 | 姓名,模糊搜索 |
|
||
| orgCode | String | 否 | 部门编码 |
|
||
| workNo | String | 否 | 工号 |
|
||
| phone | String | 否 | 手机号 |
|
||
| excludeSessionId | String | 否 | 群组ID,用于排除已在群中的人 |
|
||
| pageNo | Integer | 否 | 页码,默认1 |
|
||
| pageSize | Integer | 否 | 每页条数,默认10 |
|
||
|
||
```json
|
||
// 响应 result
|
||
{
|
||
"records": [
|
||
{
|
||
"userId": "xxx", "realname": "张三", "avatar": "https://...",
|
||
"orgCode": "650000001001", "orgName": "新疆油田公司",
|
||
"deptName": "安全环保部", "phone": "13800000000", "workNo": "A00123"
|
||
}
|
||
],
|
||
"total": 200, "size": 10, "current": 1
|
||
}
|
||
```
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| userId | 用户ID,邀请时传入 memberList |
|
||
| realname | 姓名 |
|
||
| avatar | 头像 |
|
||
| orgCode | 部门编码 |
|
||
| orgName | 单位名称(二级单位) |
|
||
| deptName | 部门名称 |
|
||
| phone | 手机号 |
|
||
| workNo | 工号 |
|
||
|
||
### 1.3 创建群聊 `GET /createGroupMag`
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| name | String | 是 | 群聊名称 |
|
||
| longitude | String | 是 | 经度 |
|
||
| latitude | String | 是 | 纬度 |
|
||
| type | String | 否 | 类型 |
|
||
|
||
> 返回 `groupId`(群组ID),作为后续拉人接口的入参。**此接口会发起音视频通话。**
|
||
|
||
### 1.4 创建群聊-急救员 `GET /createGroupMagFirstAider` ⚠️ 已废除
|
||
|
||
> ⚠️ 本接口已废除,功能由 `createGroupMag` 承接,请勿调用。
|
||
|
||
### 1.5 邀请进群 `POST /addGroupUser`
|
||
|
||
拉专家或员工加入应急群聊。
|
||
|
||
```json
|
||
// Request Body
|
||
{
|
||
"groupId": "1907659384834752513",
|
||
"memberList": ["userId1", "userId2"],
|
||
"memberType": 1
|
||
}
|
||
```
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| groupId | String | 是 | 群组ID(即 `createGroupMag` 返回的 `groupId`) |
|
||
| memberList | List\<String\> | 是 | 要邀请的用户ID列表,最多100个 |
|
||
| memberType | Integer | 否 | `0`=专家/专业人员, `1`=员工,**默认0** |
|
||
|
||
```json
|
||
// 响应
|
||
{"success": true, "message": "", "result": true}
|
||
```
|
||
|
||
> 已在群中的人员会自动跳过,不会报错。所有选中的人都在群中时返回失败。
|
||
|
||
### 1.6 移除群成员 `POST /removeGroupUser`
|
||
|
||
```json
|
||
// Request Body
|
||
{ "groupId": "1907659384834752513", "memberList": ["userId1"] }
|
||
```
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| groupId | String | 是 | 群组ID |
|
||
| memberList | List\<String\> | 是 | 要移除的用户ID列表 |
|
||
|
||
```json
|
||
// 响应
|
||
{"success": true, "message": "", "result": true}
|
||
```
|
||
|
||
> 只能移除后续拉入的协助人员,不能移除发起人和初始操作/专业人员。
|
||
|
||
### 1.7 群成员列表 `GET /order/getGroupMemberList`
|
||
|
||
> ⚠️ 本接口仅查本地 DB,不验证腾讯 IM。**建议改用 1.8 `/order/getActualGroupMemberList`。**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| sessionId | String | 是 | 群组ID |
|
||
|
||
```json
|
||
// 响应 result
|
||
[
|
||
{ "orderId": "...", "userId": "发起人id", "userName": "李四", "avatar": "https://...", "phone": "13800000001", "isGroupMember": 1, "memberType": -1 },
|
||
{ "orderId": "...", "userId": "操作人员id", "userName": "王五", "avatar": "https://...", "phone": "13800000002", "isGroupMember": 1, "memberType": 0 },
|
||
{ "orderId": "...", "userId": "专业人员id", "userName": "张医生", "avatar": "https://...", "phone": "13800000003", "isGroupMember": 1, "memberType": 1 },
|
||
{ "orderId": "...", "userId": "员工id", "userName": "张三", "avatar": "https://...", "phone": "13800000004", "isGroupMember": 1, "memberType": 2 },
|
||
{ "orderId": "...", "userId": "其他专业人id", "userName": "赵医生", "avatar": "https://...", "phone": "13800000005", "isGroupMember": 0, "memberType": 1 }
|
||
]
|
||
```
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| orderId | 应急单ID |
|
||
| userId | 用户ID |
|
||
| userName | 姓名 |
|
||
| avatar | 头像 |
|
||
| phone | 手机号 |
|
||
| isGroupMember | `1`=在群中, `0`=可邀请 |
|
||
| memberType | `-1`=发起人, `0`=操作人员, `1`=专业人员, `2`=员工 |
|
||
|
||
### 1.8 实际群成员列表 `GET /order/getActualGroupMemberList` 🆕
|
||
|
||
> **与 1.7 的区别**:本接口先查本地参与人员,再调用腾讯 IM `get_group_member_info` API 获取群内实际成员,以 IM 成员为准取交集,确保返回的都是 IM 群中真实存在的成员。**不过滤本人,通过 `isSelf` 标识。**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| sessionId | String | 是 | 群组ID |
|
||
|
||
```json
|
||
// 响应 result(与 getGroupMemberList 格式完全一致,但不过滤本人)
|
||
[
|
||
{ "orderId": "...", "userId": "当前用户id", "userName": "我", "avatar": "https://...", "phone": "13800000000", "isGroupMember": 1, "memberType": 0, "isSelf": 1 },
|
||
{ "orderId": "...", "userId": "发起人id", "userName": "李四", "avatar": "https://...", "phone": "13800000001", "isGroupMember": 1, "memberType": -1, "isSelf": 0 },
|
||
{ "orderId": "...", "userId": "专业人员id", "userName": "张医生", "avatar": "https://...", "phone": "13800000003", "isGroupMember": 1, "memberType": 1, "isSelf": 0 }
|
||
]
|
||
```
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| orderId | 应急单ID |
|
||
| userId | 用户ID |
|
||
| userName | 姓名 |
|
||
| avatar | 头像 |
|
||
| phone | 手机号 |
|
||
| isGroupMember | 始终为 `1`(所有返回成员均经 IM 验证在群中) |
|
||
| memberType | `-1`=发起人, `0`=操作人员, `1`=专业人员, `2`=员工 |
|
||
| isSelf | `0`=不是本人, `1`=是本人 |
|
||
|
||
> **建议**:前端优先使用本接口获取群成员列表,1.7 接口后续可淘汰。
|
||
|
||
### 1.9 当前登录人参与的应急工单列表 `GET /order/myParticipatedOrders` 🆕
|
||
|
||
> App端接口:查询当前登录人参与过的、正在应急(`sessionNow=1`)的工单列表,返回被救助人信息。
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| pageNo | Integer | 否 | 页码,默认1 |
|
||
| pageSize | Integer | 否 | 每页条数,默认10 |
|
||
|
||
```json
|
||
// 响应 result
|
||
{
|
||
"records": [
|
||
{
|
||
"orderId": "2074305914885640194",
|
||
"sessionId": "2074305910070706176",
|
||
"salvageUserName": "张三",
|
||
"salvageUserSex": "1",
|
||
"salvageUserAvatar": "https://fileserver.yg.dt.io/xxx.png",
|
||
"salvageUserAge": 35,
|
||
"salvageUserMobile": "13800000000",
|
||
"orgName": "新疆油田公司",
|
||
"deptName": "安全环保部",
|
||
"orderStatus": "1",
|
||
"initTime": "2026-07-20 10:30:00"
|
||
}
|
||
],
|
||
"total": 5, "size": 10, "current": 1
|
||
}
|
||
```
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| orderId | String | 应急单ID |
|
||
| sessionId | String | 会话ID |
|
||
| salvageUserName | String | 被救助人姓名 |
|
||
| salvageUserSex | String | 被救助人性别(字典: sex2) |
|
||
| salvageUserAvatar | String | 被救助人头像 |
|
||
| salvageUserAge | Integer | 被救助人年龄 |
|
||
| salvageUserMobile | String | 被救助人手机号 |
|
||
| orgName | String | 单位名称(二级单位) |
|
||
| deptName | String | 部门名称 |
|
||
| orderStatus | String | 应急单状态(字典: emergency_order_status) |
|
||
| initTime | Date | 发起时间 |
|
||
|
||
### 1.10 memberType 字典
|
||
|
||
| 值 | 含义 | 场景 |
|
||
|:---:|------|------|
|
||
| -1 | 发起人 | 创建应急的人 |
|
||
| 0 | 操作人员 | 应急中心调度员 |
|
||
| 1 | 专业人员 | 专家/医生 |
|
||
| 2 | 员工 | 普通员工(被拉入群) |
|
||
|
||
### 典型调用流程
|
||
|
||
**应急就医(带音视频通话)**:
|
||
```
|
||
1. 创建群聊
|
||
GET /health-emergency/api/emergency/createGroupMag?name=xxx&longitude=xxx&latitude=xxx
|
||
|
||
2. 查看当前成员 → 搜索要拉的人 → 确认邀请 → 移除成员 → 刷新列表
|
||
GET /health-emergency/api/emergency/order/getActualGroupMemberList?sessionId={groupId}
|
||
(以下步骤同急救员流程)
|
||
```
|
||
|
||
**急救员**:
|
||
```
|
||
1. 创建群聊
|
||
GET /health-emergency/api/emergency/createGroupMag?name=xxx&longitude=xxx&latitude=xxx
|
||
|
||
2. 查看当前成员(🔀 替换原 /order/getGroupMemberList)
|
||
GET /health-emergency/api/emergency/order/getActualGroupMemberList?sessionId={groupId}
|
||
→ 返回经腾讯IM验证的实际群成员,新增 isSelf 字段区分本人
|
||
|
||
3. 搜索要拉的人
|
||
GET /health-emergency/api/emergency/order/searchExpert?realname=张&excludeSessionId={groupId}
|
||
GET /health-emergency/api/emergency/order/searchEmployee?realname=李&excludeSessionId={groupId}
|
||
→ 展示搜索结果,用户勾选
|
||
|
||
4. 确认邀请
|
||
POST /health-emergency/api/emergency/addGroupUser
|
||
{"groupId": "{groupId}", "memberList": ["id1","id2"], "memberType": 0}
|
||
|
||
5. 移除成员
|
||
POST /health-emergency/api/emergency/removeGroupUser
|
||
{"groupId": "{groupId}", "memberList": ["id1"]}
|
||
|
||
6. 刷新成员列表(🔀 替换原 /order/getGroupMemberList)
|
||
GET /health-emergency/api/emergency/order/getActualGroupMemberList?sessionId={groupId}
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 宣教资源 `api/emergency/firstAid/resource`
|
||
|
||
> 网关完整路径: `/health-emergency/api/emergency/firstAid/resource`
|
||
|
||
### 2.1 根据宣教ID查询详情 `GET /resource/queryById`
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|:---:|------|
|
||
| id | String | 是 | 宣教资源ID |
|
||
|
||
```json
|
||
// 响应 result
|
||
{
|
||
"id": "...",
|
||
"title": "心肺复苏指南",
|
||
"summary": "摘要简介",
|
||
"contentType": "IMAGE_TEXT",
|
||
"categoryId": "cat1",
|
||
"categoryName": "心肺复苏",
|
||
"applicableScenario": "适用场景",
|
||
"tags": "tag1,tag2",
|
||
"tagNameList": ["成人", "初级"],
|
||
"content": "<h1>富文本HTML正文</h1>",
|
||
"coverImage": "https://example.com/cover.jpg",
|
||
"fileUrl": "[\"https://example.com/file1.pdf\"]",
|
||
"viewCount": 100,
|
||
"favoriteCount": 20,
|
||
"isFavorited": false,
|
||
"effectiveTime": "2026-07-01 00:00:00",
|
||
"expiryTime": "2026-12-31 23:59:59",
|
||
"createTime": "2026-07-01 10:00:00",
|
||
"updateTime": "2026-07-05 14:30:00"
|
||
}
|
||
```
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | String | 资源ID |
|
||
| title | String | 标题 |
|
||
| summary | String | 摘要/简介 |
|
||
| contentType | String | 内容类型:`IMAGE_TEXT`/`VIDEO`/`AUDIO`/`PDF` |
|
||
| categoryId | String | 分类ID |
|
||
| categoryName | String | 分类名称 |
|
||
| applicableScenario | String | 适用场景 |
|
||
| tags | String | 标签ID(逗号分隔) |
|
||
| tagNameList | List\<String\> | 标签名称列表 |
|
||
| content | String | 富文本正文HTML |
|
||
| coverImage | String | 封面图URL |
|
||
| fileUrl | String | 附件URL列表(JSON数组字符串) |
|
||
| viewCount | Integer | 浏览次数 |
|
||
| favoriteCount | Integer | 收藏次数 |
|
||
| isFavorited | Boolean | 当前用户是否已收藏 |
|
||
| effectiveTime | Date | 生效时间 |
|
||
| expiryTime | Date | 失效时间 |
|
||
| createTime | Date | 创建时间 |
|
||
| updateTime | Date | 更新时间 |
|
||
|
||
---
|
||
|
||
## 3. 工单列表 `/api/emergency/order`
|
||
|
||
> 网关完整路径: `/health-emergency/api/emergency/order`
|
||
|
||
### 3.1 当前登录人参与的应急工单列表 `GET /myParticipatedOrders` 🆕
|
||
|
||
**业务逻辑**:
|
||
1. 查 `QH_EME_ORDER_OPERATOR` 表获取当前登录人参与的所有工单ID(去重)
|
||
2. 查 `QH_EME_ORDER` 表筛选 `sessionNow=1` 的工单,按创建时间倒序
|
||
3. 返回被救助人(`salvage` 字段)信息 + 单位/部门名称
|
||
|
||
> **调用时机**:登录用户在急救页面查看自己正在参与中的应急工单。仅返回 IM 会话进行中的工单(`sessionNow=1`)。
|
||
|
||
请求和响应格式见 **[1.9 当前登录人参与的应急工单列表](#19-当前登录人参与的应急工单列表-get-ordermyparticipatedorders-)**。
|