wlzboy
2025-11-22 d4fe921568bc29d72644a55fd194adf7f9277cb5
feat: 将旧系统数据同步到新系统
11个文件已添加
19个文件已修改
2067 ■■■■■ 已修改文件
prd/旧系统转运单同步功能更新日志.md 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
prd/旧系统转运单同步功能说明.md 171 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/LegacySystemSyncTask.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/LegacyTransferSyncTask.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ILegacyTransferSyncService.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java 770 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysTaskVehicleMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/test/java/com/ruoyi/system/mapper/SysDeptMapperTest.java 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/test/java/com/ruoyi/system/service/SysDeptServiceTest.java 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/test/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImplTest.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/legacy_transfer_sync_job.sql 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
prd/¾ÉϵͳתÔ˵¥Í¬²½¹¦ÄܸüÐÂÈÕÖ¾.md
New file
@@ -0,0 +1,57 @@
# æ—§ç³»ç»Ÿè½¬è¿å•同步功能更新日志
## v1.1 (2025-11-19)
### æ–°å¢žåŠŸèƒ½
1. å®žçŽ°äº†å®Œæ•´çš„æ—§ç³»ç»Ÿè½¬è¿å•åŒæ­¥åŠŸèƒ½
2. æ”¯æŒå®šæ—¶ä»»åŠ¡è‡ªåŠ¨åŒæ­¥å’Œæ‰‹åŠ¨åŒæ­¥ä¸¤ç§æ–¹å¼
3. æä¾›äº†è¯¦ç»†çš„æ•°æ®æ˜ å°„关系和转换逻辑
4. æ·»åŠ äº†å®Œå–„çš„é”™è¯¯å¤„ç†å’Œæ—¥å¿—è®°å½•æœºåˆ¶
### ä¼˜åŒ–改进
1. ä¼˜åŒ–了syncSingleTransferOrder方法,直接通过ID查询指定转运单,提高查询效率
2. å¢žå¼ºäº†isTransferOrderSynced方法的异常处理,支持非数字ID的处理
3. å®Œå–„了buildCreateTaskVo方法的数据验证和错误处理
4. ä¼˜åŒ–了syncLegacyTransferOrders方法,添加了进度跟踪和中断处理
5. å¢žåŠ äº†æ›´å¤šçš„æ•°æ®éªŒè¯å’Œè¾¹ç•Œæ¡ä»¶æ£€æŸ¥
### ä»£ç è´¨é‡
1. æ·»åŠ äº†å®Œæ•´çš„å•å…ƒæµ‹è¯•è¦†ç›–æ ¸å¿ƒåŠŸèƒ½
2. æä¾›äº†è¯¦ç»†çš„使用文档和数据映射说明
3. å¢žåŠ äº†SQL脚本用于配置定时任务
4. ä¼˜åŒ–了日志记录,提供更详细的调试信息
### æ€§èƒ½ä¼˜åŒ–
1. å‡å°‘了不必要的数据查询,提高同步效率
2. æ·»åŠ äº†çº¿ç¨‹ä¼‘çœ æŽ§åˆ¶ï¼Œé¿å…è¯·æ±‚è¿‡å¿«å¯¼è‡´ç³»ç»ŸåŽ‹åŠ›
3. ä¼˜åŒ–了异常处理流程,避免因单个数据异常影响整体同步
### å®‰å…¨æ€§
1. å¢žåŠ äº†å‚æ•°æœ‰æ•ˆæ€§éªŒè¯ï¼Œé˜²æ­¢ç©ºæŒ‡é’ˆå¼‚å¸¸
2. å®Œå–„了数字类型转换的异常处理
3. æ·»åŠ äº†æ—¥æœŸæ ¼å¼éªŒè¯ï¼Œç¡®ä¿æ•°æ®æ­£ç¡®æ€§
## ä½¿ç”¨è¯´æ˜Ž
### éƒ¨ç½²æ­¥éª¤
1. æ‰§è¡ŒSQL脚本创建定时任务配置
2. ç¡®ä¿SQL Server数据源配置正确
3. å¯åŠ¨åº”ç”¨å¹¶éªŒè¯åŠŸèƒ½
### éªŒè¯æ–¹æ³•
1. è¿è¡Œå•元测试验证核心功能
2. æ‰‹åŠ¨è§¦å‘åŒæ­¥ä»»åŠ¡éªŒè¯æ•°æ®è½¬æ¢
3. æ£€æŸ¥æ—¥å¿—确认同步过程正常
## åŽç»­è®¡åˆ’
### v1.2 è®¡åˆ’功能
1. æ·»åŠ è½¦è¾†ä¿¡æ¯åŒæ­¥åŠŸèƒ½
2. å¢žåŠ æ›´è¯¦ç»†çš„åŒæ­¥çŠ¶æ€è·Ÿè¸ª
3. æä¾›åŒæ­¥æ•°æ®çš„统计报表功能
4. å¢žåŠ æ‰‹åŠ¨é‡è¯•å¤±è´¥ä»»åŠ¡çš„åŠŸèƒ½
### æ€§èƒ½ä¼˜åŒ–方向
1. è€ƒè™‘批量处理提高同步效率
2. ä¼˜åŒ–数据库查询减少响应时间
3. å¢žåŠ ç¼“å­˜æœºåˆ¶å‡å°‘é‡å¤æŸ¥è¯¢
prd/¾ÉϵͳתÔ˵¥Í¬²½¹¦ÄÜ˵Ã÷.md
New file
@@ -0,0 +1,171 @@
# æ—§ç³»ç»Ÿè½¬è¿å•同步功能说明
## ä¸€ã€åŠŸèƒ½æ¦‚è¿°
本功能实现了从旧系统(SQL Server)同步转运单信息到新系统(MySQL)的功能。通过定时任务或手动触发的方式,将旧系统中的转运单数据转换为新系统的任务数据。
## äºŒã€æ ¸å¿ƒç»„ä»¶
### 1. ILegacyTransferSyncService æŽ¥å£
定义了转运单同步的核心方法:
- `syncLegacyTransferOrders(int daysAgo)` - åŒæ­¥æŒ‡å®šå¤©æ•°å‰çš„转运单数据
- `syncSingleTransferOrder(String serviceOrdID, String dispatchOrdID)` - åŒæ­¥å•个转运单
- `isTransferOrderSynced(String serviceOrdID, String dispatchOrdID)` - æ£€æŸ¥è½¬è¿å•是否已同步
- `buildCreateTaskVo(String serviceOrdID, String dispatchOrdID, Map<String, Object> order)` - æž„造任务创建对象
### 2. LegacyTransferSyncServiceImpl å®žçŽ°ç±»
实现了转运单同步的具体逻辑:
- ä»ŽSQL Server查询转运单数据
- è½¬æ¢æ•°æ®æ ¼å¼ä¸ºTaskCreateVO对象
- è°ƒç”¨sysTaskService创建新任务
- è®°å½•同步状态和日志
### 3. LegacyTransferSyncMapper æ•°æ®è®¿é—®å±‚
提供了访问SQL Server数据库的Mapper接口:
- `selectTransferOrders(String startDate)` - æŸ¥è¯¢æŒ‡å®šæ—¥æœŸèŒƒå›´çš„转运单
- `selectTransferOrdersByIDs(String serviceOrdID, String dispatchOrdID)` - æ ¹æ®ID查询转运单
- `selectDiseaseIdsByServiceOrdID(String serviceOrdID)` - æŸ¥è¯¢ç—…情信息
- `selectAssigneesByDispatchOrdID(String dispatchOrdID)` - æŸ¥è¯¢æ‰§è¡Œäººä¿¡æ¯
- `selectCarLicenseByCarID(String carID)` - æŸ¥è¯¢è½¦è¾†è½¦ç‰Œå·
- `selectHospitalNameByHospID(String hospID)` - æŸ¥è¯¢åŒ»é™¢åç§°
- `selectDepartmentNameByDeptID(String deptID)` - æŸ¥è¯¢ç§‘室名称
### 4. LegacyTransferSyncTask å®šæ—¶ä»»åŠ¡
提供了定时执行转运单同步的调度任务:
- `syncTransferOrders7Days()` - åŒæ­¥7天前的转运单数据
- `syncTransferOrders(String daysAgo)` - åŒæ­¥æŒ‡å®šå¤©æ•°å‰çš„转运单数据
## ä¸‰ã€æ•°æ®æ˜ å°„关系
### 1. åŸºæœ¬ä¿¡æ¯æ˜ å°„
| æ—§ç³»ç»Ÿå­—段 | æ–°ç³»ç»Ÿå­—段 | è¯´æ˜Ž |
|------------|------------|------|
| ServiceOrdID | legacy_service_ord_id | æœåŠ¡å•ID |
| DispatchOrdID | legacy_dispatch_ord_id | è°ƒåº¦å•ID |
| ServiceOrdClass | documentTypeId | å•据类型ID |
| ServiceOrdType | taskTypeId | ä»»åŠ¡ç±»åž‹ID |
### 2. æ‚£è€…信息映射
| æ—§ç³»ç»Ÿå­—段 | æ–°ç³»ç»Ÿå­—段 | è¯´æ˜Ž |
|------------|------------|------|
| ServiceOrdPtName | patient.name | æ‚£è€…姓名 |
| ServiceOrdCoPhone | patient.phone | è”系人电话 |
| ServiceOrdPtIDCard | patient.idCard | æ‚£è€…身份证号 |
| ServiceOrdPtCondition | patient.condition | æ‚£è€…病情描述 |
| ServiceOrdCoName | patient.contact | è”系人姓名 |
### 3. åŒ»é™¢ä¿¡æ¯æ˜ å°„
| æ—§ç³»ç»Ÿå­—段 | æ–°ç³»ç»Ÿå­—段 | è¯´æ˜Ž |
|------------|------------|------|
| ServiceOrdPtOutHospID | hospitalOut.id | è½¬å‡ºåŒ»é™¢ID |
| ServiceOrdPtServicesID | hospitalOut.departmentId | è½¬å‡ºåŒ»é™¢ç§‘室ID |
| ServiceOrdPtInHospID | hospitalIn.id | è½¬å…¥åŒ»é™¢ID |
| ServiceOrdPtInServicesID | hospitalIn.departmentId | è½¬å…¥åŒ»é™¢ç§‘室ID |
### 4. åœ°å€ä¿¡æ¯æ˜ å°„
| æ—§ç³»ç»Ÿå­—段 | æ–°ç³»ç»Ÿå­—段 | è¯´æ˜Ž |
|------------|------------|------|
| ServiceOrdTraStreet | departureAddress | å‡ºå‘地址 |
| ServiceOrdTraEnd | destinationAddress | ç›®çš„地址 |
### 5. æ—¶é—´ä¿¡æ¯æ˜ å°„
| æ—§ç³»ç»Ÿå­—段 | æ–°ç³»ç»Ÿå­—段 | è¯´æ˜Ž |
|------------|------------|------|
| DispatchOrdStartDate | plannedStartTime | è®¡åˆ’开始时间 |
| DispatchOrd_NS_Time | createTime | åˆ›å»ºæ—¶é—´ |
### 6. å…¶ä»–信息映射
| æ—§ç³»ç»Ÿå­—段 | æ–°ç³»ç»Ÿå­—段 | è¯´æ˜Ž |
|------------|------------|------|
| ServiceOrdTraTxnPrice | price | æˆäº¤ä»· |
| ServiceOrdCoTies | remark | è”系人关系(备注中) |
## å››ã€æ‰§è¡Œäººä¿¡æ¯æ˜ å°„
执行人角色根据EntourageState字段映射:
- 1,2 â†’ driver(司机)
- 3,5 â†’ doctor(医生)
- 4,6 â†’ nurse(护士)
- å…¶ä»– â†’ other(其他)
## äº”、使用说明
### 1. è‡ªåŠ¨åŒæ­¥
配置定时任务自动执行转运单同步:
1. è¿›å…¥ã€Œç³»ç»Ÿç›‘控」→「定时任务」
2. æ·»åŠ æ–°ä»»åŠ¡ï¼š
   - ä»»åŠ¡åç§°ï¼šæ—§ç³»ç»Ÿè½¬è¿å•åŒæ­¥
   - ä»»åŠ¡ç»„åï¼šDEFAULT
   - è°ƒç”¨ç›®æ ‡ï¼š`legacyTransferSyncTask.syncTransferOrders7Days()`
   - cron表达式:`0 0 2 * * ?`(每天凌晨2点执行)
   - å¹¶å‘控制:禁止并发
   - é”™è¿‡ç­–略:放弃执行
### 2. æ‰‹åŠ¨åŒæ­¥
#### åŒæ­¥æŒ‡å®šå¤©æ•°å‰çš„æ•°æ®
```java
@Autowired
private ILegacyTransferSyncService legacyTransferSyncService;
// åŒæ­¥7天前的转运单数据
int successCount = legacyTransferSyncService.syncLegacyTransferOrders(7);
```
#### åŒæ­¥å•个转运单
```java
// åŒæ­¥æŒ‡å®šçš„æœåŠ¡å•å’Œè°ƒåº¦å•
boolean success = legacyTransferSyncService.syncSingleTransferOrder("12345", "67890");
```
### 3. æŸ¥çœ‹åŒæ­¥ç»“æžœ
```sql
-- æŸ¥è¯¢è½¬è¿å•同步结果
SELECT
    task_id,
    task_code,
    task_description,
    create_time,
    e.legacy_service_ord_id,
    e.legacy_dispatch_ord_id
FROM sys_task t
LEFT JOIN sys_task_emergency e ON t.task_id = e.task_id
WHERE t.task_description LIKE '%从旧系统同步的转运单%'
ORDER BY t.create_time DESC;
-- ç»Ÿè®¡åŒæ­¥æƒ…况
SELECT
    COUNT(*) as total_count,
    SUM(CASE WHEN e.legacy_service_ord_id IS NOT NULL THEN 1 ELSE 0 END) as sync_success_count
FROM sys_task t
LEFT JOIN sys_task_emergency e ON t.task_id = e.task_id
WHERE t.task_description LIKE '%从旧系统同步的转运单%';
```
## å…­ã€ç›‘控和维护
### 1. ç›‘控指标
- åŒæ­¥æˆåŠŸçŽ‡ï¼šæˆåŠŸæ•° / æ€»æ•° * 100%
- åŒæ­¥å¤±è´¥çŽ‡ï¼šå¤±è´¥æ•° / æ€»æ•° * 100%
- å¹³å‡åŒæ­¥è€—时:从创建到同步成功的时间
### 2. æ—¥å¿—查看
```bash
# æŸ¥çœ‹åº”用日志
tail -f logs/sys-info.log | grep "转运单同步"
```
### 3. é”™è¯¯å¤„理
如果同步失败,需要检查:
1. SQL Server连接是否正常
2. æ•°æ®æ ¼å¼æ˜¯å¦æ­£ç¡®
3. æ–°ç³»ç»Ÿå­—段是否匹配
4. å®šæ—¶ä»»åŠ¡æ—¥å¿—ä¸­çš„è¯¦ç»†é”™è¯¯ä¿¡æ¯
## ä¸ƒã€æ³¨æ„äº‹é¡¹
1. å»ºè®®åœ¨ä¸šåŠ¡ä½Žå³°æœŸæ‰§è¡ŒåŒæ­¥ä»»åŠ¡ï¼ˆå¦‚å‡Œæ™¨2点)
2. å¯æ ¹æ®å®žé™…需求调整同步天数(如改为3天或14天)
3. å®šæœŸæ£€æŸ¥åŒæ­¥å¤±è´¥çš„任务并处理
4. å¯é€šè¿‡ä¿®æ”¹å®šæ—¶ä»»åŠ¡çŠ¶æ€ä¸´æ—¶ç¦ç”¨åŒæ­¥ä»»åŠ¡
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
@@ -155,4 +155,18 @@
        deptService.checkDeptDataScope(deptId);
        return toAjax(deptService.deleteDeptById(deptId));
    }
    /**
     * æ ¹æ®service_class查询部门信息
     */
    @GetMapping("/service-class/{serviceClass}")
    public AjaxResult getDeptByServiceClass(@PathVariable String serviceClass)
    {
        SysDept dept = deptService.selectDeptByServiceClass(serviceClass);
        if (dept != null) {
            return success(dept);
        } else {
            return error("未找到对应的部门信息");
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -317,4 +317,18 @@
        
        return success(users);
    }
    /**
     * æ ¹æ®oaUserId查询用户信息
     */
    @GetMapping("/oa-user/{oaUserId}")
    public AjaxResult getUserByOaUserId(@PathVariable Integer oaUserId)
    {
        SysUser user = userService.selectUserByOaUserId(oaUserId);
        if (user != null) {
            return success(user);
        } else {
            return error("未找到对应的用户信息");
        }
    }
}
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/LegacySystemSyncTask.java
@@ -15,6 +15,13 @@
 * 
 * @author ruoyi
 * @date 2024-01-20
 *
 * ç›¸å…³ä»»åŠ¡:
 * 1. LegacySystemSyncTask - æ—§ç³»ç»Ÿä»»åŠ¡åŒæ­¥ï¼ˆæ€¥æ•‘è½¬è¿ä»»åŠ¡å’ŒæœåŠ¡å•ï¼‰
 * 2. LegacyTransferSyncTask - æ—§ç³»ç»Ÿè½¬è¿å•同步(从SQL Server到新系统)
 * 3. TaskStatusSyncService - ä»»åŠ¡çŠ¶æ€åŒæ­¥ï¼ˆä»Žæ—§ç³»ç»Ÿåˆ°æ–°ç³»ç»Ÿï¼‰
 * 4. TaskStatusPushService - ä»»åŠ¡çŠ¶æ€æŽ¨é€ï¼ˆä»Žæ–°ç³»ç»Ÿåˆ°æ—§ç³»ç»Ÿï¼‰
 * 5. TaskAttachmentSyncService - ä»»åŠ¡é™„ä»¶åŒæ­¥ï¼ˆä»Žæ–°ç³»ç»Ÿåˆ°æ—§ç³»ç»Ÿï¼‰
 */
@Component("legacySystemSyncTask")
public class LegacySystemSyncTask {
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/LegacyTransferSyncTask.java
New file
@@ -0,0 +1,51 @@
package com.ruoyi.quartz.task;
import com.ruoyi.system.service.ILegacyTransferSyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * æ—§ç³»ç»Ÿè½¬è¿å•同步定时任务
 *
 * @author ruoyi
 * @date 2025-11-19
 */
@Component("legacyTransferSyncTask")
public class LegacyTransferSyncTask {
    private static final Logger log = LoggerFactory.getLogger(LegacyTransferSyncTask.class);
    @Autowired
    private ILegacyTransferSyncService legacyTransferSyncService;
    /**
     * åŒæ­¥7天前的旧系统转运单数据
     */
    public void syncTransferOrders7Days() {
        log.info("开始执行7天前旧系统转运单同步任务");
        try {
            int count = legacyTransferSyncService.syncLegacyTransferOrders(7);
            log.info("7天前旧系统转运单同步任务执行完成,同步数量: {}", count);
        } catch (Exception e) {
            log.error("7天前旧系统转运单同步任务执行异常", e);
        }
    }
    /**
     * åŒæ­¥æŒ‡å®šå¤©æ•°å‰çš„æ—§ç³»ç»Ÿè½¬è¿å•数据
     *
     * @param daysAgo å¤©æ•°
     */
    public void syncTransferOrders(String daysAgo) {
        log.info("开始执行{}天前旧系统转运单同步任务", daysAgo);
        try {
            int days = Integer.parseInt(daysAgo);
            int count = legacyTransferSyncService.syncLegacyTransferOrders(days);
            log.info("{}天前旧系统转运单同步任务执行完成,同步数量: {}", daysAgo, count);
        } catch (Exception e) {
            log.error("{}天前旧系统转运单同步任务执行异常", daysAgo, e);
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java
@@ -396,6 +396,13 @@
        }
    }
    public void setPlanedStartTime(Date plannedStartTime) {
        this.plannedStartTime = plannedStartTime;
    }
    public Date getPlanedStartTime() {
        return plannedStartTime;
    }
    /**
     * åˆ¤æ–­æ˜¯å¦è¶…æ—¶
     */
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
@@ -1,9 +1,11 @@
package com.ruoyi.system.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
 * ä»»åŠ¡åˆ›å»ºå¯¹è±¡
@@ -11,8 +13,10 @@
 * @author ruoyi
 * @date 2024-01-15
 */
public class TaskCreateVO {
@Data
public class TaskCreateVO implements Serializable {
    private String taskCode;
    /** ä»»åŠ¡ç±»åž‹ */
    private String taskType;
@@ -32,6 +36,13 @@
    /** è®¡åˆ’结束时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date plannedEndTime;
    /** å®žé™…开始时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date actualStartTime;
    /** å®žé™…结束时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date actualEndTime;
    /** æ‰§è¡ŒäººID */
    private Long assigneeId;
@@ -110,6 +121,8 @@
    /** ç—…情ID列表(ICD-10疾病ID列表,用于同步调度单的OrdICD_ID参数) */
    private List<Long> diseaseIds;
    private Date createTime;
    // æ‰§è¡Œäººå‘˜ä¿¡æ¯å†…部类
    public static class AssigneeInfo {
        /** ç”¨æˆ·ID */
ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
New file
@@ -0,0 +1,76 @@
package com.ruoyi.system.mapper;
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.system.domain.OrderClassDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * æ—§ç³»ç»Ÿè½¬è¿å•同步Mapper接口
 *
 * @author ruoyi
 * @date 2025-11-19
 */
@DataSource(DataSourceType.SQLSERVER)
public interface LegacyTransferSyncMapper {
    /**
     * æŸ¥è¯¢æŒ‡å®šæ—¥æœŸèŒƒå›´çš„转运单数据
     *
     * @param startDate å¼€å§‹æ—¥æœŸ
     * @return è½¬è¿å•数据列表
     */
    List<Map<String, Object>> selectTransferOrders(@Param("startDate") String startDate);
    /**
     * æ ¹æ®æœåŠ¡å•ID和调度单ID查询转运单数据
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return è½¬è¿å•数据列表
     */
    List<Map<String, Object>> selectTransferOrdersByIDs(@Param("serviceOrdID") String serviceOrdID, @Param("dispatchOrdID") String dispatchOrdID);
    /**
     * æ ¹æ®æœåŠ¡å•ID查询病情信息
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @return ç—…情ID列表
     */
    List<String> selectDiseaseIdsByServiceOrdID(@Param("serviceOrdID") String serviceOrdID);
    /**
     * æ ¹æ®è°ƒåº¦å•ID查询执行人信息
     *
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return æ‰§è¡Œäººä¿¡æ¯åˆ—表
     */
    List<Map<String, Object>> selectAssigneesByDispatchOrdID(@Param("dispatchOrdID") String dispatchOrdID);
    /**
     * æ ¹æ®è½¦è¾†ID查询车牌号
     *
     * @param carID è½¦è¾†ID
     * @return è½¦ç‰Œå·
     */
    String selectCarLicenseByCarID(@Param("carID") String carID);
    /**
     * æ ¹æ®åŒ»é™¢ID查询医院名称
     *
     * @param hospID åŒ»é™¢ID
     * @return åŒ»é™¢åç§°
     */
    String selectHospitalNameByHospID(@Param("hospID") String hospID);
    /**
     * æ ¹æ®ç§‘室ID查询科室名称
     *
     * @param deptID ç§‘室ID
     * @return ç§‘室名称
     */
    String selectDepartmentNameByDeptID(@Param("deptID") String deptID);
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
@@ -150,4 +150,12 @@
     * @return åˆ†å…¬å¸åˆ—表
     */
    public List<SysDept> selectBranchCompaniesByOrderCodes(@Param("orderCodes") List<String> orderCodes);
    /**
     * æ ¹æ®service_class查询部门信息
     *
     * @param serviceClass æœåŠ¡ç±»åˆ«ç¼–ç 
     * @return éƒ¨é—¨ä¿¡æ¯
     */
    public SysDept selectDeptByServiceClass(@Param("serviceClass") String serviceClass);
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java
@@ -89,4 +89,20 @@
     * @return æ€¥æ•‘转运任务列表
     */
    public List<SysTaskEmergency> selectSyncedTasksForStatusUpdate(@Param("offset") Integer offset, @Param("limit") Integer limit);
    /**
     * æ ¹æ®æ—§ç³»ç»ŸæœåŠ¡å•ID查询急救转运任务扩展信息
     *
     * @param legacyServiceOrdId æ—§ç³»ç»ŸæœåŠ¡å•ID
     * @return æ€¥æ•‘转运任务扩展信息
     */
    public SysTaskEmergency selectByLegacyServiceOrdId(@Param("legacyServiceOrdId") Long legacyServiceOrdId);
    /**
     * æ ¹æ®æ—§ç³»ç»Ÿè°ƒåº¦å•ID查询急救转运任务扩展信息
     *
     * @param legacyDispatchOrdId æ—§ç³»ç»Ÿè°ƒåº¦å•ID
     * @return æ€¥æ•‘转运任务扩展信息
     */
    public SysTaskEmergency selectByLegacyDispatchOrdId(@Param("legacyDispatchOrdId") Long legacyDispatchOrdId);
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
@@ -1,6 +1,8 @@
package com.ruoyi.system.mapper;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.system.domain.VehicleInfo;
import com.ruoyi.system.domain.VehicleDept;
@@ -48,6 +50,22 @@
     * @return è½¦è¾†ä¿¡æ¯
     */
    public VehicleInfo selectVehicleInfoByVehicleNo(String vehicleNo);
    /**
     * æ ¹æ®æ—§ç³»ç»Ÿè½¦è¾†ID(CarID)查询车辆信息
     *
     * @param carId æ—§ç³»ç»Ÿè½¦è¾†ID
     * @return è½¦è¾†ä¿¡æ¯
     */
    public VehicleInfo selectVehicleInfoByCarId(@Param("carId") Integer carId);
    /**
     * æ ¹æ®æ—§ç³»ç»Ÿè½¦è¾†ID查询车辆信息
     *
     * @param carID æ—§ç³»ç»Ÿè½¦è¾†ID
     * @return è½¦è¾†ä¿¡æ¯ï¼ˆvehicle_id, car_id, vehicle_no)
     */
    public Map<String, Object> selectVehicleInfoByCarID(@Param("carID") String carID);
    /**
     * æŸ¥è¯¢è½¦è¾†ä¿¡æ¯åˆ—表
ruoyi-system/src/main/java/com/ruoyi/system/service/ILegacyTransferSyncService.java
New file
@@ -0,0 +1,53 @@
package com.ruoyi.system.service;
import com.ruoyi.system.domain.SysTask;
import com.ruoyi.system.domain.SysTaskEmergency;
import com.ruoyi.system.domain.vo.TaskCreateVO;
import java.util.List;
import java.util.Map;
/**
 * æ—§ç³»ç»Ÿè½¬è¿å•同步Service接口
 *
 * @author ruoyi
 * @date 2025-11-19
 */
public interface ILegacyTransferSyncService {
    /**
     * åŒæ­¥æŒ‡å®šæ—¥æœŸèŒƒå›´çš„æ—§ç³»ç»Ÿè½¬è¿å•到新系统
     *
     * @param daysAgo å¤šå°‘天前的数据(如7表示7天前的数据)
     * @return æˆåŠŸåŒæ­¥çš„è½¬è¿å•æ•°é‡
     */
    int syncLegacyTransferOrders(int daysAgo);
    /**
     * åŒæ­¥å•个旧系统转运单到新系统
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return æ˜¯å¦åŒæ­¥æˆåŠŸ
     */
    boolean syncSingleTransferOrder(String serviceOrdID, String dispatchOrdID);
    /**
     * æ£€æŸ¥è½¬è¿å•是否已同步
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return æ˜¯å¦å·²åŒæ­¥
     */
    boolean isTransferOrderSynced(String serviceOrdID, String dispatchOrdID);
    /**
     * æž„造TaskCreateVO对象用于创建任务
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @param order è½¬è¿å•详细信息
     * @return TaskCreateVO对象
     */
    TaskCreateVO buildCreateTaskVo(String serviceOrdID, String dispatchOrdID, Map<String, Object> order);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
@@ -134,4 +134,12 @@
     * @return åˆ†å…¬å¸åˆ—表
     */
    public List<SysDept> computeBranchCompaniesForUser(SysUser user);
    /**
     * æ ¹æ®service_class查询部门信息
     *
     * @param serviceClass æœåŠ¡ç±»åˆ«ç¼–ç 
     * @return éƒ¨é—¨ä¿¡æ¯
     */
    public SysDept selectDeptByServiceClass(String serviceClass);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
@@ -1,5 +1,6 @@
package com.ruoyi.system.service;
import java.util.Date;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.system.domain.SysTask;
@@ -43,6 +44,18 @@
     * @return ç»“æžœ
     */
    public int insertSysTask(TaskCreateVO createVO);
    /**
     * æ–°å¢žä»»åŠ¡ç®¡ç†ï¼ˆå…è®¸ä»Žå¤–éƒ¨ä¼ å…¥ç”¨æˆ·ä¿¡æ¯ã€éƒ¨é—¨ä¿¡æ¯å’Œæ—¶é—´ä¿¡æ¯ï¼‰
     *
     * @param createVO ä»»åŠ¡åˆ›å»ºå¯¹è±¡
     * @param userId ç”¨æˆ·ID
     * @param deptId éƒ¨é—¨ID
     * @param createTime åˆ›å»ºæ—¶é—´
     * @param updateTime æ›´æ–°æ—¶é—´
     * @return ç»“æžœ
     */
    public int insertTask(TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId, Long userId,String userName, Long deptId, Date createTime, Date updateTime);
    /**
     * ä¿®æ”¹ä»»åŠ¡ç®¡ç†
@@ -214,4 +227,37 @@
     * @return æ­£åœ¨è¿›è¡Œä¸­çš„任务列表
     */
    public List<SysTask> checkVehicleActiveTasks(Long vehicleId);
    /**
     * æ£€æŸ¥ä»»åŠ¡æ˜¯å¦å·²å…³è”æ—§ç³»ç»ŸæœåŠ¡å•ID
     *
     * @param taskId ä»»åŠ¡ID
     * @return true-已关联,false-未关联
     */
    public boolean hasLegacyServiceOrdId(Long taskId);
    /**
     * æ£€æŸ¥ä»»åŠ¡æ˜¯å¦å·²å…³è”æ—§ç³»ç»Ÿè°ƒåº¦å•ID
     *
     * @param taskId ä»»åŠ¡ID
     * @return true-已关联,false-未关联
     */
    public boolean hasLegacyDispatchOrdId(Long taskId);
    /**
     * æ ¹æ®æ—§ç³»ç»ŸæœåŠ¡å•ID检查是否存在任务
     *
     * @param legacyServiceOrdId æ—§ç³»ç»ŸæœåŠ¡å•ID
     * @return true-存在,false-不存在
     */
    public boolean existsByLegacyServiceOrdId(Long legacyServiceOrdId);
    /**
     * æ ¹æ®æ—§ç³»ç»Ÿè°ƒåº¦å•ID检查是否存在任务
     *
     * @param legacyDispatchOrdId æ—§ç³»ç»Ÿè°ƒåº¦å•ID
     * @return true-存在,false-不存在
     */
    public boolean existsByLegacyDispatchOrdId(Long legacyDispatchOrdId);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
@@ -57,6 +57,14 @@
     * @return ç”¨æˆ·å¯¹è±¡ä¿¡æ¯
     */
    public SysUser selectUserByOpenId(String openId);
    /**
     * æ ¹æ®oaUserId查询用户
     *
     * @param oaUserId SQL Server中的OA用户ID
     * @return ç”¨æˆ·ä¿¡æ¯
     */
    public SysUser selectUserByOaUserId(Integer oaUserId);
    /**
     * é€šè¿‡ç”¨æˆ·ID查询用户
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
New file
@@ -0,0 +1,770 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysTask;
import com.ruoyi.system.domain.SysTaskEmergency;
import com.ruoyi.system.domain.VehicleInfo;
import com.ruoyi.system.domain.vo.TaskCreateVO;
import com.ruoyi.system.mapper.SysTaskEmergencyMapper;
import com.ruoyi.system.mapper.SysTaskMapper;
import com.ruoyi.system.service.ILegacyTransferSyncService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysTaskService;
import com.ruoyi.system.mapper.LegacyTransferSyncMapper;
import com.ruoyi.system.mapper.VehicleInfoMapper;
import com.ruoyi.system.service.ISysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
 * æ—§ç³»ç»Ÿè½¬è¿å•同步Service业务层处理
 *
 * @author ruoyi
 * @date 2025-11-19
 */
@Service
public class LegacyTransferSyncServiceImpl implements ILegacyTransferSyncService {
    private static final Logger log = LoggerFactory.getLogger(LegacyTransferSyncServiceImpl.class);
    @Autowired
    private SysTaskMapper sysTaskMapper;
    @Autowired
    private SysTaskEmergencyMapper sysTaskEmergencyMapper;
    @Autowired
    private ISysTaskService sysTaskService;
    @Autowired
    private LegacyTransferSyncMapper legacyTransferSyncMapper;
    @Autowired
    private VehicleInfoMapper vehicleInfoMapper;
    @Autowired
    private ISysDeptService sysDeptService;
    @Autowired
    private ISysUserService sysUserService;
    /**
     * åŒæ­¥æŒ‡å®šæ—¥æœŸèŒƒå›´çš„æ—§ç³»ç»Ÿè½¬è¿å•到新系统
     *
     * @param daysAgo å¤šå°‘天前的数据(如7表示7天前的数据)
     * @return æˆåŠŸåŒæ­¥çš„è½¬è¿å•æ•°é‡
     */
    @Override
    public int syncLegacyTransferOrders(int daysAgo) {
        log.info("开始同步{}天前的旧系统转运单数据", daysAgo);
        try {
            // å‚数验证
            if (daysAgo <= 0) {
                log.error("天数参数必须大于0");
                return 0;
            }
            // è®¡ç®—日期范围
            Date startDate = DateUtils.addDays(new Date(), -daysAgo);
            String startDateStr = DateUtils.parseDateToStr("yyyy-MM-dd", startDate);
            // ä»ŽSQL Server查询转运单数据
            List<Map<String, Object>> transferOrders = legacyTransferSyncMapper.selectTransferOrders(startDateStr);
            if (transferOrders == null || transferOrders.isEmpty()) {
                log.info("未查询到{}天前的转运单数据", daysAgo);
                return 0;
            }
            log.info("查询到{}条转运单数据,开始同步...", transferOrders.size());
            int successCount = 0;
            int totalCount = transferOrders.size();
            int processedCount = 0;
            for (Map<String, Object> order : transferOrders) {
                processedCount++;
                try {
                    String serviceOrdID = getStringValue(order, "ServiceOrdID");
                    String dispatchOrdID = getStringValue(order, "DispatchOrdID");
                    // æ£€æŸ¥å‚数有效性
                    if (StringUtils.isEmpty(serviceOrdID)) {
                        log.warn("第{}条数据服务单ID为空,跳过处理", processedCount);
                        continue;
                    }
                    log.debug("正在处理第{}/{}条转运单: ServiceOrdID={}, DispatchOrdID={}",
                             processedCount, totalCount, serviceOrdID, dispatchOrdID);
                    // æ£€æŸ¥æ˜¯å¦å·²åŒæ­¥
                    if (isTransferOrderSynced(serviceOrdID, dispatchOrdID)) {
                        log.debug("转运单已同步,跳过: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
                        continue;
                    }
                    // åŒæ­¥å•个转运单
                    boolean success = syncSingleTransferOrder(serviceOrdID, dispatchOrdID, order);
                    if (success) {
                        successCount++;
                    }
                    // æŽ§åˆ¶åŒæ­¥é¢‘率,避免请求过快
                    Thread.sleep(100);
                } catch (InterruptedException ie) {
                    log.warn("同步任务被中断");
                    Thread.currentThread().interrupt();
                    break;
                } catch (Exception e) {
                    log.error("同步单个转运单失败: ServiceOrdID={}, DispatchOrdID={}",
                             getStringValue(order, "ServiceOrdID"),
                             getStringValue(order, "DispatchOrdID"), e);
                }
            }
            log.info("同步完成,共处理{}条转运单,成功同步{}条转运单数据", totalCount, successCount);
            return successCount;
        } catch (Exception e) {
            log.error("同步{}天前的旧系统转运单数据异常", daysAgo, e);
            return 0;
        }
    }
    /**
     * åŒæ­¥å•个旧系统转运单到新系统
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return æ˜¯å¦åŒæ­¥æˆåŠŸ
     */
    @Override
    public boolean syncSingleTransferOrder(String serviceOrdID, String dispatchOrdID) {
        log.info("开始同步单个转运单: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
        try {
            // æ£€æŸ¥å‚数有效性
            if (StringUtils.isEmpty(serviceOrdID)) {
                log.error("服务单ID不能为空");
                return false;
            }
            // æ£€æŸ¥æ˜¯å¦å·²åŒæ­¥
            if (isTransferOrderSynced(serviceOrdID, dispatchOrdID)) {
                log.info("转运单已同步,跳过: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
                return true;
            }
            // ç›´æŽ¥æŸ¥è¯¢æŒ‡å®šçš„转运单信息
            List<Map<String, Object>> transferOrders = legacyTransferSyncMapper.selectTransferOrdersByIDs(serviceOrdID, dispatchOrdID);
            if (transferOrders == null || transferOrders.isEmpty()) {
                log.error("未查询到对应的转运单信息: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
                return false;
            }
            Map<String, Object> order = transferOrders.get(0);
            // åŒæ­¥å•个转运单
            return syncSingleTransferOrder(serviceOrdID, dispatchOrdID, order);
        } catch (Exception e) {
            log.error("同步单个转运单异常: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID, e);
            return false;
        }
    }
    /**
     * åŒæ­¥å•个旧系统转运单到新系统(带详细信息)
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @param order è½¬è¿å•详细信息
     * @return æ˜¯å¦åŒæ­¥æˆåŠŸ
     */
    private boolean syncSingleTransferOrder(String serviceOrdID, String dispatchOrdID, Map<String, Object> order) {
        log.info("开始同步单个转运单: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
        try {
            // æž„造TaskCreateVO对象
            TaskCreateVO createTaskVo = buildCreateTaskVo(serviceOrdID, dispatchOrdID, order);
            if (createTaskVo == null) {
                log.error("构造TaskCreateVO失败: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
                return false;
            }
            // è®°å½•创建的任务信息
            log.debug("准备创建任务: ServiceOrdID={}, DispatchOrdID={}, æ‚£è€…姓名={}, è½¬å‡ºåŒ»é™¢={}, è½¬å…¥åŒ»é™¢={}",
                     serviceOrdID, dispatchOrdID,
                     createTaskVo.getPatient() != null ? createTaskVo.getPatient().getName() : "未知",
                     createTaskVo.getHospitalOut() != null ? createTaskVo.getHospitalOut().getName() : "未知",
                     createTaskVo.getHospitalIn() != null ? createTaskVo.getHospitalIn().getName() : "未知");
            Date ServiceOrd_CC_Time= getDateValue(order, "ServiceOrd_CC_Time");
            // è°ƒç”¨sysTaskService创建任务
            String serviceOrdClass = getStringValue(order,"ServiceOrdClass");
            Integer oauserId=getIntegerValue(order,"ServiceOrd_NS_ID");
            SysUser sysUser=sysUserService.selectUserByOaUserId(oauserId);
            Long taskCreatorId=sysUser==null?null:sysUser.getUserId();
            String createUserName=sysUser==null?"system":sysUser.getUserName();
            SysDept dept=sysDeptService.selectDeptByServiceClass(serviceOrdClass);
            Long deptId=dept==null?null:dept.getDeptId();
            int result = sysTaskService.insertTask(createTaskVo,serviceOrdID,dispatchOrdID, taskCreatorId,createUserName, deptId, ServiceOrd_CC_Time, ServiceOrd_CC_Time);
            if (result > 0) {
                log.info("转运单同步成功: ServiceOrdID={}, DispatchOrdID={}, åˆ›å»ºçš„任务ID={}", serviceOrdID, dispatchOrdID, result);
                return true;
            } else {
                log.error("转运单同步失败: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
                return false;
            }
        } catch (Exception e) {
            log.error("同步单个转运单异常: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID, e);
            return false;
        }
    }
    /**
     * æ£€æŸ¥è½¬è¿å•是否已同步
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return æ˜¯å¦å·²åŒæ­¥
     */
    @Override
    public boolean isTransferOrderSynced(String serviceOrdID, String dispatchOrdID) {
        try {
            // æ£€æŸ¥å‚数有效性
            if (StringUtils.isEmpty(serviceOrdID)) {
                log.warn("服务单ID不能为空");
                return false;
            }
            // æ£€æŸ¥sys_task_emergency表中是否已存在对应的记录
            // æ¡ä»¶ï¼šlegacy_service_ord_id = serviceOrdID æˆ– legacy_dispatch_ord_id = dispatchOrdID
            try {
                SysTaskEmergency emergency = sysTaskEmergencyMapper.selectByLegacyServiceOrdId(Long.valueOf(serviceOrdID));
                if (emergency != null) {
                    return true;
                }
            } catch (NumberFormatException e) {
                log.warn("服务单ID不是有效数字: {}", serviceOrdID);
            }
            if (StringUtils.isNotEmpty(dispatchOrdID)) {
                try {
                    SysTaskEmergency emergency = sysTaskEmergencyMapper.selectByLegacyDispatchOrdId(Long.valueOf(dispatchOrdID));
                    if (emergency != null) {
                        return true;
                    }
                } catch (NumberFormatException e) {
                    log.warn("调度单ID不是有效数字: {}", dispatchOrdID);
                }
            }
            return false;
        } catch (Exception e) {
            log.error("检查转运单是否已同步异常: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID, e);
            return false;
        }
    }
    /**
     * æž„造TaskCreateVO对象用于创建任务
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @param order è½¬è¿å•详细信息
     * @return TaskCreateVO对象
     */
    @Override
    public TaskCreateVO buildCreateTaskVo(String serviceOrdID, String dispatchOrdID, Map<String, Object> order) {
        log.info("构造TaskCreateVO: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
        try {
            // æ£€æŸ¥å‚数有效性
            if (order == null || order.isEmpty()) {
                log.error("转运单详细信息不能为空");
                return null;
            }
            if (StringUtils.isEmpty(serviceOrdID)) {
                log.error("服务单ID不能为空");
                return null;
            }
            TaskCreateVO createTaskVo = new TaskCreateVO();
            String Old_ServiceOrdID_TXT=getStringValue(order,"Old_ServiceOrdID_TXT");
            if(Old_ServiceOrdID_TXT!=null){
                createTaskVo.setTaskCode(Old_ServiceOrdID_TXT);
            }
            // è®¾ç½®åŸºæœ¬ä¿¡æ¯
            createTaskVo.setTaskType("EMERGENCY_TRANSFER"); // æ€¥æ•‘转运任务
            // è®¾ç½®å•据类型和任务类型ID(从旧系统字段映射)
            String serviceOrdClass = getStringValue(order, "ServiceOrdClass");
            if (StringUtils.isNotEmpty(serviceOrdClass)) {
                createTaskVo.setDocumentTypeId(serviceOrdClass);
            }
            String serviceOrdType = getStringValue(order, "ServiceOrdType");
            if (StringUtils.isNotEmpty(serviceOrdType)) {
                createTaskVo.setTaskTypeId(serviceOrdType);
            }
            // è®¾ç½®åŒºåŸŸç±»åž‹
            String serviceOrdAreaType = getStringValue(order, "ServiceOrdAreaType");
            if (StringUtils.isNotEmpty(serviceOrdAreaType)) {
                // å¯ä»¥æ ¹æ®éœ€è¦å°†åŒºåŸŸç±»åž‹æ˜ å°„到TaskCreateVO的其他字段
                log.debug("区域类型: {}", serviceOrdAreaType);
            }
            // è®¾ç½®ç”¨æˆ·ID
            Long serviceOrdUserID = getLongValue(order, "ServiceOrdUserID");
            if (serviceOrdUserID != null) {
                // å¯ä»¥æ ¹æ®éœ€è¦å°†ç”¨æˆ·ID映射到TaskCreateVO的其他字段
                log.debug("用户ID: {}", serviceOrdUserID);
            }
            // è®¾ç½®æ‚£è€…信息
            TaskCreateVO.PatientInfo patientInfo = new TaskCreateVO.PatientInfo();
            patientInfo.setName(getStringValue(order, "ServiceOrdPtName"));
            patientInfo.setPhone(getStringValue(order, "ServiceOrdCoPhone"));
            patientInfo.setIdCard(getStringValue(order, "ServiceOrdPtIDCard"));
            patientInfo.setCondition(getStringValue(order, "ServiceOrdPtCondition"));
            patientInfo.setContact(getStringValue(order, "ServiceOrdCoName"));
            String serviceOrdPtSex = getStringValue(order, "ServiceOrdPtSex");
            if(serviceOrdPtSex!=null){
                if(serviceOrdPtSex.equals("男")){
                    patientInfo.setGender("male");
                }else if(serviceOrdPtSex.equals("女")){
                    patientInfo.setGender("female");
                }
            }
            createTaskVo.setPatient(patientInfo);
            //1000公里,提取数字
            String ServiceOrdTraDistance=getStringValue(order, "ServiceOrdTraDistance");
            if(ServiceOrdTraDistance!=null){
                ServiceOrdTraDistance=ServiceOrdTraDistance.replaceAll("[^0-9]", "");
                createTaskVo.setDistance(new BigDecimal(ServiceOrdTraDistance));
            }
            // è®¾ç½®è½¬å‡ºåŒ»é™¢ä¿¡æ¯
            TaskCreateVO.HospitalInfo hospitalOutInfo = new TaskCreateVO.HospitalInfo();
            Long hospitalOutId = getLongValue(order, "ServiceOrdPtOutHospID");
            hospitalOutInfo.setId(hospitalOutId);
            if (hospitalOutId != null) {
                String hospitalOutName = legacyTransferSyncMapper.selectHospitalNameByHospID(hospitalOutId.toString());
                if (StringUtils.isNotEmpty(hospitalOutName)) {
                    hospitalOutInfo.setName(hospitalOutName);
                }
            }
            String ServiceOrdTraVia=getStringValue(order, "ServiceOrdTraVia");
            if(ServiceOrdTraVia!=null){
                hospitalOutInfo.setAddress(ServiceOrdTraVia);
            }
            String hospitalOutDeptId = getStringValue(order, "ServiceOrdPtServicesID");
            //转出床位
            String serviceOrdPtServices=getStringValue(order, "ServiceOrdPtServices");
            hospitalOutInfo.setDepartmentId(hospitalOutDeptId);
            if (StringUtils.isNotEmpty(hospitalOutDeptId)) {
                String hospitalOutDeptName = legacyTransferSyncMapper.selectDepartmentNameByDeptID(hospitalOutDeptId);
                if (StringUtils.isNotEmpty(hospitalOutDeptName)) {
                    hospitalOutInfo.setDepartment(hospitalOutDeptName);
                }
            }
            if(serviceOrdPtServices!= null){
                hospitalOutInfo.setBedNumber(serviceOrdPtServices);
            }
            createTaskVo.setHospitalOut(hospitalOutInfo);
            // è®¾ç½®è½¬å…¥åŒ»é™¢ä¿¡æ¯
            TaskCreateVO.HospitalInfo hospitalInInfo = new TaskCreateVO.HospitalInfo();
            Long hospitalInId = getLongValue(order, "ServiceOrdPtInHospID");
            hospitalInInfo.setId(hospitalInId);
            if (hospitalInId != null) {
                String hospitalInName = legacyTransferSyncMapper.selectHospitalNameByHospID(hospitalInId.toString());
                if (StringUtils.isNotEmpty(hospitalInName)) {
                    hospitalInInfo.setName(hospitalInName);
                }
            }
            String DispatchOrdTraEnd = getStringValue(order, "DispatchOrdTraEnd");
            if(DispatchOrdTraEnd!= null){
                hospitalInInfo.setAddress(DispatchOrdTraEnd);
            }
            //转入床位
            String serviceOrdPtInServices =getStringValue(order, "ServiceOrdPtInServices");
            if(serviceOrdPtInServices!= null){
                hospitalInInfo.setBedNumber(serviceOrdPtInServices);
            }
            String hospitalInDeptId = getStringValue(order, "ServiceOrdPtInServicesID");
            hospitalInInfo.setDepartmentId(hospitalInDeptId);
            if (StringUtils.isNotEmpty(hospitalInDeptId)) {
                String hospitalInDeptName = legacyTransferSyncMapper.selectDepartmentNameByDeptID(hospitalInDeptId);
                if (StringUtils.isNotEmpty(hospitalInDeptName)) {
                    hospitalInInfo.setDepartment(hospitalInDeptName);
                }
            }
            createTaskVo.setHospitalIn(hospitalInInfo);
            // è®¾ç½®åœ°å€ä¿¡æ¯
            createTaskVo.setDepartureAddress(getStringValue(order, "ServiceOrdTraVia"));
            createTaskVo.setDestinationAddress(getStringValue(order, "ServiceOrdTraEnd"));
            // è®¾ç½®ä»·æ ¼å’Œè·ç¦»ä¿¡æ¯
            createTaskVo.setPrice(getBigDecimalValue(order, "ServiceOrdTraTxnPrice"));
            // è·ç¦»ä¿¡æ¯éœ€è¦ä»Žå…¶ä»–字段计算或获取
            // è®¾ç½®æ‰§è¡Œäººä¿¡æ¯
            List<TaskCreateVO.AssigneeInfo> assignees = queryAssignees(dispatchOrdID);
            createTaskVo.setAssignees(assignees);
            // è®¾ç½®è½¦è¾†ä¿¡æ¯
            // è½¦è¾†ID需要根据DispatchOrdCarID查询获取
            String carID = getStringValue(order, "DispatchOrdCarID");
            if (StringUtils.isNotEmpty(carID)) {
                String carLicense = legacyTransferSyncMapper.selectCarLicenseByCarID(carID);
                if (StringUtils.isNotEmpty(carLicense)) {
                    // æ ¹æ®è½¦ç‰Œå·æŸ¥è¯¢æ–°ç³»ç»Ÿä¸­çš„车辆ID
                    log.debug("车辆车牌号: {}", carLicense);
                    // é¦–先尝试通过VehicleInfoMapper查询车辆信息
                    try {
                        // å…ˆå°è¯•通过car_id查询车辆信息
                        Integer carIdInt = Integer.valueOf(carID);
                        VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoByCarId(carIdInt);
                        if (vehicleInfo != null && vehicleInfo.getVehicleId() != null) {
                            // è®¾ç½®è½¦è¾†ID列表
                            List<Long> vehicleIds = new ArrayList<>();
                            vehicleIds.add(vehicleInfo.getVehicleId());
                            createTaskVo.setVehicleIds(vehicleIds);
                            log.debug("通过car_id找到车辆信息: vehicle_id={}, vehicle_no={}", vehicleInfo.getVehicleId(), vehicleInfo.getVehicleNo());
                        } else {
                            // å¦‚果通过car_id找不到,尝试通过车牌号查询
                            vehicleInfo = vehicleInfoMapper.selectVehicleInfoByVehicleNo(carLicense);
                            if (vehicleInfo != null && vehicleInfo.getVehicleId() != null) {
                                List<Long> vehicleIds = new ArrayList<>();
                                vehicleIds.add(vehicleInfo.getVehicleId());
                                createTaskVo.setVehicleIds(vehicleIds);
                                log.debug("通过车牌号找到车辆信息: vehicle_id={}, vehicle_no={}", vehicleInfo.getVehicleId(), vehicleInfo.getVehicleNo());
                            } else {
                                log.warn("未找到对应的车辆信息: car_id={}, vehicle_no={}", carID, carLicense);
                            }
                        }
                    } catch (NumberFormatException e) {
                        log.warn("carID不是有效数字: {}", carID);
                        // å¦‚æžœcarID不是数字,直接通过车牌号查询
                        VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoByVehicleNo(carLicense);
                        if (vehicleInfo != null && vehicleInfo.getVehicleId() != null) {
                            List<Long> vehicleIds = new ArrayList<>();
                            vehicleIds.add(vehicleInfo.getVehicleId());
                            createTaskVo.setVehicleIds(vehicleIds);
                            log.debug("通过车牌号找到车辆信息: vehicle_id={}, vehicle_no={}", vehicleInfo.getVehicleId(), vehicleInfo.getVehicleNo());
                        } else {
                            log.warn("未找到对应的车辆信息: vehicle_no={}", carLicense);
                        }
                    }
                }
            }
            // è®¾ç½®å…¶ä»–信息
            createTaskVo.setTaskDescription("从旧系统同步的转运单");
            // è®¾ç½®å¤‡æ³¨ä¿¡æ¯
            String remark = "服务单ID: " + serviceOrdID + ", è°ƒåº¦å•ID: " + dispatchOrdID;
            String serviceOrdCoTies = getStringValue(order, "ServiceOrdCoTies");
            if (StringUtils.isNotEmpty(serviceOrdCoTies)) {
                remark += ", è”系人关系: " + serviceOrdCoTies;
            }
            createTaskVo.setRemark(remark);
            // è®¾ç½®è®¡åˆ’开始时间
            Date plannedStartTime = getDateValue(order, "ServiceOrdApptDate");
            if (plannedStartTime != null) {
                createTaskVo.setPlannedStartTime(plannedStartTime);
            }
            Date actualStartTime = getDateValue(order, "DispatchOrdActualDate");
            if (actualStartTime != null) {
                createTaskVo.setActualStartTime(actualStartTime);
            }
            Date actualEndTime = getDateValue(order, "DispatchOrdReturnDate");
            if (actualEndTime != null) {
                createTaskVo.setActualEndTime(actualEndTime);
            }
            // è®¾ç½®åˆ›å»ºæ—¶é—´
            Date createTime = getDateValue(order, "ServiceOrd_CC_Time");
            if (createTime != null) {
                createTaskVo.setCreateTime(createTime);
            }
            // æŸ¥è¯¢å¹¶è®¾ç½®ç—…情信息
            String diseaseIdsStr = queryDiseaseIds(serviceOrdID);
            if (StringUtils.isNotEmpty(diseaseIdsStr)) {
                String[] diseaseIdArray = diseaseIdsStr.split(",");
                List<Long> diseaseIds = new ArrayList<>();
                for (String diseaseId : diseaseIdArray) {
                    try {
                        diseaseIds.add(Long.valueOf(diseaseId.trim()));
                    } catch (NumberFormatException e) {
                        log.warn("无效的疾病ID: {}", diseaseId);
                    }
                }
                createTaskVo.setDiseaseIds(diseaseIds);
            }
            log.info("TaskCreateVO构造完成: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
            return createTaskVo;
        } catch (Exception e) {
            log.error("构造TaskCreateVO异常: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID, e);
            return null;
        }
    }
    /**
     * æŸ¥è¯¢æ‰§è¡Œäººä¿¡æ¯
     *
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return æ‰§è¡Œäººä¿¡æ¯åˆ—表
     */
    private List<TaskCreateVO.AssigneeInfo> queryAssignees(String dispatchOrdID) {
        try {
            // æ£€æŸ¥å‚数有效性
            if (StringUtils.isEmpty(dispatchOrdID)) {
                log.warn("调度单ID不能为空");
                return new ArrayList<>();
            }
            // ä»ŽSQL Server查询执行人信息
            List<Map<String, Object>> assigneeList = legacyTransferSyncMapper.selectAssigneesByDispatchOrdID(dispatchOrdID);
            // è½¬æ¢ä¸ºTaskCreateVO.AssigneeInfo对象
            List<TaskCreateVO.AssigneeInfo> assignees = new ArrayList<>();
            if (assigneeList != null && !assigneeList.isEmpty()) {
                for (Map<String, Object> assigneeMap : assigneeList) {
                    String entourageOAId = getStringValue(assigneeMap, "EntourageOAId");
                    String entourageState = getStringValue(assigneeMap, "EntourageState");
                    if (StringUtils.isNotEmpty(entourageOAId)) {
                        try {
                            // å°†OA用户ID转换为系统用户ID
                            Integer oaUserId = Integer.valueOf(entourageOAId);
                            SysUser sysUser = sysUserService.selectUserByOaUserId(oaUserId);
                            if (sysUser != null) {
                                TaskCreateVO.AssigneeInfo assigneeInfo = new TaskCreateVO.AssigneeInfo();
                                assigneeInfo.setUserId(sysUser.getUserId()); // ä½¿ç”¨ç³»ç»Ÿç”¨æˆ·ID
                                assigneeInfo.setUserName(sysUser.getUserName());
                                // æ ¹æ®EntourageState确定角色类型
                                // 1,2 å¸æœºï¼Œ3,5 åŒ»ç”Ÿï¼Œ4,6 æŠ¤å£«
                                if ("1".equals(entourageState) || "2".equals(entourageState)) {
                                    assigneeInfo.setUserType("driver");
                                } else if ("3".equals(entourageState) || "5".equals(entourageState)) {
                                    assigneeInfo.setUserType("doctor");
                                } else if ("4".equals(entourageState) || "6".equals(entourageState)) {
                                    assigneeInfo.setUserType("nurse");
                                } else {
                                    assigneeInfo.setUserType("other");
                                }
                                assignees.add(assigneeInfo);
                            } else {
                                log.warn("未找到对应的系统用户: OA用户ID={}", oaUserId);
                            }
                        } catch (NumberFormatException e) {
                            log.warn("执行人OA ID不是有效数字: {}", entourageOAId);
                        }
                    }
                }
            }
            log.info("查询到{}个执行人,调度单ID: {}", assignees.size(), dispatchOrdID);
            return assignees;
        } catch (Exception e) {
            log.error("查询执行人信息异常,调度单ID: {}", dispatchOrdID, e);
            return new ArrayList<>(); // è¿”回空列表而不是null
        }
    }
    /**
     * æŸ¥è¯¢ç—…情信息
     *
     * @param serviceOrdID æœåŠ¡å•ID
     * @return ç—…情ID列表
     */
    private String queryDiseaseIds(String serviceOrdID) {
        try {
            // æ£€æŸ¥å‚数有效性
            if (StringUtils.isEmpty(serviceOrdID)) {
                log.warn("服务单ID不能为空");
                return null;
            }
            // ä»ŽSQL Server查询病情信息
            List<String> diseaseIds = legacyTransferSyncMapper.selectDiseaseIdsByServiceOrdID(serviceOrdID);
            // è½¬æ¢ä¸ºé€—号分隔的字符串
            if (diseaseIds != null && !diseaseIds.isEmpty()) {
                return String.join(",", diseaseIds);
            }
            log.info("查询到病情信息,服务单ID: {}, ç—…情数量: {}", serviceOrdID, diseaseIds != null ? diseaseIds.size() : 0);
            return null;
        } catch (Exception e) {
            log.error("查询病情信息异常,服务单ID: {}", serviceOrdID, e);
            return null;
        }
    }
    /**
     * ä»ŽMap中获取字符串值
     *
     * @param map Map对象
     * @param key é”®
     * @return å­—符串值
     */
    private String getStringValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        return value != null ? value.toString() : null;
    }
    /**
     * ä»ŽMap中获取BigDecimal值
     *
     * @param map Map对象
     * @param key é”®
     * @return BigDecimal值
     */
    private BigDecimal getBigDecimalValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof BigDecimal) {
            return (BigDecimal) value;
        }
        try {
            return new BigDecimal(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }
    /**
     * ä»ŽMap中获取Long值
     *
     * @param map Map对象
     * @param key é”®
     * @return Long值
     */
    private Long getLongValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof Long) {
            return (Long) value;
        }
        try {
            return Long.valueOf(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }
    private Integer getIntegerValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof Integer) {
            return (Integer) value;
        }
        try {
            return Integer.valueOf(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }
    /**
     * ä»ŽMap中获取Date值
     *
     * @param map Map对象
     * @param key é”®
     * @return Date值
     */
    private Date getDateValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof Date) {
            return (Date) value;
        }
        // å¦‚果是字符串,尝试解析
        if (value instanceof String) {
            try {
                return DateUtils.parseDate(value.toString());
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }
    /**
     * éªŒè¯æ—¥æœŸå­—符串格式是否有效
     *
     * @param dateStr æ—¥æœŸå­—符串
     * @param format æ—¥æœŸæ ¼å¼
     * @return æ˜¯å¦æœ‰æ•ˆ
     */
    private boolean isValidDateFormat(String dateStr, String format) {
        if (StringUtils.isEmpty(dateStr)) {
            return false;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            sdf.setLenient(false);
            sdf.parse(dateStr);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -428,4 +428,16 @@
        
        return result;
    }
    /**
     * æ ¹æ®service_class查询部门信息
     *
     * @param serviceClass æœåŠ¡ç±»åˆ«ç¼–ç 
     * @return éƒ¨é—¨ä¿¡æ¯
     */
    @Override
    public SysDept selectDeptByServiceClass(String serviceClass)
    {
        return deptMapper.selectDeptByServiceClass(serviceClass);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
@@ -142,6 +142,7 @@
    @Override
    @Transactional
    public int insertSysTask(TaskCreateVO createVO) {
        String username = SecurityUtils.getUsername();
        SysTask task = new SysTask();
        task.setTaskCode(generateTaskCode());
        task.setTaskType(createVO.getTaskType());
@@ -153,9 +154,9 @@
        task.setCreatorId(SecurityUtils.getUserId());
        // ä¼˜å…ˆä½¿ç”¨å‰ç«¯ä¼ å…¥çš„部门ID,如果没有则使用当前用户的部门ID
        task.setDeptId(createVO.getDeptId() != null ? createVO.getDeptId() : SecurityUtils.getDeptId());
        task.setCreateBy(SecurityUtils.getUsername());
        task.setCreateBy(username);
        task.setCreateTime(DateUtils.getNowDate());
        task.setUpdateBy(SecurityUtils.getUsername());
        task.setUpdateBy(username);
        task.setUpdateTime(DateUtils.getNowDate());
        task.setRemark(createVO.getRemark());
        task.setDelFlag("0");
@@ -228,17 +229,17 @@
        
        // ä¿å­˜æ‰§è¡Œäººå‘˜ä¿¡æ¯ï¼ˆåŒ…含角色类型)
        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            saveTaskAssignees(task.getTaskId(), createVO.getAssignees());
            saveTaskAssignees(task.getTaskId(), createVO.getAssignees(),username);
        }
        
        // ä¿å­˜æ€¥æ•‘转运扩展信息
        if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) {
            saveEmergencyInfo(task.getTaskId(), createVO);
            saveEmergencyInfo(task.getTaskId(),username, createVO,null,null);
        }
        
        // ä¿å­˜ç¦ç¥‰è½¦æ‰©å±•信息
        if (result > 0 && "WELFARE".equals(createVO.getTaskType())) {
            saveWelfareInfo(task.getTaskId(), createVO);
            saveWelfareInfo(task.getTaskId(),SecurityUtils.getUsername(), createVO);
        }
        
        // è®°å½•操作日志
@@ -291,6 +292,170 @@
                }
            }).start();
        }
        return result;
    }
    /**
     * æ–°å¢žä»»åŠ¡ç®¡ç†ï¼ˆå…è®¸ä»Žå¤–éƒ¨ä¼ å…¥ç”¨æˆ·ä¿¡æ¯ã€éƒ¨é—¨ä¿¡æ¯å’Œæ—¶é—´ä¿¡æ¯ï¼‰
     *
     * @param createVO ä»»åŠ¡åˆ›å»ºå¯¹è±¡
     * @param userId ç”¨æˆ·ID
     * @param deptId éƒ¨é—¨ID
     * @param createTime åˆ›å»ºæ—¶é—´
     * @param updateTime æ›´æ–°æ—¶é—´
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    public int insertTask(TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId, Long userId,String userName, Long deptId, Date createTime, Date updateTime) {
        SysTask task = new SysTask();
        if(createVO.getTaskCode()!=null){
            task.setTaskCode(createVO.getTaskCode());
        }else{
            task.setTaskCode(generateTaskCode());
        }
        task.setTaskType(createVO.getTaskType());
        task.setTaskStatus(TaskStatus.PENDING.getCode());
        task.setTaskDescription(createVO.getTaskDescription());
        task.setPlannedStartTime(createVO.getPlannedStartTime());
        task.setPlannedEndTime(createVO.getPlannedEndTime());
        task.setActualStartTime(createVO.getActualStartTime());
        task.setActualEndTime(createVO.getActualEndTime());
        task.setAssigneeId(createVO.getAssigneeId());
        // ä½¿ç”¨å¤–部传入的用户ID和部门ID
        task.setCreatorId(userId);
        task.setDeptId(deptId);
        task.setCreateBy(userName);
        // ä½¿ç”¨å¤–部传入的创建时间和更新时间
        task.setCreateTime(createTime);
        task.setUpdateTime(updateTime);
        task.setUpdateBy(userName);
        task.setRemark(createVO.getRemark());
        task.setDelFlag("0");
        // è®¾ç½®é€šç”¨åœ°å€å’Œåæ ‡ä¿¡æ¯
        if (createVO.getDepartureAddress() != null) {
            task.setDepartureAddress(createVO.getDepartureAddress());
        }
        if (createVO.getDestinationAddress() != null) {
            task.setDestinationAddress(createVO.getDestinationAddress());
        }
        if (createVO.getDepartureLongitude() != null) {
            task.setDepartureLongitude(createVO.getDepartureLongitude());
        }
        if (createVO.getDepartureLatitude() != null) {
            task.setDepartureLatitude(createVO.getDepartureLatitude());
        }
        if (createVO.getDestinationLongitude() != null) {
            task.setDestinationLongitude(createVO.getDestinationLongitude());
        }
        if (createVO.getDestinationLatitude() != null) {
            task.setDestinationLatitude(createVO.getDestinationLatitude());
        }
        if (createVO.getEstimatedDistance() != null) {
            task.setEstimatedDistance(createVO.getEstimatedDistance());
        }
        // è®¾ç½®æ€¥æ•‘转运特定信息
        if (createVO.getTransferTime() != null) {
            task.setPlannedStartTime(createVO.getTransferTime());
        }
        if (createVO.getTransferDistance() != null) {
            task.setEstimatedDistance(createVO.getTransferDistance());
        }
        // è®¾ç½®ç¦ç¥‰è½¦ç‰¹å®šä¿¡æ¯
        if (createVO.getPlannedStartTime() != null) {
            task.setPlannedStartTime(createVO.getPlannedStartTime());
        }
        if (createVO.getStartAddress() != null) {
            task.setDepartureAddress(createVO.getStartAddress());
        }
        if (createVO.getEndAddress() != null) {
            task.setDestinationAddress(createVO.getEndAddress());
        }
        // è®¾ç½®ç¦ç¥‰è½¦å…¬é‡Œæ•°
        if (createVO.getDistance() != null) {
            task.setEstimatedDistance(createVO.getDistance());
        }
        int result = sysTaskMapper.insertSysTask(task);
        // ä¿å­˜è½¦è¾†å…³è”信息
        if (result > 0 && createVO.getVehicleIds() != null && !createVO.getVehicleIds().isEmpty()) {
            for (Long vehicleId : createVO.getVehicleIds()) {
                SysTaskVehicle taskVehicle = new SysTaskVehicle();
                taskVehicle.setTaskId(task.getTaskId());
                taskVehicle.setVehicleId(vehicleId);
                taskVehicle.setAssignTime(updateTime);
                taskVehicle.setAssignBy(userName);
                taskVehicle.setStatus("ASSIGNED");
                taskVehicle.setCreateBy(userName);
                taskVehicle.setCreateTime(createTime);
                taskVehicle.setUpdateBy(userName);
                taskVehicle.setUpdateTime(updateTime);
                sysTaskVehicleMapper.insertSysTaskVehicle(taskVehicle);
            }
        }
        // ä¿å­˜æ‰§è¡Œäººå‘˜ä¿¡æ¯ï¼ˆåŒ…含角色类型)
        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            saveTaskAssignees(task.getTaskId(), createVO.getAssignees(),userName);
        }
        // ä¿å­˜æ€¥æ•‘转运扩展信息
        if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) {
            saveEmergencyInfo(task.getTaskId(),userName, createVO, serviceOrderId, dispatchOrderId);
        }
        // ä¿å­˜ç¦ç¥‰è½¦æ‰©å±•信息
        if (result > 0 && "WELFARE".equals(createVO.getTaskType())) {
            saveWelfareInfo(task.getTaskId(),userName, createVO);
        }
        // è®°å½•操作日志
        if (result > 0) {
            recordTaskLog(task.getTaskId(), "CREATE", "创建任务", null,
                         "任务类型:" + createVO.getTaskType(), userId, userName);
        }
        // å‘布任务创建事件
        if (result > 0) {
            eventPublisher.publishEvent(new TaskCreatedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                task.getTaskType(),
                userId,
                userName
            ));
        }
        // å‘布任务分配事件
        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            List<Long> assigneeIds = createVO.getAssignees().stream()
                .map(assignee -> assignee.getUserId())
                .collect(Collectors.toList());
            List<String> assigneeNames = createVO.getAssignees().stream()
                .map(assignee -> assignee.getUserName())
                .collect(Collectors.toList());
            eventPublisher.publishEvent(new TaskAssignedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                assigneeIds,
                assigneeNames,
                userId,
                userName
            ));
        }
        
        return result;
    }
@@ -973,6 +1138,70 @@
        return sysTaskMapper.selectActiveTasksByVehicleId(vehicleId);
    }
    /**
     * æ£€æŸ¥ä»»åŠ¡æ˜¯å¦å·²å…³è”æ—§ç³»ç»ŸæœåŠ¡å•ID
     *
     * @param taskId ä»»åŠ¡ID
     * @return true-已关联,false-未关联
     */
    @Override
    public boolean hasLegacyServiceOrdId(Long taskId) {
        // åªæœ‰æ€¥æ•‘转运任务才有旧系统ID
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task != null && "EMERGENCY_TRANSFER".equals(task.getTaskType())) {
            SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
            return emergencyInfo != null && emergencyInfo.getLegacyServiceOrdId() != null;
        }
        return false;
    }
    /**
     * æ£€æŸ¥ä»»åŠ¡æ˜¯å¦å·²å…³è”æ—§ç³»ç»Ÿè°ƒåº¦å•ID
     *
     * @param taskId ä»»åŠ¡ID
     * @return true-已关联,false-未关联
     */
    @Override
    public boolean hasLegacyDispatchOrdId(Long taskId) {
        // åªæœ‰æ€¥æ•‘转运任务才有旧系统ID
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task != null && "EMERGENCY_TRANSFER".equals(task.getTaskType())) {
            SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
            return emergencyInfo != null && emergencyInfo.getLegacyDispatchOrdId() != null;
        }
        return false;
    }
    /**
     * æ ¹æ®æ—§ç³»ç»ŸæœåŠ¡å•ID检查是否存在任务
     *
     * @param legacyServiceOrdId æ—§ç³»ç»ŸæœåŠ¡å•ID
     * @return true-存在,false-不存在
     */
    @Override
    public boolean existsByLegacyServiceOrdId(Long legacyServiceOrdId) {
        if (legacyServiceOrdId == null) {
            return false;
        }
        SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectByLegacyServiceOrdId(legacyServiceOrdId);
        return emergencyInfo != null;
    }
    /**
     * æ ¹æ®æ—§ç³»ç»Ÿè°ƒåº¦å•ID检查是否存在任务
     *
     * @param legacyDispatchOrdId æ—§ç³»ç»Ÿè°ƒåº¦å•ID
     * @return true-存在,false-不存在
     */
    @Override
    public boolean existsByLegacyDispatchOrdId(Long legacyDispatchOrdId) {
        if (legacyDispatchOrdId == null) {
            return false;
        }
        SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectByLegacyDispatchOrdId(legacyDispatchOrdId);
        return emergencyInfo != null;
    }
    @Autowired
    private TaskCodeGenerator taskCodeGenerator;
    
@@ -1105,14 +1334,14 @@
     * @param taskId ä»»åŠ¡ID
     * @param assignees æ‰§è¡Œäººå‘˜ä¿¡æ¯åˆ—表
     */
    private void saveTaskAssignees(Long taskId, java.util.List<TaskCreateVO.AssigneeInfo> assignees) {
    private void saveTaskAssignees(Long taskId, java.util.List<TaskCreateVO.AssigneeInfo> assignees,String userName) {
        if (assignees == null || assignees.isEmpty()) {
            return;
        }
        
        java.util.List<SysTaskAssignee> taskAssignees = new java.util.ArrayList<>();
        Date now = DateUtils.getNowDate();
        String currentUser = SecurityUtils.getUsername();
        String currentUser = userName;
        
        for (int i = 0; i < assignees.size(); i++) {
            TaskCreateVO.AssigneeInfo assigneeInfo = assignees.get(i);
@@ -1145,7 +1374,7 @@
     * @param taskId ä»»åŠ¡ID
     * @param createVO ä»»åŠ¡åˆ›å»ºå¯¹è±¡
     */
    private void saveEmergencyInfo(Long taskId, TaskCreateVO createVO) {
    private void saveEmergencyInfo(Long taskId,String createUserName, TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId) {
        SysTaskEmergency emergencyInfo = new SysTaskEmergency();
        emergencyInfo.setTaskId(taskId);
        
@@ -1200,12 +1429,26 @@
                .collect(Collectors.joining(","));
            emergencyInfo.setDiseaseIds(diseaseIdsStr);
        }
        if(serviceOrderId!=null){
            emergencyInfo.setLegacyServiceOrdId(Long.parseLong(serviceOrderId));
            emergencyInfo.setSyncStatus(2);
            emergencyInfo.setSyncTime(new Date());
            emergencyInfo.setSyncErrorMsg("旧系统同步过来");
        }
        if(dispatchOrderId!=null){
            emergencyInfo.setLegacyDispatchOrdId(Long.parseLong(dispatchOrderId));
            emergencyInfo.setDispatchSyncStatus(2);
            emergencyInfo.setDispatchSyncTime(new Date());
            emergencyInfo.setDispatchSyncErrorMsg("旧系统同步过来");
        // ç³»ç»Ÿå­—段
        }
        // ç³»ç»Ÿå­—段
        emergencyInfo.setCreateTime(DateUtils.getNowDate());
        emergencyInfo.setUpdateTime(DateUtils.getNowDate());
        emergencyInfo.setCreateBy(SecurityUtils.getUsername());
        emergencyInfo.setUpdateBy(SecurityUtils.getUsername());
        emergencyInfo.setCreateBy(createUserName);
        emergencyInfo.setUpdateBy(createUserName);
        
        sysTaskEmergencyMapper.insertSysTaskEmergency(emergencyInfo);
    }
@@ -1216,7 +1459,7 @@
     * @param taskId ä»»åŠ¡ID
     * @param createVO ä»»åŠ¡åˆ›å»ºå¯¹è±¡
     */
    private void saveWelfareInfo(Long taskId, TaskCreateVO createVO) {
    private void saveWelfareInfo(Long taskId,String userName, TaskCreateVO createVO) {
        SysTaskWelfare welfareInfo = new SysTaskWelfare();
        welfareInfo.setTaskId(taskId);
        
@@ -1245,8 +1488,8 @@
        // ç³»ç»Ÿå­—段
        welfareInfo.setCreateTime(DateUtils.getNowDate());
        welfareInfo.setUpdateTime(DateUtils.getNowDate());
        welfareInfo.setCreateBy(SecurityUtils.getUsername());
        welfareInfo.setUpdateBy(SecurityUtils.getUsername());
        welfareInfo.setCreateBy(userName);
        welfareInfo.setUpdateBy(userName);
        
        sysTaskWelfareMapper.insertSysTaskWelfare(welfareInfo);
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -151,6 +151,18 @@
    {
        return userMapper.selectUserByOpenId(openId);
    }
    /**
     * æ ¹æ®oaUserId查询用户
     *
     * @param oaUserId SQL Server中的OA用户ID
     * @return ç”¨æˆ·ä¿¡æ¯
     */
    @Override
    public SysUser selectUserByOaUserId(Integer oaUserId)
    {
        return userMapper.selectUserByOaUserId(oaUserId);
    }
    /**
     * æŸ¥è¯¢ç”¨æˆ·æ‰€å±žè§’色组
ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
New file
@@ -0,0 +1,182 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.LegacyTransferSyncMapper">
    <!-- è½¬è¿å•结果映射 -->
    <resultMap type="java.util.HashMap" id="TransferOrderResult">
        <result property="ServiceOrdID" column="ServiceOrdID" />
        <result property="ServiceOrdUserID" column="ServiceOrdUserID" />
        <result property="ServiceOrdAreaType" column="ServiceOrdAreaType" />
        <result property="ServiceOrdType" column="ServiceOrdType" />
        <result property="ServiceOrdTraTxnPrice" column="ServiceOrdTraTxnPrice" />
        <result property="ServiceOrdPtOutHospID" column="ServiceOrdPtOutHospID" />
        <result property="ServiceOrdPtServicesID" column="ServiceOrdPtServicesID" />
        <result property="ServiceOrdPtInHospID" column="ServiceOrdPtInHospID" />
        <result property="ServiceOrdPtInServicesID" column="ServiceOrdPtInServicesID" />
        <result property="ServiceOrdCoTies" column="ServiceOrdCoTies" />
        <result property="ServiceOrdCoName" column="ServiceOrdCoName" />
        <result property="ServiceOrdCoPhone" column="ServiceOrdCoPhone" />
        <result property="ServiceOrdClass" column="ServiceOrdClass" />
        <result property="ServiceOrdTraStreet" column="ServiceOrdTraStreet" />
        <result property="ServiceOrdTraEnd" column="ServiceOrdTraEnd" />
        <result property="ServiceOrdPtCondition" column="ServiceOrdPtCondition" />
        <result property="DispatchOrd_NS_Time" column="DispatchOrd_NS_Time" />
        <result property="ServiceOrdState" column="ServiceOrdState" />
        <result property="ServiceOrdPtIDCard" column="ServiceOrdPtIDCard" />
        <result property="ServiceOrd_NS_ID" column="ServiceOrd_NS_ID" />
        <result property="ServiceOrd_CC_ID" column="ServiceOrd_CC_ID" />
        <result property="DispatchOrdTraStreet" column="DispatchOrdTraStreet" />
        <result property="DispatchOrdStartDate" column="DispatchOrdStartDate" />
        <result property="DispatchOrdActualDate" column="DispatchOrdActualDate" />
        <result property="DispatchOrdReturnDate" column="DispatchOrdReturnDate" />
        <result property="DispatchOrdTraEnd" column="DispatchOrdTraEnd" />
        <result property="DispatchOrdID" column="DispatchOrdID" />
        <result property="DispatchOrdCarID" column="DispatchOrdCarID" />
        <result property="ServiceOrdPtName" column="ServiceOrdPtName" />
        <result property="ServiceOrdPtServices" column="ServiceOrdPtServices" />
        <result property="ServiceOrdPtInServices" column="ServiceOrdPtInServices" />
        <result property="ServiceOrdPtSex" column="ServiceOrdPtSex" />
        <result property="ServiceOrdTraVia" column="ServiceOrdTraVia" />
        <result property="Old_ServiceOrdID_TXT" column="Old_ServiceOrdID_TXT" />
        <result property="ServiceOrdTraDistance" column="ServiceOrdTraDistance" />
        <result property="ServiceOrdApptDate" column="ServiceOrdApptDate" />
    </resultMap>
    <!-- æ‰§è¡Œäººç»“果映射 -->
    <resultMap type="java.util.HashMap" id="AssigneeResult">
        <result property="EntourageOAId" column="EntourageOAId" />
        <result property="EntourageState" column="EntourageState" />
    </resultMap>
    <!-- æŸ¥è¯¢æŒ‡å®šæ—¥æœŸèŒƒå›´çš„转运单数据 -->
    <select id="selectTransferOrders" resultMap="TransferOrderResult">
        SELECT
            a.ServiceOrdID,
            a.Old_ServiceOrdID_TXT,
            a.ServiceOrdTraVia,
            a.ServiceOrdApptDate,
            a.ServiceOrd_NS_ID,
            a.ServiceOrd_CC_ID,
            a.ServiceOrd_CC_Time,
            a.ServiceOrdPtSex,
            a.ServiceOrdAreaType,
            a.ServiceOrdType,
            a.ServiceOrdTraTxnPrice,
            a.ServiceOrdPtOutHospID,
            a.ServiceOrdPtServicesID,
            a.ServiceOrdPtInHospID,
            a.ServiceOrdPtInServicesID,
            a.ServiceOrdCoTies,
            a.ServiceOrdCoName,
            a.ServiceOrdTraDistance,
            a.ServiceOrdCoPhone,
            a.ServiceOrdClass,
            a.ServiceOrdTraStreet,
            a.ServiceOrdTraEnd,
            a.ServiceOrdPtCondition,
            b.DispatchOrd_NS_Time,
            a.ServiceOrdState,
            a.ServiceOrdPtIDCard,
            b.DispatchOrdTraStreet,
            b.DispatchOrdStartDate,
            b.DispatchOrdActualDate,
            b.DispatchOrdReturnDate,
            b.DispatchOrdTraEnd,
            b.DispatchOrdID,
            b.DispatchOrdCarID,
            a.ServiceOrdPtServices,
            a.ServiceOrdPtInServices,
            a.ServiceOrdPtName
        FROM ServiceOrder as a
        INNER JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
        WHERE a.ServiceOrdState = 3
            AND a.ServiceOrd_CC_Time > #{startDate}
            AND b.DispatchOrdState != 0
    </select>
    <!-- æ ¹æ®æœåŠ¡å•ID和调度单ID查询转运单数据 -->
    <select id="selectTransferOrdersByIDs" resultMap="TransferOrderResult">
        SELECT
            a.ServiceOrdID,
            a.Old_ServiceOrdID_TXT,
            a.ServiceOrdTraVia,
            a.ServiceOrdApptDate,
            a.ServiceOrdUserID,
            a.ServiceOrd_NS_ID,
            a.ServiceOrd_CC_ID,
            a.ServiceOrd_CC_Time,
            a.ServiceOrdAreaType,
            a.ServiceOrdType,
            a.ServiceOrdPtSex,
            a.ServiceOrdTraTxnPrice,
            a.ServiceOrdPtOutHospID,
            a.ServiceOrdPtServicesID,
            a.ServiceOrdPtInHospID,
            a.ServiceOrdPtInServicesID,
            a.ServiceOrdCoTies,
            a.ServiceOrdCoName,
            a.ServiceOrdTraDistance,
            a.ServiceOrdCoPhone,
            a.ServiceOrdClass,
            a.ServiceOrdTraStreet,
            a.ServiceOrdTraEnd,
            a.ServiceOrdPtCondition,
            b.DispatchOrd_NS_Time,
            a.ServiceOrdState,
            a.ServiceOrdPtIDCard,
            b.DispatchOrdTraStreet,
            b.DispatchOrdStartDate,
            b.DispatchOrdTraEnd,
            b.DispatchOrdID,
            b.DispatchOrdCarID,
            a.ServiceOrdPtServices,
            a.ServiceOrdPtInServices,
            a.ServiceOrdPtName
        FROM ServiceOrder as a
        INNER JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
        WHERE a.ServiceOrdID = #{serviceOrdID}
            AND b.DispatchOrdID = #{dispatchOrdID}
            AND a.ServiceOrdState = 3
            AND b.DispatchOrdState != 0
    </select>
    <!-- æ ¹æ®æœåŠ¡å•ID查询病情信息 -->
    <select id="selectDiseaseIdsByServiceOrdID" resultType="String">
        SELECT icd_id
        FROM ServiceOrder_ICD
        WHERE ServiceOrdIDDt = #{serviceOrdID}
    </select>
    <!-- æ ¹æ®è°ƒåº¦å•ID查询执行人信息 -->
    <select id="selectAssigneesByDispatchOrdID" resultMap="AssigneeResult">
        SELECT
            EntourageOAId,
            EntourageState
        FROM DispatchOrd_Entourage
        WHERE DispatchOrdIDDt = #{dispatchOrdID}
    </select>
    <!-- æ ¹æ®è½¦è¾†ID查询车牌号 -->
    <select id="selectCarLicenseByCarID" resultType="String">
        SELECT CarLicense
        FROM CarData
        WHERE CarID = #{carID}
    </select>
    <!-- æ ¹æ®åŒ»é™¢ID查询医院名称 -->
    <select id="selectHospitalNameByHospID" resultType="String">
        SELECT HospName
        FROM HospData
        WHERE HospID = #{hospID}
    </select>
    <!-- æ ¹æ®ç§‘室ID查询科室名称 -->
    <select id="selectDepartmentNameByDeptID" resultType="String">
        SELECT vtext
        FROM dictionary
        WHERE vID = #{deptID} AND vtitle = 'HospitalDepartment'
    </select>
</mapper>
ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -221,5 +221,12 @@
            </foreach>
        )
    </select>
    <!-- æ ¹æ®service_class查询部门信息 -->
    <select id="selectDeptByServiceClass" parameterType="String" resultMap="SysDeptResult">
        <include refid="selectDeptVo"/>
        where d.service_order_class = #{serviceClass} and d.del_flag = '0'
        limit 1
    </select>
</mapper> 
ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
@@ -285,5 +285,17 @@
            limit 200
        </if>
    </select>
    <!-- æ ¹æ®æ—§ç³»ç»ŸæœåŠ¡å•ID查询急救转运任务扩展信息 -->
    <select id="selectByLegacyServiceOrdId" parameterType="Long" resultMap="SysTaskEmergencyResult">
        <include refid="selectSysTaskEmergencyVo"/>
        where legacy_service_ord_id = #{legacyServiceOrdId}
    </select>
    <!-- æ ¹æ®æ—§ç³»ç»Ÿè°ƒåº¦å•ID查询急救转运任务扩展信息 -->
    <select id="selectByLegacyDispatchOrdId" parameterType="Long" resultMap="SysTaskEmergencyResult">
        <include refid="selectSysTaskEmergencyVo"/>
        where legacy_dispatch_ord_id = #{legacyDispatchOrdId}
    </select>
</mapper>
ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
@@ -186,6 +186,10 @@
            <if test="creatorId != null">creator_id,</if>
            <if test="assigneeId != null">assignee_id,</if>
            <if test="deptId != null">dept_id,</if>
            <if test="plannedStartTime!=null">planned_start_time,</if>
            <if test="plannedEndTime!=null">planned_end_time,</if>
            <if test="plannedStartTime!=null">planned_start_time,</if>
            <if test="plannedEndTime!=null">planned_end_time,</if>
            <if test="createTime != null">create_time,</if>
            update_time,
            <if test="createBy != null">create_by,</if>
@@ -212,6 +216,10 @@
            <if test="creatorId != null">#{creatorId},</if>
            <if test="assigneeId != null">#{assigneeId},</if>
            <if test="deptId != null">#{deptId},</if>
            <if test="plannedStartTime!=null">#{plannedStartTime},</if>
            <if test="plannedEndTime!=null">#{plannedEndTime},</if>
            <if test="actualStartTime!=null">#{actualStartTime},</if>
            <if test="actualEndTime!=null">#{actualEndTime},</if>
            <if test="createTime != null">#{createTime},</if>
            now(),
            <if test="createBy != null">#{createBy},</if>
ruoyi-system/src/main/resources/mapper/system/SysTaskVehicleMapper.xml
@@ -27,7 +27,8 @@
               t.task_code, t.task_type
        from sys_task_vehicle tv
        left join tb_vehicle_info v on tv.vehicle_id = v.vehicle_id
        left join sys_dept d on v.dept_id = d.dept_id
        left join tb_vehicle_dept vd on v.vehicle_id = vd.vehicle_id
        left join sys_dept d on vd.dept_id = d.dept_id
        left join sys_task t on tv.task_id = t.task_id
    </sql>
@@ -117,4 +118,4 @@
    <delete id="deleteSysTaskVehicleByTaskIdAndVehicleId">
        delete from sys_task_vehicle where task_id = #{taskId} and vehicle_id = #{vehicleId}
    </delete>
</mapper>
</mapper>
ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
@@ -137,6 +137,22 @@
        <include refid="selectVehicleInfoVo"/>
        where v.vehicle_no LIKE concat('%', #{vehicleNo}, '%')
    </select>
    <!-- æ ¹æ®æ—§ç³»ç»Ÿè½¦è¾†ID(CarID)查询车辆信息 -->
    <select id="selectVehicleInfoByCarId" parameterType="Integer" resultMap="VehicleInfoResult">
        <include refid="selectVehicleInfoVo"/>
        where v.car_id = #{carId}
    </select>
    <!-- æ ¹æ®æ—§ç³»ç»Ÿè½¦è¾†ID查询车辆信息 -->
    <select id="selectVehicleInfoByCarID" resultType="java.util.HashMap">
        SELECT
            vehicle_id,
            car_id,
            vehicle_no
        FROM tb_vehicle_info
        WHERE car_id = #{carID}
    </select>
        
    <insert id="insertVehicleInfo" parameterType="VehicleInfo" useGeneratedKeys="true" keyProperty="vehicleId">
        insert into tb_vehicle_info
ruoyi-system/src/test/java/com/ruoyi/system/mapper/SysDeptMapperTest.java
ruoyi-system/src/test/java/com/ruoyi/system/service/SysDeptServiceTest.java
ruoyi-system/src/test/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImplTest.java
New file
@@ -0,0 +1,113 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.system.domain.vo.TaskCreateVO;
import com.ruoyi.system.service.ILegacyTransferSyncService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
public class LegacyTransferSyncServiceImplTest {
    @Autowired
    private ILegacyTransferSyncService legacyTransferSyncService;
    @Test
    public void testBuildCreateTaskVo() {
        // å‡†å¤‡æµ‹è¯•数据
        String serviceOrdID = "12345";
        String dispatchOrdID = "67890";
        Map<String, Object> order = new HashMap<>();
        order.put("ServiceOrdID", serviceOrdID);
        order.put("DispatchOrdID", dispatchOrdID);
        order.put("ServiceOrdPtName", "张三");
        order.put("ServiceOrdCoPhone", "13800138000");
        order.put("ServiceOrdPtIDCard", "110101199001011234");
        order.put("ServiceOrdPtCondition", "病情稳定");
        order.put("ServiceOrdCoName", "李四");
        order.put("ServiceOrdPtOutHospID", 1001L);
        order.put("ServiceOrdPtServicesID", "2001");
        order.put("ServiceOrdPtInHospID", 1002L);
        order.put("ServiceOrdPtInServicesID", "2002");
        order.put("ServiceOrdTraStreet", "北京市朝阳区某某街道123号");
        order.put("ServiceOrdTraEnd", "北京市海淀区某某医院");
        order.put("ServiceOrdTraTxnPrice", "500.00");
        order.put("ServiceOrdClass", "A001");
        order.put("ServiceOrdType", "T001");
        order.put("DispatchOrdStartDate", "2025-11-20 09:00:00");
        order.put("DispatchOrd_NS_Time", "2025-11-19 14:30:00");
        // è°ƒç”¨æ–¹æ³•
        TaskCreateVO taskCreateVO = legacyTransferSyncService.buildCreateTaskVo(serviceOrdID, dispatchOrdID, order);
        // éªŒè¯ç»“æžœ
        assertNotNull(taskCreateVO);
        assertEquals("EMERGENCY_TRANSFER", taskCreateVO.getTaskType());
        assertEquals("从旧系统同步的转运单", taskCreateVO.getTaskDescription());
        // éªŒè¯æ‚£è€…信息
        assertNotNull(taskCreateVO.getPatient());
        assertEquals("张三", taskCreateVO.getPatient().getName());
        assertEquals("13800138000", taskCreateVO.getPatient().getPhone());
        assertEquals("110101199001011234", taskCreateVO.getPatient().getIdCard());
        assertEquals("病情稳定", taskCreateVO.getPatient().getCondition());
        assertEquals("李四", taskCreateVO.getPatient().getContact());
        // éªŒè¯è½¬å‡ºåŒ»é™¢ä¿¡æ¯
        assertNotNull(taskCreateVO.getHospitalOut());
        assertEquals(Long.valueOf(1001), taskCreateVO.getHospitalOut().getId());
        assertEquals("2001", taskCreateVO.getHospitalOut().getDepartmentId());
        // éªŒè¯è½¬å…¥åŒ»é™¢ä¿¡æ¯
        assertNotNull(taskCreateVO.getHospitalIn());
        assertEquals(Long.valueOf(1002), taskCreateVO.getHospitalIn().getId());
        assertEquals("2002", taskCreateVO.getHospitalIn().getDepartmentId());
        // éªŒè¯åœ°å€ä¿¡æ¯
        assertEquals("北京市朝阳区某某街道123号", taskCreateVO.getDepartureAddress());
        assertEquals("北京市海淀区某某医院", taskCreateVO.getDestinationAddress());
        // éªŒè¯ä»·æ ¼ä¿¡æ¯
        assertEquals("500.00", taskCreateVO.getPrice().toString());
        // éªŒè¯å•据类型和任务类型
        assertEquals("A001", taskCreateVO.getDocumentTypeId());
        assertEquals("T001", taskCreateVO.getTaskTypeId());
        // éªŒè¯å¤‡æ³¨ä¿¡æ¯
        assertTrue(taskCreateVO.getRemark().contains("服务单ID: " + serviceOrdID));
        assertTrue(taskCreateVO.getRemark().contains("调度单ID: " + dispatchOrdID));
    }
    @Test
    public void testIsTransferOrderSyncedWithInvalidParams() {
        // æµ‹è¯•服务单ID为空的情况
        boolean result1 = legacyTransferSyncService.isTransferOrderSynced(null, "12345");
        assertFalse(result1);
        // æµ‹è¯•服务单ID为空字符串的情况
        boolean result2 = legacyTransferSyncService.isTransferOrderSynced("", "12345");
        assertFalse(result2);
        // æµ‹è¯•服务单ID为非数字字符串的情况
        boolean result3 = legacyTransferSyncService.isTransferOrderSynced("abc", "12345");
        assertFalse(result3);
    }
    @Test
    public void testSyncSingleTransferOrderWithInvalidParams() {
        // æµ‹è¯•服务单ID为空的情况
        boolean result1 = legacyTransferSyncService.syncSingleTransferOrder(null, "12345");
        assertFalse(result1);
        // æµ‹è¯•服务单ID为空字符串的情况
        boolean result2 = legacyTransferSyncService.syncSingleTransferOrder("", "12345");
        assertFalse(result2);
    }
}
sql/legacy_transfer_sync_job.sql
New file
@@ -0,0 +1,88 @@
-- æ—§ç³»ç»Ÿè½¬è¿å•同步定时任务配置SQL
-- åœ¨sys_job表中添加定时任务
-- è½¬è¿å•自动同步(从旧系统到新系统)
INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark)
VALUES
('旧系统转运单同步', 'DEFAULT', 'legacyTransferSyncTask.syncTransferOrders7Days', '0 0 2 * * ?', '3', '1', '0', 'admin', sysdate(),
'每天凌晨2点自动同步7天前的旧系统转运单数据。');
-- è¯´æ˜Žï¼š
-- job_name: ä»»åŠ¡åç§° - æ—§ç³»ç»Ÿè½¬è¿å•同步
-- job_group: ä»»åŠ¡ç»„åï¼ˆDEFAULT为默认组)
-- invoke_target: è°ƒç”¨ç›®æ ‡å­—符串(Bean名称.方法名)
--   - legacyTransferSyncTask.syncTransferOrders7Days() åŒæ­¥7天前的转运单数据
--   - legacyTransferSyncTask.syncTransferOrders('7') ä¹Ÿå¯ä»¥ä½¿ç”¨å¸¦å‚数的方法
-- cron_expression: cron表达式
--   - '0 0 2 * * ?' = æ¯å¤©å‡Œæ™¨2点执行
--   - '0 0 2 * * ?' = æ¯å¤©å‡Œæ™¨2点执行
--   - '0 0 3 * * ?' = æ¯å¤©å‡Œæ™¨3点执行
--   - '0 0 2 1 * ?' = æ¯æœˆ1日凌晨2点执行
-- misfire_policy: é”™è¿‡æ‰§è¡Œç­–ç•¥
--   - 1=立即执行
--   - 2=执行一次
--   - 3=放弃执行(推荐)
-- concurrent: æ˜¯å¦å¹¶å‘
--   - 0=允许并发
--   - 1=禁止并发(推荐,避免重复同步)
-- status: çŠ¶æ€
--   - 0=正常(启用)
--   - 1=暂停(停用)
-- create_by: åˆ›å»ºè€…
-- create_time: åˆ›å»ºæ—¶é—´
-- remark: å¤‡æ³¨è¯´æ˜Ž
-- åŒæ­¥é€»è¾‘:
-- 1. æ¯å¤©å‡Œæ™¨è‡ªåŠ¨æ‰§è¡ŒåŒæ­¥ä»»åŠ¡
-- 2. æŸ¥è¯¢7天前的转运单数据
-- 3. æ£€æŸ¥æ˜¯å¦å·²åŒæ­¥è¿‡
-- 4. æœªåŒæ­¥çš„转运单数据创建新任务
-- 5. è®°å½•同步日志
-- ç›‘控查询:
-- æŸ¥çœ‹ä»Šæ—¥è½¬è¿å•同步统计:
SELECT
    COUNT(*) AS total_sync_count,
    SUM(CASE WHEN task_type = 'EMERGENCY_TRANSFER' THEN 1 ELSE 0 END) AS emergency_transfer_count
FROM sys_task
WHERE DATE(create_time) = CURDATE()
  AND task_description LIKE '%从旧系统同步的转运单%';
-- æŸ¥çœ‹åŒæ­¥å¤±è´¥çš„任务:
SELECT
    task_id,
    task_code,
    task_description,
    create_time
FROM sys_task
WHERE task_description LIKE '%从旧系统同步的转运单%'
  AND task_status = 'ERROR'
ORDER BY create_time DESC;
-- æŸ¥çœ‹æœ€è¿‘同步的任务:
SELECT
    t.task_id,
    t.task_code,
    t.task_description,
    t.create_time,
    e.legacy_service_ord_id,
    e.legacy_dispatch_ord_id
FROM sys_task t
LEFT JOIN sys_task_emergency e ON t.task_id = e.task_id
WHERE t.task_description LIKE '%从旧系统同步的转运单%'
ORDER BY t.create_time DESC
LIMIT 20;
-- ä½¿ç”¨å»ºè®®ï¼š
-- 1. å»ºè®®åœ¨ä¸šåŠ¡ä½Žå³°æœŸæ‰§è¡ŒåŒæ­¥ä»»åŠ¡ï¼ˆå¦‚å‡Œæ™¨2点)
-- 2. å¯æ ¹æ®å®žé™…需求调整同步天数(如改为3天或14天)
-- 3. å®šæœŸæ£€æŸ¥åŒæ­¥å¤±è´¥çš„任务并处理
-- 4. å¯é€šè¿‡ä¿®æ”¹ status=1 ä¸´æ—¶ç¦ç”¨åŒæ­¥ä»»åŠ¡
-- é”™è¯¯å¤„理:
-- 1. å¦‚果同步失败,检查:
--    - SQL Server连接是否正常
--    - æ•°æ®æ ¼å¼æ˜¯å¦æ­£ç¡®
--    - æ–°ç³»ç»Ÿå­—段是否匹配
-- 2. å¯é€šè¿‡å®šæ—¶ä»»åŠ¡æ—¥å¿—æŸ¥çœ‹è¯¦ç»†é”™è¯¯ï¼š
--    ç³»ç»Ÿç›‘控 -> å®šæ—¶ä»»åŠ¡ -> è°ƒåº¦æ—¥å¿—