在急救转运任务创建时,需要区分存储执行人员的角色类型(司机、医生、护士),以便在同步调度单到旧系统时能准确对应到相应的随行人员参数:
- 司机 → Entourage_1
- 医生 → Entourage_3
- 护士 → Entourage_4
- 第一个执行人员自动成为领队(EntourageLeadID设为1/3/4)
文件: sql/create_sys_task_assignee.sql
CREATE TABLE `sys_task_assignee` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`task_id` bigint(20) NOT NULL COMMENT '任务ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户姓名',
`user_type` varchar(20) NOT NULL COMMENT '用户类型:driver-司机,doctor-医生,nurse-护士',
`is_primary` char(1) DEFAULT '0' COMMENT '是否为主要执行人:0-否,1-是',
`sort_order` int(11) DEFAULT 0 COMMENT '排序顺序(用于确定领队)',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
PRIMARY KEY (`id`),
KEY `idx_task_id` (`task_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务执行人员关联表';
字段说明:
- task_id: 关联的任务ID
- user_id: 执行人员的用户ID
- user_name: 用户姓名(冗余字段,方便查询)
- user_type: 用户角色类型(driver/doctor/nurse),由前端识别并提交
- is_primary: 是否为主要执行人(第一个执行人员)
- sort_order: 排序顺序,用于确定领队(第一个执行人员为领队)
文件: app/pages/task/create-emergency.vue
前端已经实现了根据用户的岗位名称(postName)或角色名称(roleName)自动识别用户类型:
// 根据用户的岗位或角色判断类型
getUserType(user) {
const postName = user.posts && user.posts.length > 0 ? user.posts[0].postName : ''
const roleName = user.roles && user.roles.length > 0 ? user.roles[0].roleName : ''
// 判断是否为司机
if (postName.includes('司机') || roleName.includes('司机')) {
return 'driver'
}
// 判断是否为医生
if (postName.includes('医生') || roleName.includes('医生')) {
return 'doctor'
}
// 判断是否为护士
if (postName.includes('护士') || roleName.includes('护士')) {
return 'nurse'
}
// 其他类型,默认为司机
return 'driver'
}
前端提供了按角色筛选人员的功能:
<view class="staff-filter">
<view class="filter-item" :class="{ active: staffFilterType === 'all' }" @click="filterStaff('all')">全部</view>
<view class="filter-item" :class="{ active: staffFilterType === 'driver' }" @click="filterStaff('driver')">司机</view>
<view class="filter-item" :class="{ active: staffFilterType === 'doctor' }" @click="filterStaff('doctor')">医生</view>
<view class="filter-item" :class="{ active: staffFilterType === 'nurse' }" @click="filterStaff('nurse')">护士</view>
</view>
在buildSubmitData方法中,将执行人员的详细信息(包含角色类型)一起提交:
const submitData = {
taskType: 'EMERGENCY_TRANSFER',
// ...其他字段
assigneeIds: this.selectedStaff.map(staff => staff.userId),
assigneeId: this.selectedStaff.length > 0 ? this.selectedStaff[0].userId : null,
// 执行人员详细信息(包含角色类型)
assignees: this.selectedStaff.map(staff => ({
userId: staff.userId,
userName: staff.nickName,
userType: staff.type // driver/doctor/nurse
}))
}
文件: ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAssignee.java
创建了SysTaskAssignee实体类,对应数据库表:
public class SysTaskAssignee extends BaseEntity {
private Long id;
private Long taskId;
private Long userId;
private String userName;
private String userType; // driver/doctor/nurse
private String isPrimary; // 是否为主要执行人
private Integer sortOrder; // 排序顺序
// ... getters and setters
}
文件: ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskAssigneeMapper.java
提供了CRUD操作接口:
public interface SysTaskAssigneeMapper {
// 查询任务的执行人员列表
public List<SysTaskAssignee> selectSysTaskAssigneeByTaskId(Long taskId);
// 批量新增任务执行人员关联
public int batchInsertSysTaskAssignee(List<SysTaskAssignee> assignees);
// 删除任务的所有执行人员关联
public int deleteSysTaskAssigneeByTaskId(Long taskId);
// ... 其他方法
}
文件: ruoyi-system/src/main/resources/mapper/system/SysTaskAssigneeMapper.xml
实现了批量插入和查询(按排序顺序):
<insert id="batchInsertSysTaskAssignee" parameterType="java.util.List">
insert into sys_task_assignee(task_id, user_id, user_name, user_type, is_primary, sort_order, create_time, create_by, update_time, update_by)
values
<foreach collection="list" item="item" separator=",">
(#{item.taskId}, #{item.userId}, #{item.userName}, #{item.userType}, #{item.isPrimary}, #{item.sortOrder}, #{item.createTime}, #{item.createBy}, #{item.updateTime}, #{item.updateBy})
</foreach>
</insert>
<select id="selectSysTaskAssigneeByTaskId" parameterType="Long" resultMap="SysTaskAssigneeResult">
select id, task_id, user_id, user_name, user_type, is_primary, sort_order, create_time, create_by, update_time, update_by
from sys_task_assignee
where task_id = #{taskId}
order by sort_order asc
</select>
文件: ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
在insertSysTask方法中添加了保存执行人员信息的逻辑:
@Override
@Transactional
public int insertSysTask(TaskCreateVO createVO) {
// ... 保存任务主信息
int result = sysTaskMapper.insertSysTask(task);
// 保存车辆关联信息
// ...
// 保存执行人员信息(包含角色类型)
if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
saveTaskAssignees(task.getTaskId(), createVO.getAssignees());
}
// ... 其他逻辑
}
/**
* 保存任务执行人员信息(包含角色类型)
*/
private void saveTaskAssignees(Long taskId, List<TaskCreateVO.AssigneeInfo> assignees) {
if (assignees == null || assignees.isEmpty()) {
return;
}
List<SysTaskAssignee> taskAssignees = new ArrayList<>();
Date now = DateUtils.getNowDate();
String currentUser = SecurityUtils.getUsername();
for (int i = 0; i < assignees.size(); i++) {
TaskCreateVO.AssigneeInfo assigneeInfo = assignees.get(i);
SysTaskAssignee taskAssignee = new SysTaskAssignee();
taskAssignee.setTaskId(taskId);
taskAssignee.setUserId(assigneeInfo.getUserId());
taskAssignee.setUserName(assigneeInfo.getUserName());
taskAssignee.setUserType(assigneeInfo.getUserType());
// 第一个执行人员为主要执行人
taskAssignee.setIsPrimary(i == 0 ? "1" : "0");
taskAssignee.setSortOrder(i);
taskAssignee.setCreateTime(now);
taskAssignee.setCreateBy(currentUser);
taskAssignee.setUpdateTime(now);
taskAssignee.setUpdateBy(currentUser);
taskAssignees.add(taskAssignee);
}
// 批量保存
if (!taskAssignees.isEmpty()) {
sysTaskAssigneeMapper.batchInsertSysTaskAssignee(taskAssignees);
}
}
文件: ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
修改了getTaskAssignees方法,优先从数据库读取执行人员信息:
/**
* 获取任务的执行人员信息列表(包含角色类型)
*/
private List<TaskCreateVO.AssigneeInfo> getTaskAssignees(Long taskId) {
List<TaskCreateVO.AssigneeInfo> assignees = new ArrayList<>();
try {
// 从数据库查询执行人员信息(按排序顺序)
List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId);
if (taskAssignees != null && !taskAssignees.isEmpty()) {
// 将数据库中的执行人员转换为AssigneeInfo对象
for (SysTaskAssignee taskAssignee : taskAssignees) {
TaskCreateVO.AssigneeInfo assignee = new TaskCreateVO.AssigneeInfo();
assignee.setUserId(taskAssignee.getUserId());
assignee.setUserName(taskAssignee.getUserName());
assignee.setUserType(taskAssignee.getUserType());
assignees.add(assignee);
}
log.info("从数据库获取执行人员信息成功,任务ID: {}, 人员数量: {}", taskId, assignees.size());
return assignees;
}
// 如果数据库中没有执行人员信息,尝试从任务的主要执行人获取
log.warn("数据库中未找到执行人员信息,尝试从任务主要执行人获取,任务ID: {}", taskId);
SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
if (task != null && task.getAssigneeId() != null) {
SysUser user = sysUserMapper.selectUserById(task.getAssigneeId());
if (user != null) {
TaskCreateVO.AssigneeInfo assignee = new TaskCreateVO.AssigneeInfo();
assignee.setUserId(user.getUserId());
assignee.setUserName(user.getNickName());
assignee.setUserType(getUserType(user)); // 通过角色判断类型
assignees.add(assignee);
}
}
} catch (Exception e) {
log.error("获取任务执行人员信息异常,任务ID: {}", taskId, e);
}
return assignees;
}
同步逻辑syncTaskAssignees方法保持不变,直接使用getTaskAssignees返回的角色信息:
private void syncTaskAssignees(SysTask task, Map<String, String> params) {
try {
// 获取任务的执行人员信息列表(包含角色类型)
List<TaskCreateVO.AssigneeInfo> assignees = getTaskAssignees(task.getTaskId());
// ... 其他逻辑
// 遍历执行人员,根据角色类型分配到对应的Entourage参数
for (int i = 0; i < assignees.size(); i++) {
TaskCreateVO.AssigneeInfo assignee = assignees.get(i);
Long userId = assignee.getUserId();
String userType = assignee.getUserType(); // 直接使用前端传递的角色类型
// ... 根据userType分配到Entourage_1/3/4
}
params.put("EntourageLeadID", leadEntourageId);
params.put("Entourage_1", driverOaId); // 司机
params.put("Entourage_3", doctorOaId); // 医生
params.put("Entourage_4", nurseOaId); // 护士
} catch (Exception e) {
log.error("同步任务执行人员异常,任务ID: {}", task.getTaskId(), e);
}
}
前端选择人员
↓
getUserType识别角色(根据岗位名称或角色名称)
↓
添加到selectedStaff(包含type属性:driver/doctor/nurse)
↓
buildSubmitData生成assignees数组
[{userId, userName, userType}, ...]
↓
后端接收TaskCreateVO(包含assignees字段)
↓
insertSysTask保存任务主信息
↓
saveTaskAssignees保存执行人员信息到sys_task_assignee表
↓
同步到旧系统(异步执行)
syncEmergencyTaskToLegacy
↓
buildDispatchOrderParams
↓
syncTaskAssignees获取执行人员信息
↓
getTaskAssignees从数据库查询(按sort_order排序)
↓
返回List<AssigneeInfo>(包含userId, userName, userType)
↓
遍历执行人员,根据userType分配
- driver → Entourage_1
- doctor → Entourage_3
- nurse → Entourage_4
- 第一个人员 → EntourageLeadID设为1/3/4
↓
发送HTTP请求到旧系统
通过判断岗位名称或角色名称中是否包含关键词:
- "司机" → driver
- "医生" → doctor
- "护士" → nurse
- 其他 → 默认为driver
创建独立的关联表sys_task_assignee:
- 优点:支持多个执行人员,每个人员都有明确的角色类型
- 优点:通过sort_order字段确定领队顺序
- 优点:is_primary字段标识主要执行人
- 优点:便于后续扩展(如添加分工、任务分配等)
使用MyBatis的批量插入,一次性保存所有执行人员信息,提高性能。
getTaskAssignees方法具有向后兼容性:
1. 优先从新表sys_task_assignee查询执行人员信息
2. 如果查询不到,则从任务主表的assignee_id字段获取主要执行人
3. 对于旧数据,通过getUserType方法判断角色类型
sql/create_sys_task_assignee.sql - 创建执行人员关联表ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAssignee.java - 执行人员实体类ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskAssigneeMapper.java - 执行人员Mapper接口ruoyi-system/src/main/resources/mapper/system/SysTaskAssigneeMapper.xml - 执行人员Mapper XMLprd/执行人员角色存储功能实现总结.md - 本文档app/pages/task/create-emergency.vue - 已在之前修改,本次无新修改ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java - 已在之前添加AssigneeInfo内部类和assignees字段ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
执行数据库脚本
bash # 在MySQL数据库中执行 mysql -u root -p < sql/create_sys_task_assignee.sql
编译后端代码
bash mvn clean install
重启后端服务
bash java -jar ruoyi-admin.jar
前端代码已在之前部署,无需重新部署
sys_task_assignee表中是否正确保存了执行人员信息user_type是否为driver/doctor/nurseis_primary第一个是否为"1",其他为"0"sort_order是否从0开始递增EntourageLeadID是否正确设置为1/3/4Entourage_1是否为司机的OA_UserIDEntourage_3是否为医生的OA_UserIDEntourage_4是否为护士的OA_UserIDassignee_id字段获取执行人员assignee_id(主要执行人)和sys_task_assignee表(所有执行人员)assignee_id应该等于sys_task_assignee表中is_primary='1'的记录sort_order字段保证顺序的正确性getTaskAssignees方法会自动从任务主表获取执行人员sys_task_assignee表sort_order排序,确保顺序正确执行人员任务分工:在sys_task_assignee表中添加task_role字段,记录执行人员在任务中的具体职责
执行人员状态追踪:添加status字段,记录执行人员的任务状态(已分配、已确认、执行中、已完成等)
执行人员变更记录:添加历史记录表,记录执行人员的变更历史
执行人员绩效统计:基于执行人员关联表,统计每个人员的任务执行情况
智能推荐:基于历史数据,智能推荐合适的执行人员组合