feat: 合并急救员建群逻辑到createGroupMag,新增参与工单列表接口

1. createGroupMag增加addCareUsersToGroup调用,自动拉入关爱联络员+急救员
2. 废除createGroupMagFirstAider(标记@Deprecated)
3. 新增/myparticipatedOrders接口,app端查询当前登录人参与的应急工单列表

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-20 15:51:33 +08:00
co-authored by Claude
parent be701122ca
commit 38a0aa07dd
8 changed files with 202 additions and 24 deletions
+71 -21
View File
@@ -3,14 +3,10 @@
## 🆕 本次变更(前端联调)
| # | 接口 | 变更类型 | 说明 |
|---|------|:---:|------|
| 1 | `GET /createGroupMagFirstAider` | **新增** | 急救员建群:不发起音视频通话,自动拉入关爱联络员+急救员1+急救员2 |
| 2 | `GET /order/searchExpert` | 补充 | 响应新增 `phone` 字段 |
| 3 | `GET /order/searchEmployee` | 修复 | 姓名、手机号、员工编号改为模糊搜索(之前为精确匹配) |
| 4 | `GET /order/getActualGroupMemberList` | **新增** | 新增实际群成员列表接口,替换原 `/order/getGroupMemberList`。调用腾讯 IM 验证实际群成员,新增 `isSelf` 字段区分本人 |
| 5 | `GroupMemberVO` 响应 | 扩展 | 新增 `isSelf` 字段:`0`=不是本人, `1`=是本人 |
|---|------|:---:|------------------------------------------------------------------------------|
| 1 | `GET /createGroupMagFirstAider` | **废除** | 已废除,功能由 `createGroupMag` 承接 |
| 2 | `GET /order/myParticipatedOrders` | **新增** | App端查询当前登录人参与的应急工单列表(sessionNow=1),返回被救助人信息 |
> **memberType 字典**(群成员列表中用):-1=发起人, 0=操作人员, 1=专业人员, 2=员工
---
@@ -28,6 +24,7 @@
1. [应急群聊拉人](#1-应急群聊拉人-apiemergency)
2. [宣教资源](#2-宣教资源-apiemergencyfirstaidresource)
3. [工单列表](#3-工单列表-apiemergencyorder)
---
@@ -122,17 +119,9 @@
> 返回 `groupId`(群组ID),作为后续拉人接口的入参。**此接口会发起音视频通话。**
### 1.4 创建群聊-急救员 `GET /createGroupMagFirstAider` 🆕
### 1.4 创建群聊-急救员 `GET /createGroupMagFirstAider` ⚠️ 已废除
> 不发起音视频通话,建群后自动拉入关爱联络员和急救员(通过安眼系统查询)
| 参数 | 类型 | 必填 | 说明 |
|------|------|:---:|------|
| name | String | 是 | 群聊名称 |
| longitude | String | 是 | 经度 |
| latitude | String | 是 | 纬度 |
> 返回结构与 `createGroupMag` 一致(`CreateGroupMagVO`),群成员 = 发起人 + 操作人员 + 专业人员 + 关爱联络员 + 急救员1 + 急救员2。
> ⚠️ 本接口已废除,功能由 `createGroupMag` 承接,请勿调用
### 1.5 邀请进群 `POST /addGroupUser`
@@ -238,7 +227,52 @@
> **建议**:前端优先使用本接口获取群成员列表,1.7 接口后续可淘汰。
### 1.9 memberType 字典
### 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 字典
| 值 | 含义 | 场景 |
|:---:|------|------|
@@ -259,11 +293,10 @@
(以下步骤同急救员流程)
```
**急救员(不发起通话,自动拉关爱/急救员)**
**急救员**
```
1. 创建群聊
GET /health-emergency/api/emergency/createGroupMagFirstAider?name=xxx&longitude=xxx&latitude=xxx
→ 自动拉入:发起人 + 操作人员 + 专业人员 + 关爱联络员 + 急救员1 + 急救员2
GET /health-emergency/api/emergency/createGroupMag?name=xxx&longitude=xxx&latitude=xxx
2. 查看当前成员(🔀 替换原 /order/getGroupMemberList
GET /health-emergency/api/emergency/order/getActualGroupMemberList?sessionId={groupId}
@@ -344,3 +377,20 @@
| 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-)**。
@@ -0,0 +1,53 @@
package com.renkang.emergency.entity.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* App端:当前登录人参与的应急工单VO
*
* @author PengJ
* @date 2026/7/20
*/
@Data
public class MyParticipatedOrderVO {
@Schema(title = "应急单ID")
private String orderId;
@Schema(title = "会话ID")
private String sessionId;
@Schema(title = "被救助人姓名")
private String salvageUserName;
@Schema(title = "被救助人性别", description = "字典: sex2")
private String salvageUserSex;
@Schema(title = "被救助人头像")
private String salvageUserAvatar;
@Schema(title = "被救助人年龄")
private Integer salvageUserAge;
@Schema(title = "被救助人手机号")
private String salvageUserMobile;
@Schema(title = "单位名称")
private String orgName;
@Schema(title = "部门名称")
private String deptName;
@Schema(title = "应急单状态", description = "字典: emergency_order_status")
private String orderStatus;
@Schema(title = "发起时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date initTime;
}
@@ -104,7 +104,8 @@ public class EmergencyApiController {
return Result.OK(emergencyApiService.createGroupMag(name, longitude, latitude, type));
}
@Operation(summary = "创建群聊-应急就医-急救员(不发起音视频通话,自动拉入关爱联络员和急救员)")
@Deprecated
@Operation(summary = "[已废弃] 创建群聊-应急就医-急救员,请使用 /createGroupMag")
@GetMapping(value = "/createGroupMagFirstAider")
public Result<CreateGroupMagVO> createGroupMagFirstAider(@RequestParam("name") String name,
@RequestParam("longitude") String longitude,
@@ -18,6 +18,7 @@ import com.renkang.emergency.entity.OrderDetail;
import com.renkang.emergency.entity.OrderSendRecord;
import com.renkang.emergency.entity.vo.EmployeeVO;
import com.renkang.emergency.entity.vo.GroupMemberVO;
import com.renkang.emergency.entity.vo.MyParticipatedOrderVO;
import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.api.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
@@ -328,4 +329,12 @@ public class EmergencyOrderApiController {
return Result.OK(emergencyOrderApiService.searchEmployee(realname, orgCode, workNo, phone, excludeSessionId, pageNo, pageSize));
}
@Operation(summary = "查询当前登录人参与的应急工单列表")
@GetMapping("/myParticipatedOrders")
public Result<IPage<MyParticipatedOrderVO>> myParticipatedOrders(
@RequestParam(defaultValue = "1") Integer pageNo,
@RequestParam(defaultValue = "10") Integer pageSize) {
return Result.OK(emergencyOrderApiService.myParticipatedOrders(pageNo, pageSize));
}
}
@@ -34,8 +34,9 @@ public interface EmergencyApiService {
CreateGroupMagVO createGroupMag(String name, String longitude, String latitude, String type);
/**
* 创建群聊-应急就医-急救员(不发起音视频通话,额外拉入关爱联络员和急救员)
* [已废弃] 创建群聊-应急就医-急救员,请使用 {@link #createGroupMag}
*/
@Deprecated
CreateGroupMagVO createGroupMagFirstAider(String name, String longitude, String latitude);
Result<Map<String, Object>> createGroupMagIntervene(String name, String longitude, String latitude, String type);
@@ -16,6 +16,7 @@ import com.renkang.emergency.entity.OrderSendRecord;
import com.renkang.emergency.entity.TblHelpCentorVo;
import com.renkang.emergency.entity.vo.EmployeeVO;
import com.renkang.emergency.entity.vo.GroupMemberVO;
import com.renkang.emergency.entity.vo.MyParticipatedOrderVO;
import java.util.Date;
import java.util.List;
@@ -86,4 +87,9 @@ public interface EmergencyOrderApiService {
IPage<EmployeeVO> searchEmployee(String realname, String orgCode, String workNo, String phone, String excludeSessionId, Integer pageNo, Integer pageSize);
/**
* 查询当前登录人参与的应急工单列表(sessionNow=1
*/
IPage<MyParticipatedOrderVO> myParticipatedOrders(Integer pageNo, Integer pageSize);
}
@@ -890,6 +890,8 @@ public class EmergencyApiServiceImpl implements EmergencyApiService {
String orderId = this.call(emergencyCall);
//保存参与应急的人员信息 PS: 不想大改之前的代码逻辑此处 没有将同一条记录的赋值逻辑合并
saveOderOperationInfo(orderId, sessionId, majorsId, operatorsId, majorsTwoId, rs.getCenterId(), conSessionRequestDO.getAccountList());
// 自动拉入关爱联络员+急救员1+急救员2(不阻断主流程)
addCareUsersToGroup(sysUser.getId(), sessionId, orderId);
imrs.getResult().put("member", userList);
imrs.getResult().put("tfNew", "1");
imrs.getResult().put("id", orderId);
@@ -899,6 +901,7 @@ public class EmergencyApiServiceImpl implements EmergencyApiService {
return createGroupMagVO;
}
@Deprecated
@Transactional(rollbackFor = Exception.class)
@Override
public CreateGroupMagVO createGroupMagFirstAider(String name, String longitude, String latitude) {
@@ -21,6 +21,7 @@ import com.renkang.emergency.constant.EmergencyConstants;
import com.renkang.emergency.entity.*;
import com.renkang.emergency.entity.vo.EmployeeVO;
import com.renkang.emergency.entity.vo.GroupMemberVO;
import com.renkang.emergency.entity.vo.MyParticipatedOrderVO;
import com.renkang.emergency.manager.EmergencyCacheManager;
import com.renkang.emergency.manager.EmergencyCloudManager;
import com.renkang.emergency.mapper.*;
@@ -928,6 +929,60 @@ public class EmergencyOrderApiServiceImpl implements EmergencyOrderApiService {
return targetPage;
}
@Override
public IPage<MyParticipatedOrderVO> myParticipatedOrders(Integer pageNo, Integer pageSize) {
String userId = GlobalUtils.getLoginUser().getId();
// 1. 查当前登录人参与的所有工单ID(去重)
List<String> orderIds = orderOperatorMapper.selectList(
new LambdaQueryWrapper<OrderOperator>()
.select(OrderOperator::getOrderId)
.eq(OrderOperator::getUserId, userId)
).stream().map(OrderOperator::getOrderId).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(orderIds)) {
return new Page<>(pageNo != null ? pageNo : 1, pageSize != null ? pageSize : 10);
}
// 2. 查正在应急的工单
Page<Order> page = new Page<>(pageNo != null ? pageNo : 1, pageSize != null ? pageSize : 10);
LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
wrapper.in(Order::getId, orderIds);
wrapper.eq(Order::getSessionNow, true);
wrapper.eq(Order::getDelFlag, CommonConstant.DEL_FLAG_0);
wrapper.eq(Order::getStatus, 1);
wrapper.orderByDesc(Order::getCreateTime);
IPage<Order> srcPage = orderMapper.selectPage(page, wrapper);
// 3. 映射VO
Page<MyParticipatedOrderVO> targetPage = new Page<>(srcPage.getCurrent(), srcPage.getSize(), srcPage.getTotal());
if (CollectionUtils.isEmpty(srcPage.getRecords())) {
return targetPage;
}
List<MyParticipatedOrderVO> records = srcPage.getRecords().stream().map(order -> {
MyParticipatedOrderVO vo = new MyParticipatedOrderVO();
vo.setOrderId(order.getId());
vo.setSessionId(order.getSessionId());
vo.setSalvageUserName(order.getSalvageUserName());
vo.setSalvageUserSex(order.getSalvageUserSex());
vo.setSalvageUserAvatar(order.getSalvageUserAvatar());
vo.setSalvageUserAge(order.getSalvageUserAge());
vo.setSalvageUserMobile(order.getSalvageUserMobile());
vo.setOrderStatus(order.getOrderStatus());
vo.setInitTime(order.getCreateTime());
// 解析部门(防NPE
if (StrUtil.isNotBlank(order.getSalvageUserDepart())) {
SysDepart secondDepart = emergencyCacheManager.getUserSecondDepart(order.getSalvageUserDepart());
SysDepart depart = emergencyCacheManager.getUserDepart(order.getSalvageUserDepart());
if (secondDepart != null) {
vo.setOrgName(secondDepart.getDepartName());
}
if (depart != null) {
vo.setDeptName(depart.getDepartName());
}
}
return vo;
}).collect(Collectors.toList());
targetPage.setRecords(records);
return targetPage;
}
private List<SessionOrderUser> convertOrder(List<Order> orders) {
if (CollectionUtils.isEmpty(orders)) {
return Collections.emptyList();