wlzboy
2025-11-01 82d6b98f5b6b88e223259547208ab59829ad723e
fix:增加旧系统状态同步到新系统,新系统状态同步到旧系统
12个文件已添加
19个文件已修改
2196 ■■■■■ 已修改文件
app/App.vue 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/task.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pages/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pages/task/detail.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pages/task/index.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/store/modules/user.js 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
prd/旧系统任务状态同步功能说明.md 311 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/LegacySystemSyncTask.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchOrdMapper.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchOrdService.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ILegacySystemSyncService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskEmergencyService.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ITaskStatusPushService.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ITaskStatusSyncService.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchOrdServiceImpl.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskEmergencyServiceImpl.java 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusPushServiceImpl.java 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusSyncServiceImpl.java 332 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskCodeGenerator.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusConverter.java 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusPushConverter.java 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/DispatchOrdMapper.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/task/general/index.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/legacy_status_sync_job.sql 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/task_status_push_job.sql 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/update_task_status_dict.sql 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/App.vue
@@ -5,14 +5,54 @@
  import { getUnreadCount } from '@/api/message'
  export default {
    data() {
      return {
        messagePollingTimer: null,
        lastToken: null // ç”¨äºŽæ£€æµ‹ token å˜åŒ–
      }
    },
    onLaunch: function() {
      this.lastToken = getToken()
      this.initApp()
      // ç›‘听用户登出事件
      uni.$on('user-logout', () => {
        console.log('接收到用户登出事件,停止消息轮询')
        this.stopMessagePolling()
        this.lastToken = null
        // æ¸…除消息徽标
        uni.removeTabBarBadge({ index: 3 })
      })
    },
    onShow: function() {
      // åº”用显示时刷新未读消息数量
      if (getToken()) {
        this.updateUnreadMessageBadge()
      const currentToken = getToken()
      // æ£€æµ‹ token å˜åŒ–:从有到无(登出)
      if (this.lastToken && !currentToken) {
        console.log('检测到用户已登出,停止消息轮询')
        this.stopMessagePolling()
        this.lastToken = currentToken
        return
      }
      // æ£€æµ‹ token å˜åŒ–:从无到有(登录)
      if (!this.lastToken && currentToken) {
        console.log('检测到用户已登录,启动消息轮询')
        this.lastToken = currentToken
      }
      // åº”用显示时刷新未读消息数量
      if (currentToken) {
        this.updateUnreadMessageBadge()
        // é‡æ–°å¯åŠ¨è½®è¯¢ï¼ˆå¦‚æžœä¹‹å‰å·²åœæ­¢ï¼‰
        if (!this.messagePollingTimer) {
          this.startMessagePolling()
        }
      }
    },
    onHide: function() {
      // åº”用隐藏时停止轮询,节省资源
      this.stopMessagePolling()
    },
    methods: {
      // åˆå§‹åŒ–应用
@@ -42,6 +82,12 @@
      
      // æ›´æ–°æœªè¯»æ¶ˆæ¯å¾½æ ‡
      updateUnreadMessageBadge() {
        // æ£€æŸ¥æ˜¯å¦å·²ç™»å½•,未登录则不请求
        if (!getToken()) {
          console.log('用户未登录,跳过获取未读消息数量')
          return
        }
        getUnreadCount().then(response => {
          const count = response.data || 0
          console.log('未读消息数量:', count)
app/api/task.js
@@ -46,7 +46,12 @@
    data: data
  })
}
/**
 * ä¿®æ”¹ä»»åŠ¡çŠ¶æ€
 * @param {*} taskId
 * @param {*} data
 * @returns
 */
export function changeTaskStatus(taskId, data) {
  return request({
    url: '/task/' + taskId + '/status',
app/pages/index.vue
@@ -246,6 +246,13 @@
      
      // åŠ è½½æœªè¯»æ¶ˆæ¯æ•°é‡
      loadUnreadMessageCount() {
        // æ£€æŸ¥ç”¨æˆ·æ˜¯å¦å·²ç™»å½•
        const userId = this.currentUser.userId
        if (!userId) {
          console.log('用户未登录,跳过获取未读消息数量')
          return
        }
        getUnreadCount().then(response => {
          if (response.code === 200) {
            this.unreadMessageCount = response.data || 0
app/pages/task/detail.vue
@@ -399,11 +399,11 @@
        getTask(this.taskId).then(response => {
          this.taskDetail = response.data || response
          // è°ƒè¯•:打印返回的数据
          console.log('任务详情完整数据:', JSON.stringify(this.taskDetail, null, 2))
          console.log('任务类型字段值:', this.taskDetail.taskType)
          console.log('任务状态字段值:', this.taskDetail.taskStatus)
          console.log('出发地址:', this.taskDetail.departureAddress)
          console.log('目的地址:', this.taskDetail.destinationAddress)
          // console.log('任务详情完整数据:', JSON.stringify(this.taskDetail, null, 2))
          // console.log('任务类型字段值:', this.taskDetail.taskType)
          // console.log('任务状态字段值:', this.taskDetail.taskStatus)
          // console.log('出发地址:', this.taskDetail.departureAddress)
          // console.log('目的地址:', this.taskDetail.destinationAddress)
        }).catch(error => {
          console.error('加载任务详情失败:', error)
          this.$modal.showToast('加载任务详情失败')
app/pages/task/index.vue
@@ -108,7 +108,7 @@
      
      <scroll-view class="task-list-scroll" scroll-y="true">
        <view class="task-list">
          <view class="task-item" v-for="task in filteredTaskList" :key="task.id">
          <view class="task-item" v-for="task in filteredTaskList" :key="task.taskId">
            <view class="task-main" @click="viewTaskDetail(task)">
              <!-- ä»»åŠ¡å¤´éƒ¨ï¼šæ ‡é¢˜å’ŒçŠ¶æ€æ ‡ç­¾ -->
              <view class="task-header">
@@ -430,8 +430,17 @@
      
      // æŸ¥çœ‹ä»»åŠ¡è¯¦æƒ…
      viewTaskDetail(task) {
        // è·³è½¬åˆ°ä»»åŠ¡è¯¦æƒ…é¡µé¢ - ä¿®å¤:使用taskId而不是id
        this.$tab.navigateTo(`/pages/task/detail?id=${task.taskId}`);
        // é˜²å¾¡æ€§æ£€æŸ¥
        if (!task || !task.taskId) {
          console.error('任务数据无效:', task)
          this.$modal.showToast('任务数据异常')
          return
        }
        // è·³è½¬åˆ°ä»»åŠ¡è¯¦æƒ…é¡µé¢ - ä½¿ç”¨uni.navigateTo
        uni.navigateTo({
          url: `/pages/task/detail?id=${task.taskId}`
        });
      },
      
      // å¤„理任务操作
@@ -516,6 +525,7 @@
            
            changeTaskStatus(taskId, statusData).then(response => {
              that.$modal.showToast('状态更新成功')
              // åˆ·æ–°ä»»åŠ¡åˆ—è¡¨
              that.loadTaskList()
            }).catch(error => {
              console.error('更新任务状态失败:', error)
@@ -533,6 +543,7 @@
              
              changeTaskStatus(taskId, statusData).then(response => {
                that.$modal.showToast('状态更新成功')
                // åˆ·æ–°ä»»åŠ¡åˆ—è¡¨
                that.loadTaskList()
              }).catch(error => {
                console.error('更新任务状态失败:', error)
app/store/modules/user.js
@@ -140,8 +140,22 @@
          commit('SET_PERMISSIONS', [])
          removeToken()
          storage.clean()
          // è§¦å‘全局事件,通知 App.vue åœæ­¢è½®è¯¢
          uni.$emit('user-logout')
          resolve()
        }).catch(error => {
          // å³ä½¿é€€å‡ºæŽ¥å£å¤±è´¥ï¼Œä¹Ÿè¦æ¸…空本地状态
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          commit('SET_PERMISSIONS', [])
          removeToken()
          storage.clean()
          // è§¦å‘全局事件
          uni.$emit('user-logout')
          reject(error)
        })
      })
prd/¾ÉϵͳÈÎÎñ״̬ͬ²½¹¦ÄÜ˵Ã÷.md
New file
@@ -0,0 +1,311 @@
# æ—§ç³»ç»Ÿä»»åŠ¡çŠ¶æ€åŒæ­¥åŠŸèƒ½è¯´æ˜Ž
## ðŸ“‹ åŠŸèƒ½æ¦‚è¿°
实现从旧系统同步任务状态到新系统,确保新旧系统的任务状态保持一致。当旧系统操作人员更新调度单状态后,新系统能够自动获取最新状态并更新本地任务。
## ðŸŽ¯ ä¸šåŠ¡åœºæ™¯
1. **状态实时更新**: æ—§ç³»ç»Ÿå¸æœº/医护人员更新了任务状态,新系统需要同步显示
2. **双系统并行**: æ–°æ—§ç³»ç»ŸåŒæ—¶ä½¿ç”¨æœŸé—´ï¼Œä¿æŒæ•°æ®ä¸€è‡´æ€§
3. **状态监控**: é€šè¿‡æ–°ç³»ç»Ÿç›‘控旧系统任务执行情况
## ðŸ“Š çŠ¶æ€æ˜ å°„è§„åˆ™
### æ—§ç³»ç»Ÿ â†’ æ–°ç³»ç»ŸçŠ¶æ€æ˜ å°„
| æ—§ç³»ç»ŸçŠ¶æ€ | çŠ¶æ€ç  | æ–°ç³»ç»ŸçŠ¶æ€ | è¯´æ˜Ž |
|---------|-------|---------|------|
| æ–°è°ƒåº¦å•(未下发) | 0 | PENDING | å¾…处理 |
| å®Œå…¨æœªç¡®è®¤ | 1 | PENDING | å¾…处理 |
| éƒ¨åˆ†å·²ç¡®è®¤ | 2 | PENDING | å¾…处理 |
| æœªå‡ºè½¦ | 3 | PENDING | å¾…处理 |
| å·²å‡ºè½¦ï¼ˆåŽ»æŽ¥æ‚£è€…é€”ä¸­ï¼‰ | 4 | DEPARTING | å‡ºå‘中 |
| å·²å‡ºè½¦ï¼ˆç­‰å¾…患者) | 5 | ARRIVED | å·²åˆ°è¾¾ |
| å·²å‡ºè½¦ï¼ˆæœåŠ¡ä¸­ï¼‰ | 6 | IN_PROGRESS | ä»»åС䏭 |
| å·²é€è¾¾ï¼ˆå›žç¨‹ä¸­ï¼‰ | 7 | RETURNING | è¿”程中 |
| å·²è¿”回 | 8 | COMPLETED | å·²å®Œæˆ |
| è·‘空单,已返回 | 9 | COMPLETED | å·²å®Œæˆ |
| å–消 | 10 | CANCELLED | å·²å–消 |
| å·²æäº¤ï¼Œç­‰å¾…审核 | 11 | PENDING | å¾…处理 |
| å®¡æ ¸å®Œæˆ | 12 | PENDING | å¾…处理 |
| å®¡æ ¸ä¸é€šè¿‡ | 13 | CANCELLED | å·²å–消 |
| å·²é©»ç‚¹ | 14 | ARRIVED | å·²åˆ°è¾¾ |
## ðŸ”§ æŠ€æœ¯å®žçް
### 1. æ ¸å¿ƒæ–‡ä»¶
#### çŠ¶æ€è½¬æ¢å·¥å…·ç±»
- **文件**: `TaskStatusConverter.java`
- **位置**: `ruoyi-system/src/main/java/com/ruoyi/system/utils/`
- **功能**:
  - æ—§ç³»ç»ŸçŠ¶æ€ç è½¬æ–°ç³»ç»ŸçŠ¶æ€æžšä¸¾
  - æ–°ç³»ç»ŸçŠ¶æ€æžšä¸¾è½¬æ—§ç³»ç»ŸçŠ¶æ€ç 
  - çŠ¶æ€æè¿°æŸ¥è¯¢
```java
// ä½¿ç”¨ç¤ºä¾‹
TaskStatus newStatus = TaskStatusConverter.convertFromLegacyStatus(4);
// è¿”回: TaskStatus.DEPARTING
Integer legacyCode = TaskStatusConverter.convertToLegacyStatus(TaskStatus.DEPARTING);
// è¿”回: 4
String description = TaskStatusConverter.getLegacyStatusDescription(4);
// è¿”回: "已出车(去接患者途中)"
```
#### åŒæ­¥æœåŠ¡æŽ¥å£
- **接口**: `ILegacySystemSyncService.java`
- **实现**: `LegacySystemSyncServiceImpl.java`
- **新增方法**:
  - `syncTaskStatusFromLegacy(Long taskId)`: åŒæ­¥å•个任务状态
  - `batchSyncTaskStatusFromLegacy()`: æ‰¹é‡åŒæ­¥ä»»åŠ¡çŠ¶æ€
#### å®šæ—¶ä»»åŠ¡
- **文件**: `LegacySystemSyncTask.java`
- **位置**: `ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/`
- **方法**: `syncTaskStatusFromLegacy()`
- **执行频率**: å»ºè®®æ¯5分钟一次
### 2. é…ç½®æ–‡ä»¶
#### æ—§ç³»ç»Ÿé…ç½®
```yaml
# application.yml
legacy:
  system:
    base-url: http://legacy-system.com
    status-query-path: /task_status_query.asp  # æ–°å¢žçŠ¶æ€æŸ¥è¯¢æŽ¥å£è·¯å¾„
    enabled: true
```
#### å®šæ—¶ä»»åŠ¡é…ç½®
执行SQL脚本: `sql/legacy_status_sync_job.sql`
```sql
-- ä»»åŠ¡é…ç½®
任务名称: ä»»åŠ¡çŠ¶æ€åŒæ­¥
调用目标: legacySystemSyncTask.syncTaskStatusFromLegacy()
Cron表达式: 0 0/5 * * * ? (每5分钟执行一次)
```
### 3. åŒæ­¥æµç¨‹
```mermaid
graph TB
    A[定时任务启动] --> B[查询需同步任务]
    B --> C{是否有任务}
    C -->|是| D[遍历任务列表]
    C -->|否| E[结束]
    D --> F[查询旧系统状态]
    F --> G{查询成功?}
    G -->|是| H[状态码转换]
    G -->|否| I[记录错误日志]
    H --> J{状态是否变化?}
    J -->|是| K[更新任务状态]
    J -->|否| L[跳过更新]
    K --> M[设置时间戳]
    M --> N[保存任务]
    L --> D
    N --> D
    I --> D
    D --> O{是否完成}
    O -->|否| D
    O -->|是| P[统计同步结果]
    P --> E
```
### 4. æ•°æ®åº“查询
#### Mapper新增方法
```xml
<!-- æŸ¥è¯¢å·²åŒæ­¥è°ƒåº¦å•且状态未完成的任务 -->
<select id="selectSyncedTasksForStatusUpdate" resultMap="SysTaskEmergencyResult">
    SELECT * FROM sys_task_emergency
    WHERE dispatch_sync_status = 2
      AND legacy_dispatch_ord_id IS NOT NULL
      AND task_id IN (
          SELECT task_id FROM sys_task
          WHERE task_status NOT IN ('COMPLETED', 'CANCELLED')
            AND del_flag = '0'
      )
    ORDER BY id ASC
    LIMIT 200
</select>
```
## ðŸš€ éƒ¨ç½²æ­¥éª¤
### 1. ä»£ç éƒ¨ç½²
```bash
# é‡æ–°ç¼–译项目
mvn clean package
# é‡å¯åº”用
./ry.sh restart
```
### 2. é…ç½®æ—§ç³»ç»ŸæŽ¥å£
确保旧系统提供状态查询接口,接口规范:
- **URL**: `/task_status_query.asp`
- **方法**: POST
- **参数**: `DispatchOrdID` (调度单ID)
- **响应格式**:
  - æˆåŠŸ: `OK:状态码` (如: `OK:4`)
  - å¤±è´¥: `ERROR:错误信息`
### 3. æ·»åŠ å®šæ—¶ä»»åŠ¡
执行SQL脚本:
```bash
mysql -u root -p your_database < sql/legacy_status_sync_job.sql
```
或在系统管理界面手动添加:
1. ç™»å½•系统管理后台
2. è¿›å…¥ `系统管理` -> `定时任务`
3. ç‚¹å‡» `新增`
4. å¡«å†™ä»»åŠ¡ä¿¡æ¯:
   - ä»»åŠ¡åç§°: ä»»åŠ¡çŠ¶æ€åŒæ­¥
   - è°ƒç”¨ç›®æ ‡å­—符串: `legacySystemSyncTask.syncTaskStatusFromLegacy()`
   - Cron表达式: `0 0/5 * * * ?`
   - çŠ¶æ€: æ­£å¸¸
5. ä¿å­˜å¹¶å¯åŠ¨ä»»åŠ¡
### 4. éªŒè¯åŠŸèƒ½
#### æ‰‹åŠ¨è§¦å‘æµ‹è¯•
```java
// åœ¨å®šæ—¶ä»»åŠ¡ç®¡ç†é¡µé¢ç‚¹å‡»"执行一次"按钮
// æˆ–在代码中调用
@Autowired
private ILegacySystemSyncService legacySystemSyncService;
// åŒæ­¥å•个任务
boolean success = legacySystemSyncService.syncTaskStatusFromLegacy(taskId);
// æ‰¹é‡åŒæ­¥
int count = legacySystemSyncService.batchSyncTaskStatusFromLegacy();
```
#### æŸ¥çœ‹åŒæ­¥ç»“æžœ
```sql
-- æŸ¥çœ‹æœ€è¿‘同步的任务
SELECT
    t.task_id,
    t.task_code,
    t.task_status,
    e.legacy_dispatch_ord_id,
    t.update_time
FROM sys_task t
INNER JOIN sys_task_emergency e ON t.task_id = e.task_id
WHERE e.dispatch_sync_status = 2
ORDER BY t.update_time DESC
LIMIT 20;
```
#### æŸ¥çœ‹æ—¥å¿—
```bash
# æŸ¥çœ‹åº”用日志
tail -f logs/sys-info.log | grep "任务状态同步"
```
## ðŸ“ åŒæ­¥è§„则
### åŒæ­¥æ¡ä»¶
任务需要满足以下所有条件才会被同步:
1. âœ… è°ƒåº¦å•已同步成功 (`dispatch_sync_status = 2`)
2. âœ… å­˜åœ¨æ—§ç³»ç»Ÿè°ƒåº¦å•ID (`legacy_dispatch_ord_id IS NOT NULL`)
3. âœ… ä»»åŠ¡çŠ¶æ€æœªå®Œæˆ (`task_status NOT IN ('COMPLETED', 'CANCELLED')`)
4. âœ… ä»»åŠ¡æœªåˆ é™¤ (`del_flag = '0'`)
### çŠ¶æ€æ›´æ–°è§„åˆ™
1. **状态相同**: ä¸æ›´æ–°ï¼Œè·³è¿‡
2. **状态不同**: æ›´æ–°ä»»åŠ¡çŠ¶æ€ï¼Œå¹¶è®¾ç½®æ—¶é—´æˆ³:
   - `DEPARTING/ARRIVED/IN_PROGRESS`: è®¾ç½® `actual_start_time`
   - `COMPLETED/CANCELLED`: è®¾ç½® `actual_start_time` å’Œ `actual_end_time`
### é˜²é‡å¤æœºåˆ¶
- æ¯æ¬¡åŒæ­¥å‰æ£€æŸ¥çŠ¶æ€æ˜¯å¦å˜åŒ–
- çŠ¶æ€æœªå˜åŒ–åˆ™è·³è¿‡æ›´æ–°ï¼Œé¿å…æ— æ•ˆæ“ä½œ
## âš ï¸ æ³¨æ„äº‹é¡¹
### 1. ä¾èµ–关系
- **前置条件**: å¿…须先完成调度单同步
- **执行顺序**:
  1. æœåŠ¡å•åŒæ­¥ (admin_save_19.gds)
  2. è°ƒåº¦å•同步 (admin_save_24.gds)
  3. çŠ¶æ€åŒæ­¥ (task_status_query.asp) â† å½“前功能
### 2. æ€§èƒ½ä¼˜åŒ–
- æ¯æ¬¡æœ€å¤šæŸ¥è¯¢200个任务
- è¯·æ±‚é—´éš”0.5秒,避免频繁请求
- ä»…同步未完成状态的任务
### 3. é”™è¯¯å¤„理
- æŸ¥è¯¢å¤±è´¥è®°å½•错误日志
- ä¸å½±å“å…¶ä»–任务的同步
- ä¸‹æ¬¡å®šæ—¶ä»»åŠ¡ç»§ç»­å°è¯•
### 4. ç›‘控建议
- å®šæœŸæ£€æŸ¥å®šæ—¶ä»»åŠ¡æ‰§è¡Œæ—¥å¿—
- ç›‘控同步成功率
- å…³æ³¨çŠ¶æ€è½¬æ¢å¼‚å¸¸
## ðŸ” æ•…障排查
### é—®é¢˜1: çŠ¶æ€æœªåŒæ­¥
**可能原因**:
1. å®šæ—¶ä»»åŠ¡æœªå¯åŠ¨
2. æ—§ç³»ç»ŸæŽ¥å£ä¸å¯ç”¨
3. ä»»åŠ¡ä¸æ»¡è¶³åŒæ­¥æ¡ä»¶
**排查步骤**:
```sql
-- 1. æ£€æŸ¥å®šæ—¶ä»»åŠ¡çŠ¶æ€
SELECT * FROM sys_job WHERE job_name = '任务状态同步';
-- 2. æ£€æŸ¥ä»»åŠ¡åŒæ­¥çŠ¶æ€
SELECT
    e.task_id,
    e.dispatch_sync_status,
    e.legacy_dispatch_ord_id,
    t.task_status
FROM sys_task_emergency e
INNER JOIN sys_task t ON e.task_id = t.task_id
WHERE e.task_id = 'YOUR_TASK_ID';
-- 3. æŸ¥çœ‹é”™è¯¯æ—¥å¿—
-- tail -f logs/sys-error.log | grep "状态同步"
```
### é—®é¢˜2: çŠ¶æ€æ˜ å°„é”™è¯¯
**解决方案**:
检查 `TaskStatusConverter.java` çš„æ˜ å°„规则是否正确
### é—®é¢˜3: æ€§èƒ½é—®é¢˜
**优化建议**:
- è°ƒæ•´å®šæ—¶ä»»åŠ¡æ‰§è¡Œé¢‘çŽ‡
- å‡å°‘每批查询的任务数量
- å¢žåŠ è¯·æ±‚é—´éš”æ—¶é—´
## ðŸ“š ç›¸å…³æ–‡æ¡£
- [任务状态流转合法性规则](../任务状态.md)
- [旧系统同步功能实现总结](旧系统同步功能实现总结.md)
- [旧系统同步参数映射表](旧系统同步参数映射表.md)
## ðŸ”„ ç‰ˆæœ¬åŽ†å²
- **v1.0** (2025-01-30)
  - å®žçŽ°åŸºç¡€çŠ¶æ€åŒæ­¥åŠŸèƒ½
  - æ”¯æŒæ–°æ—§ç³»ç»ŸçŠ¶æ€æ˜ å°„
  - æ·»åŠ å®šæ—¶ä»»åŠ¡è‡ªåŠ¨åŒæ­¥
  - å®Œå–„错误处理和日志记录
ruoyi-admin/src/main/resources/application.yml
@@ -56,7 +56,7 @@
    basename: i18n/messages
  profiles:
    # çŽ¯å¢ƒ dev|test|prod
    active: dev
    active: prod
  # æ–‡ä»¶ä¸Šä¼ 
  servlet:
    multipart:
ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java
@@ -21,6 +21,10 @@
    /** è°ƒåº¦å•创建接口路径 */
    private String dispatchCreatePath = "/admin_save_24.gds";
    
    /** ä»»åŠ¡çŠ¶æ€æŸ¥è¯¢æŽ¥å£è·¯å¾„ï¼ˆå·²å¼ƒç”¨ï¼Œç›´æŽ¥æŸ¥è¯¢SQL Server数据库) */
    @Deprecated
    private String statusQueryPath = "/task_status_query.asp";
    /** è¿žæŽ¥è¶…æ—¶æ—¶é—´(毫秒) */
    private int connectTimeout = 30000;
    
@@ -102,4 +106,19 @@
    public String getDispatchCreateUrl() {
        return baseUrl + dispatchCreatePath;
    }
    public String getStatusQueryPath() {
        return statusQueryPath;
    }
    public void setStatusQueryPath(String statusQueryPath) {
        this.statusQueryPath = statusQueryPath;
    }
    /**
     * èŽ·å–å®Œæ•´çš„çŠ¶æ€æŸ¥è¯¢URL
     */
    public String getStatusQueryUrl() {
        return baseUrl + statusQueryPath;
    }
}
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/LegacySystemSyncTask.java
@@ -6,6 +6,8 @@
import org.springframework.stereotype.Component;
import com.ruoyi.system.service.ILegacySystemSyncService;
import com.ruoyi.system.service.ITaskStatusSyncService;
import com.ruoyi.system.service.ITaskStatusPushService;
/**
 * æ—§ç³»ç»ŸåŒæ­¥å®šæ—¶ä»»åŠ¡
@@ -20,6 +22,12 @@
    
    @Autowired
    private ILegacySystemSyncService legacySystemSyncService;
    @Autowired
    private ITaskStatusSyncService taskStatusSyncService;
    @Autowired
    private ITaskStatusPushService taskStatusPushService;
    
    /**
     * æ‰¹é‡åŒæ­¥æœªåŒæ­¥çš„æ€¥æ•‘转运任务到旧系统
@@ -80,4 +88,44 @@
            log.error("旧系统调度单同步异常", e);
        }
    }
    /**
     * æ‰¹é‡åŒæ­¥ä»»åŠ¡çŠ¶æ€ï¼ˆä»Žæ—§ç³»ç»Ÿåˆ°æ–°ç³»ç»Ÿï¼‰
     *
     * ä½¿ç”¨ç¤ºä¾‹:
     * åœ¨ç³»ç»Ÿç®¡ç† -> å®šæ—¶ä»»åŠ¡ä¸­æ·»åŠ :
     * ä»»åŠ¡åç§°: ä»»åŠ¡çŠ¶æ€åŒæ­¥
     * ä»»åŠ¡ç»„å: DEFAULT
     * è°ƒç”¨ç›®æ ‡å­—符串: legacySystemSyncTask.syncTaskStatusFromLegacy()
     * cron表达式: 0 0/5 * * * ? (每5分钟执行一次)
     */
    public void syncTaskStatusFromLegacy() {
        log.info("开始执行任务状态同步定时任务(从旧系统到新系统)");
        try {
            int successCount = taskStatusSyncService.batchSyncTaskStatusFromLegacy();
            log.info("任务状态同步完成,成功同步: {} ä¸ªä»»åŠ¡", successCount);
        } catch (Exception e) {
            log.error("任务状态同步异常", e);
        }
    }
    /**
     * æ‰¹é‡æŽ¨é€ä»»åŠ¡çŠ¶æ€ï¼ˆä»Žæ–°ç³»ç»Ÿåˆ°æ—§ç³»ç»Ÿï¼‰
     *
     * ä½¿ç”¨ç¤ºä¾‹:
     * åœ¨ç³»ç»Ÿç®¡ç† -> å®šæ—¶ä»»åŠ¡ä¸­æ·»åŠ :
     * ä»»åŠ¡åç§°: ä»»åŠ¡çŠ¶æ€æŽ¨é€
     * ä»»åŠ¡ç»„å: DEFAULT
     * è°ƒç”¨ç›®æ ‡å­—符串: legacySystemSyncTask.pushTaskStatusToLegacy()
     * cron表达式: 0 0/3 * * * ? (每3分钟执行一次)
     */
    public void pushTaskStatusToLegacy() {
        log.info("开始执行任务状态推送定时任务(从新系统到旧系统)");
        try {
            int successCount = taskStatusPushService.batchPushTaskStatusToLegacy();
            log.info("任务状态推送完成,成功推送: {} ä¸ªä»»åŠ¡", successCount);
        } catch (Exception e) {
            log.error("任务状态推送异常", e);
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchOrdMapper.java
@@ -2,6 +2,7 @@
import com.ruoyi.system.domain.DictionaryCondition;
import com.ruoyi.system.domain.DispatchOrd;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -59,4 +60,29 @@
     * @return å›¾ç‰‡URL列表
     */
    public List<String> selectImageUrlsByDOrdIDDt(String dOrdIDDt);
    /**
     * æ ¹æ®è°ƒåº¦å•ID查询调度单状态
     *
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return è°ƒåº¦å•状态码
     */
    public Integer selectDispatchOrdStateByID(Long dispatchOrdID);
    /**
     * æ‰¹é‡æŸ¥è¯¢è°ƒåº¦å•状态
     *
     * @param dispatchOrdIDs è°ƒåº¦å•ID列表
     * @return è°ƒåº¦å•ID和状态的映射集合
     */
    public List<DispatchOrd> selectDispatchOrdStatesByIDs(List<Long> dispatchOrdIDs);
    /**
     * æ›´æ–°è°ƒåº¦å•状态
     *
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @param dispatchOrdState çŠ¶æ€ç 
     * @return å½±å“è¡Œæ•°
     */
    public int updateDispatchOrdState(@Param("dispatchOrdID") Long dispatchOrdID, @Param("dispatchOrdState") Integer dispatchOrdState);
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskEmergencyMapper.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.system.domain.SysTaskEmergency;
/**
@@ -61,15 +62,31 @@
    /**
     * æŸ¥è¯¢å¾…同步的急救转运任务列表(同步状态为0或3的任务)
     * æ”¯æŒåˆ†é¡µæŸ¥è¯¢ï¼Œè¿‡æ»¤å·²å®Œæˆ/已取消的任务
     * 
     * @param offset åç§»é‡ï¼ˆä»Žç¬¬å‡ æ¡å¼€å§‹ï¼‰
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    public List<SysTaskEmergency> selectPendingSyncTasks();
    public List<SysTaskEmergency> selectPendingSyncTasks(@Param("offset") Integer offset, @Param("limit") Integer limit);
    
    /**
     * æŸ¥è¯¢å¾…同步调度单的任务列表(已同步服务单但未同步调度单)
     * æ”¯æŒåˆ†é¡µæŸ¥è¯¢ï¼Œè¿‡æ»¤å·²å®Œæˆ/已取消的任务
     * 
     * @param offset åç§»é‡ï¼ˆä»Žç¬¬å‡ æ¡å¼€å§‹ï¼‰
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    public List<SysTaskEmergency> selectPendingDispatchSyncTasks();
    public List<SysTaskEmergency> selectPendingDispatchSyncTasks(@Param("offset") Integer offset, @Param("limit") Integer limit);
    /**
     * æŸ¥è¯¢å·²åŒæ­¥è°ƒåº¦å•且状态未完成的任务列表(用于状态同步)
     * æ”¯æŒåˆ†é¡µæŸ¥è¯¢
     *
     * @param offset åç§»é‡ï¼ˆä»Žç¬¬å‡ æ¡å¼€å§‹ï¼‰
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    public List<SysTaskEmergency> selectSyncedTasksForStatusUpdate(@Param("offset") Integer offset, @Param("limit") Integer limit);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchOrdService.java
@@ -58,4 +58,29 @@
     * @return å›¾ç‰‡URL列表  
     */
    public List<String> selectImageUrlsByDOrdIDDt(String dOrdIDDt);
    /**
     * æ ¹æ®è°ƒåº¦å•ID查询调度单状态
     *
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return è°ƒåº¦å•状态码
     */
    public Integer selectDispatchOrdStateByID(Long dispatchOrdID);
    /**
     * æ‰¹é‡æŸ¥è¯¢è°ƒåº¦å•状态
     *
     * @param dispatchOrdIDs è°ƒåº¦å•ID列表
     * @return è°ƒåº¦å•ID和状态的映射集合
     */
    public List<DispatchOrd> selectDispatchOrdStatesByIDs(List<Long> dispatchOrdIDs);
    /**
     * æ›´æ–°è°ƒåº¦å•状态
     *
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @param dispatchOrdState çŠ¶æ€ç 
     * @return å½±å“è¡Œæ•°
     */
    public int updateDispatchOrdState(Long dispatchOrdID, Integer dispatchOrdState);
ruoyi-system/src/main/java/com/ruoyi/system/service/ILegacySystemSyncService.java
@@ -47,4 +47,4 @@
     * @return æˆåŠŸåŒæ­¥çš„ä»»åŠ¡æ•°é‡
     */
    int batchSyncPendingDispatchOrders();
}
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskEmergencyService.java
New file
@@ -0,0 +1,91 @@
package com.ruoyi.system.service;
import com.ruoyi.system.domain.SysTaskEmergency;
import java.util.List;
/**
 * æ€¥æ•‘转运任务扩展信息Service接口
 *
 * @author ruoyi
 * @date 2024-01-16
 */
public interface ISysTaskEmergencyService {
    /**
     * æŸ¥è¯¢æ€¥æ•‘转运任务扩展信息
     *
     * @param id æ€¥æ•‘转运任务扩展信息主键
     * @return æ€¥æ•‘转运任务扩展信息
     */
    public SysTaskEmergency selectSysTaskEmergencyById(Long id);
    /**
     * é€šè¿‡ä»»åŠ¡ID查询急救转运任务扩展信息
     *
     * @param taskId ä»»åŠ¡ID
     * @return æ€¥æ•‘转运任务扩展信息
     */
    public SysTaskEmergency selectSysTaskEmergencyByTaskId(Long taskId);
    /**
     * æ–°å¢žæ€¥æ•‘转运任务扩展信息
     *
     * @param sysTaskEmergency æ€¥æ•‘转运任务扩展信息
     * @return ç»“æžœ
     */
    public int insertSysTaskEmergency(SysTaskEmergency sysTaskEmergency);
    /**
     * ä¿®æ”¹æ€¥æ•‘转运任务扩展信息
     *
     * @param sysTaskEmergency æ€¥æ•‘转运任务扩展信息
     * @return ç»“æžœ
     */
    public int updateSysTaskEmergency(SysTaskEmergency sysTaskEmergency);
    /**
     * åˆ é™¤æ€¥æ•‘转运任务扩展信息
     *
     * @param id æ€¥æ•‘转运任务扩展信息主键
     * @return ç»“æžœ
     */
    public int deleteSysTaskEmergencyById(Long id);
    /**
     * é€šè¿‡ä»»åŠ¡ID删除急救转运任务扩展信息
     *
     * @param taskId ä»»åŠ¡ID
     * @return ç»“æžœ
     */
    public int deleteSysTaskEmergencyByTaskId(Long taskId);
    /**
     * æŸ¥è¯¢å¾…同步的急救转运任务列表(同步状态为0或3的任务)
     * æ”¯æŒåˆ†é¡µæŸ¥è¯¢
     *
     * @param offset åç§»é‡
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    public List<SysTaskEmergency> selectPendingSyncTasks(Integer offset, Integer limit);
    /**
     * æŸ¥è¯¢å¾…同步调度单的任务列表(已同步服务单但未同步调度单)
     * æ”¯æŒåˆ†é¡µæŸ¥è¯¢
     *
     * @param offset åç§»é‡
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    public List<SysTaskEmergency> selectPendingDispatchSyncTasks(Integer offset, Integer limit);
    /**
     * æŸ¥è¯¢å·²åŒæ­¥è°ƒåº¦å•且状态未完成的任务列表(用于状态同步)
     * æ”¯æŒåˆ†é¡µæŸ¥è¯¢
     *
     * @param offset åç§»é‡
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    public List<SysTaskEmergency> selectSyncedTasksForStatusUpdate(Integer offset, Integer limit);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ITaskStatusPushService.java
New file
@@ -0,0 +1,27 @@
package com.ruoyi.system.service;
/**
 * ä»»åŠ¡çŠ¶æ€æŽ¨é€Service接口
 * è´Ÿè´£å°†æ–°ç³»ç»Ÿçš„任务状态推送到旧系统
 *
 * @author ruoyi
 * @date 2024-01-16
 */
public interface ITaskStatusPushService {
    /**
     * å°†å•个任务状态推送到旧系统
     *
     * @param taskId ä»»åŠ¡ID
     * @return æ˜¯å¦æŽ¨é€æˆåŠŸ
     */
    boolean pushTaskStatusToLegacy(Long taskId);
    /**
     * æ‰¹é‡æŽ¨é€ä»»åŠ¡çŠ¶æ€åˆ°æ—§ç³»ç»Ÿ
     * æŸ¥è¯¢æ–°ç³»ç»Ÿä¸­çŠ¶æ€å·²å˜åŒ–ä¸”éœ€è¦åŒæ­¥çš„ä»»åŠ¡ï¼Œæ‰¹é‡æŽ¨é€åˆ°æ—§ç³»ç»Ÿ
     *
     * @return æˆåŠŸæŽ¨é€çš„ä»»åŠ¡æ•°é‡
     */
    int batchPushTaskStatusToLegacy();
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ITaskStatusSyncService.java
New file
@@ -0,0 +1,27 @@
package com.ruoyi.system.service;
/**
 * ä»»åŠ¡çŠ¶æ€åŒæ­¥Service接口
 * è´Ÿè´£ä»Žæ—§ç³»ç»ŸåŒæ­¥ä»»åŠ¡çŠ¶æ€åˆ°æ–°ç³»ç»Ÿ
 *
 * @author ruoyi
 * @date 2024-01-16
 */
public interface ITaskStatusSyncService {
    /**
     * ä»Žæ—§ç³»ç»ŸåŒæ­¥å•个任务状态到新系统
     *
     * @param taskId ä»»åŠ¡ID
     * @return æ˜¯å¦åŒæ­¥æˆåŠŸ
     */
    boolean syncTaskStatusFromLegacy(Long taskId);
    /**
     * æ‰¹é‡åŒæ­¥å·²åŒæ­¥è°ƒåº¦å•的任务状态(从旧系统到新系统)
     * æŸ¥è¯¢å·²åŒæ­¥è°ƒåº¦å•且状态未完成的任务,批量查询旧系统状态并更新
     *
     * @return æˆåŠŸåŒæ­¥çš„ä»»åŠ¡æ•°é‡
     */
    int batchSyncTaskStatusFromLegacy();
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchOrdServiceImpl.java
@@ -87,6 +87,40 @@
    public List<String> selectImageUrlsByDOrdIDDt(String dOrdIDDt) {
        return dispatchOrdMapper.selectImageUrlsByDOrdIDDt(dOrdIDDt);
    }
    /**
     * æ ¹æ®è°ƒåº¦å•ID查询调度单状态
     *
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @return è°ƒåº¦å•状态码
     */
    @Override
    public Integer selectDispatchOrdStateByID(Long dispatchOrdID) {
        return dispatchOrdMapper.selectDispatchOrdStateByID(dispatchOrdID);
    }
    /**
     * æ‰¹é‡æŸ¥è¯¢è°ƒåº¦å•状态
     *
     * @param dispatchOrdIDs è°ƒåº¦å•ID列表
     * @return è°ƒåº¦å•ID和状态的映射集合
     */
    @Override
    public List<DispatchOrd> selectDispatchOrdStatesByIDs(List<Long> dispatchOrdIDs) {
        return dispatchOrdMapper.selectDispatchOrdStatesByIDs(dispatchOrdIDs);
    }
    /**
     * æ›´æ–°è°ƒåº¦å•状态
     *
     * @param dispatchOrdID è°ƒåº¦å•ID
     * @param dispatchOrdState çŠ¶æ€ç 
     * @return å½±å“è¡Œæ•°
     */
    @Override
    public int updateDispatchOrdState(Long dispatchOrdID, Integer dispatchOrdState) {
        return dispatchOrdMapper.updateDispatchOrdState(dispatchOrdID, dispatchOrdState);
    }
        
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
@@ -36,6 +36,9 @@
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.ILegacySystemSyncService;
import com.ruoyi.system.utils.TaskStatusConverter;
import com.ruoyi.system.service.IDispatchOrdService;
import com.ruoyi.system.service.ISysTaskEmergencyService;
/**
 * æ—§ç³»ç»ŸåŒæ­¥Service业务层处理
@@ -55,9 +58,6 @@
    private SysTaskMapper sysTaskMapper;
    
    @Autowired
    private SysTaskEmergencyMapper sysTaskEmergencyMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    
    @Autowired
@@ -71,6 +71,12 @@
    
    @Autowired
    private VehicleInfoMapper vehicleInfoMapper;
    @Autowired
    private IDispatchOrdService dispatchOrdService;
    @Autowired
    private ISysTaskEmergencyService sysTaskEmergencyService;
    
    /**
     * åŒæ­¥æ€¥æ•‘转运任务到旧系统
@@ -98,7 +104,7 @@
            }
            
            // æŸ¥è¯¢æ€¥æ•‘转运扩展信息
            SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
            SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId);
            if (emergency == null) {
                log.error("急救转运扩展信息不存在,任务ID: {}", taskId);
                return null;
@@ -112,7 +118,7 @@
            
            // æ›´æ–°åŒæ­¥çŠ¶æ€ä¸ºåŒæ­¥ä¸­
            emergency.setSyncStatus(1);
            sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
            sysTaskEmergencyService.updateSysTaskEmergency(emergency);
            
            // æž„建请求参数
            Map<String, String> params = buildSyncParams(task, emergency);
@@ -129,7 +135,7 @@
                emergency.setSyncStatus(2); // åŒæ­¥æˆåŠŸ
                emergency.setSyncTime(new Date());
                emergency.setSyncErrorMsg(null);
                sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
                sysTaskEmergencyService.updateSysTaskEmergency(emergency);
                
                // æ›´æ–°ä»»åŠ¡ä¸»è¡¨åŒæ­¥æ ‡è®°
                task.setLegacySynced(1);
@@ -142,7 +148,7 @@
                emergency.setSyncStatus(3); // åŒæ­¥å¤±è´¥
                emergency.setSyncTime(new Date());
                emergency.setSyncErrorMsg("旧系统返回无效的ServiceOrdID: " + response);
                sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
                sysTaskEmergencyService.updateSysTaskEmergency(emergency);
                
                log.error("任务同步失败,任务ID: {}, å“åº”: {}", taskId, response);
                return null;
@@ -153,12 +159,12 @@
            
            // æ›´æ–°åŒæ­¥çŠ¶æ€ä¸ºå¤±è´¥
            try {
                SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
                SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId);
                if (emergency != null) {
                    emergency.setSyncStatus(3); // åŒæ­¥å¤±è´¥
                    emergency.setSyncTime(new Date());
                    emergency.setSyncErrorMsg("同步异常: " + e.getMessage());
                    sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
                    sysTaskEmergencyService.updateSysTaskEmergency(emergency);
                }
            } catch (Exception ex) {
                log.error("更新同步状态失败", ex);
@@ -170,6 +176,7 @@
    
    /**
     * æ‰¹é‡åŒæ­¥æœªåŒæ­¥çš„æ€¥æ•‘转运任务
     * ä½¿ç”¨åˆ†é¡µæŸ¥è¯¢ï¼Œç¡®ä¿æ‰€æœ‰ç¬¦åˆæ¡ä»¶çš„任务都能被同步
     */
    @Override
    public int batchSyncPendingTasks() {
@@ -179,27 +186,53 @@
        }
        
        try {
            // æŸ¥è¯¢æœªåŒæ­¥çš„æ€¥æ•‘转运任务(同步状态为0或3的任务)
            List<SysTaskEmergency> pendingTasks = sysTaskEmergencyMapper.selectPendingSyncTasks();
            int totalSuccessCount = 0;
            int pageSize = 100; // æ¯é¡µ100条
            int offset = 0;
            
            int successCount = 0;
            for (SysTaskEmergency emergency : pendingTasks) {
                Long serviceOrdId = syncEmergencyTaskToLegacy(emergency.getTaskId());
                if (serviceOrdId != null && serviceOrdId > 0) {
                    successCount++;
            while (true) {
                // åˆ†é¡µæŸ¥è¯¢æœªåŒæ­¥çš„æ€¥æ•‘转运任务(同步状态为0或3的任务)
                List<SysTaskEmergency> pendingTasks = sysTaskEmergencyService.selectPendingSyncTasks(offset, pageSize);
                if (pendingTasks == null || pendingTasks.isEmpty()) {
                    log.info("没有更多需要同步的任务,offset: {}", offset);
                    break; // æ²¡æœ‰æ›´å¤šæ•°æ®ï¼Œé€€å‡ºå¾ªçޝ
                }
                
                // é¿å…è¿‡äºŽé¢‘繁的请求
                try {
                    Thread.sleep(1000); // æ¯ä¸ªè¯·æ±‚é—´éš”1秒
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                log.info("开始同步第 {} é¡µï¼Œä»»åŠ¡æ•°é‡: {}", (offset / pageSize) + 1, pendingTasks.size());
                int pageSuccessCount = 0;
                for (SysTaskEmergency emergency : pendingTasks) {
                    Long serviceOrdId = syncEmergencyTaskToLegacy(emergency.getTaskId());
                    if (serviceOrdId != null && serviceOrdId > 0) {
                        pageSuccessCount++;
                    }
                    // é¿å…è¿‡äºŽé¢‘繁的请求
                    try {
                        Thread.sleep(1000); // æ¯ä¸ªè¯·æ±‚é—´éš”1秒
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        log.warn("同步被中断");
                        return totalSuccessCount + pageSuccessCount;
                    }
                }
                totalSuccessCount += pageSuccessCount;
                log.info("第 {} é¡µåŒæ­¥å®Œæˆï¼Œæ€»æ•°: {}, æˆåŠŸ: {}",
                    (offset / pageSize) + 1, pendingTasks.size(), pageSuccessCount);
                // å¦‚果本页数据少于每页大小,说明已经是最后一页
                if (pendingTasks.size() < pageSize) {
                    log.info("已到达最后一页,同步结束");
                    break;
                }
                offset += pageSize; // ä¸‹ä¸€é¡µ
            }
            
            log.info("批量同步完成,总数: {}, æˆåŠŸ: {}", pendingTasks.size(), successCount);
            return successCount;
            log.info("批量同步完成,总成功数: {}", totalSuccessCount);
            return totalSuccessCount;
            
        } catch (Exception e) {
            log.error("批量同步任务异常", e);
@@ -215,12 +248,12 @@
    public boolean retrySyncTask(Long taskId) {
        try {
            // é‡ç½®åŒæ­¥çŠ¶æ€
            SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
            SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId);
            if (emergency != null) {
                emergency.setSyncStatus(0); // é‡ç½®ä¸ºæœªåŒæ­¥
                emergency.setLegacyServiceOrdId(null);
                emergency.setSyncErrorMsg(null);
                sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
                sysTaskEmergencyService.updateSysTaskEmergency(emergency);
            }
            
            // é‡æ–°åŒæ­¥
@@ -259,7 +292,7 @@
            }
            
            // æŸ¥è¯¢æ€¥æ•‘转运扩展信息
            SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
            SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId);
            if (emergency == null) {
                log.error("急救转运扩展信息不存在,任务ID: {}", taskId);
                return null;
@@ -279,7 +312,7 @@
            
            // æ›´æ–°åŒæ­¥çŠ¶æ€ä¸ºåŒæ­¥ä¸­
            emergency.setDispatchSyncStatus(1);
            sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
            sysTaskEmergencyService.updateSysTaskEmergency(emergency);
            
            // æž„建请求参数
            Map<String, String> params = buildDispatchOrderParams(task, emergency);
@@ -296,7 +329,7 @@
                emergency.setDispatchSyncStatus(2); // åŒæ­¥æˆåŠŸ
                emergency.setDispatchSyncTime(new Date());
                emergency.setDispatchSyncErrorMsg(null);
                sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
                sysTaskEmergencyService.updateSysTaskEmergency(emergency);
                
                log.info("调度单同步成功,任务ID: {}, DispatchOrdID: {}", taskId, dispatchOrdId);
                return dispatchOrdId;
@@ -305,7 +338,7 @@
                emergency.setDispatchSyncStatus(3); // åŒæ­¥å¤±è´¥
                emergency.setDispatchSyncTime(new Date());
                emergency.setDispatchSyncErrorMsg("旧系统返回无效的DispatchOrdID: " + response);
                sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
                sysTaskEmergencyService.updateSysTaskEmergency(emergency);
                
                log.error("调度单同步失败,任务ID: {}, å“åº”: {}", taskId, response);
                return null;
@@ -316,12 +349,12 @@
            
            // æ›´æ–°åŒæ­¥çŠ¶æ€ä¸ºå¤±è´¥
            try {
                SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
                SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId);
                if (emergency != null) {
                    emergency.setDispatchSyncStatus(3); // åŒæ­¥å¤±è´¥
                    emergency.setDispatchSyncTime(new Date());
                    emergency.setDispatchSyncErrorMsg("同步异常: " + e.getMessage());
                    sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
                    sysTaskEmergencyService.updateSysTaskEmergency(emergency);
                }
            } catch (Exception ex) {
                log.error("更新调度单同步状态失败", ex);
@@ -333,6 +366,7 @@
    
    /**
     * æ‰¹é‡åŒæ­¥æœªåŒæ­¥çš„调度单
     * ä½¿ç”¨åˆ†é¡µæŸ¥è¯¢ï¼Œç¡®ä¿æ‰€æœ‰ç¬¦åˆæ¡ä»¶çš„任务都能被同步
     */
    @Override
    public int batchSyncPendingDispatchOrders() {
@@ -342,27 +376,53 @@
        }
        
        try {
            // æŸ¥è¯¢å·²åŒæ­¥æœåŠ¡å•ä½†æœªåŒæ­¥è°ƒåº¦å•çš„ä»»åŠ¡
            List<SysTaskEmergency> pendingTasks = sysTaskEmergencyMapper.selectPendingDispatchSyncTasks();
            int totalSuccessCount = 0;
            int pageSize = 100; // æ¯é¡µ100条
            int offset = 0;
            
            int successCount = 0;
            for (SysTaskEmergency emergency : pendingTasks) {
                Long dispatchOrdId = syncDispatchOrderToLegacy(emergency.getTaskId());
                if (dispatchOrdId != null && dispatchOrdId > 0) {
                    successCount++;
            while (true) {
                // åˆ†é¡µæŸ¥è¯¢å·²åŒæ­¥æœåŠ¡å•ä½†æœªåŒæ­¥è°ƒåº¦å•çš„ä»»åŠ¡
                List<SysTaskEmergency> pendingTasks = sysTaskEmergencyService.selectPendingDispatchSyncTasks(offset, pageSize);
                if (pendingTasks == null || pendingTasks.isEmpty()) {
                    log.info("没有更多需要同步调度单的任务,offset: {}", offset);
                    break; // æ²¡æœ‰æ›´å¤šæ•°æ®ï¼Œé€€å‡ºå¾ªçޝ
                }
                
                // é¿å…è¿‡äºŽé¢‘繁的请求
                try {
                    Thread.sleep(1000); // æ¯ä¸ªè¯·æ±‚é—´éš”1秒
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                log.info("开始同步调度单第 {} é¡µï¼Œä»»åŠ¡æ•°é‡: {}", (offset / pageSize) + 1, pendingTasks.size());
                int pageSuccessCount = 0;
                for (SysTaskEmergency emergency : pendingTasks) {
                    Long dispatchOrdId = syncDispatchOrderToLegacy(emergency.getTaskId());
                    if (dispatchOrdId != null && dispatchOrdId > 0) {
                        pageSuccessCount++;
                    }
                    // é¿å…è¿‡äºŽé¢‘繁的请求
                    try {
                        Thread.sleep(1000); // æ¯ä¸ªè¯·æ±‚é—´éš”1秒
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        log.warn("同步调度单被中断");
                        return totalSuccessCount + pageSuccessCount;
                    }
                }
                totalSuccessCount += pageSuccessCount;
                log.info("调度单第 {} é¡µåŒæ­¥å®Œæˆï¼Œæ€»æ•°: {}, æˆåŠŸ: {}",
                    (offset / pageSize) + 1, pendingTasks.size(), pageSuccessCount);
                // å¦‚果本页数据少于每页大小,说明已经是最后一页
                if (pendingTasks.size() < pageSize) {
                    log.info("已到达最后一页,调度单同步结束");
                    break;
                }
                offset += pageSize; // ä¸‹ä¸€é¡µ
            }
            
            log.info("批量同步调度单完成,总数: {}, æˆåŠŸ: {}", pendingTasks.size(), successCount);
            return successCount;
            log.info("批量同步调度单完成,总成功数: {}", totalSuccessCount);
            return totalSuccessCount;
            
        } catch (Exception e) {
            log.error("批量同步调度单异常", e);
@@ -398,7 +458,7 @@
        // åŸºæœ¬ä¿¡æ¯
        params.put("DispatchOrdClass", dispatchOrdClass);
        params.put("ServiceOrdID", emergency.getLegacyServiceOrdId().toString());
        params.put("DispatchOrdState", "8"); // è°ƒåº¦å•状态
        params.put("DispatchOrdState", "1"); // è°ƒåº¦å•状态
        
        // æ—¶é—´ä¿¡æ¯
        if (task.getPlannedStartTime() != null) {
@@ -478,7 +538,7 @@
        params.put("ServiceOrdEstimatedOrderDateOld", ""); // åŽŸé¢„è®¡æ´¾å•æ—¶é—´
        params.put("ServiceOrdViaDistance", "0"); // ä¸­é€”距离
        params.put("ServiceOrdTraDistance", emergency.getTransferDistance() != null ? emergency.getTransferDistance().toString() : "0"); // è·ç¦»
        params.put("OrderLevel", "2"); // æŸ¥çœ‹ç­‰çº§
        params.put("OrderLevel", "0"); // æŸ¥çœ‹ç­‰çº§
        params.put("ServiceOrdDepartureType", "1"); // é¢„约类型
        params.put("ConditionLevel", "0"); // ç—…重级别
        params.put("DirectionType", "0"); // è½¬è¿å޻向
@@ -866,7 +926,7 @@
        params.put("ServiceOrdOperationRemarks", "新系统同步创建"); // æ“ä½œå¤‡æ³¨
        params.put("ServiceOrdEstimatedOrderDate", ""); // é¢„计派单时间
        params.put("ServiceOrdSource", "10"); // è®¢å•来源(10=新系统)
        params.put("OrderLevel", "2"); // æŸ¥çœ‹ç­‰çº§
        params.put("OrderLevel", "0"); // æŸ¥çœ‹ç­‰çº§
        params.put("ServiceOrdDepartureType", "1"); // é¢„约类型
        params.put("ConditionLevel", "0"); // ç—…重级别
        params.put("DirectionType", "0"); // è½¬è¿å޻向
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskEmergencyServiceImpl.java
New file
@@ -0,0 +1,124 @@
package com.ruoyi.system.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SysTaskEmergencyMapper;
import com.ruoyi.system.domain.SysTaskEmergency;
import com.ruoyi.system.service.ISysTaskEmergencyService;
import java.util.List;
/**
 * æ€¥æ•‘转运任务扩展信息Service业务层处理
 *
 * @author ruoyi
 * @date 2024-01-16
 */
@Service
public class SysTaskEmergencyServiceImpl implements ISysTaskEmergencyService {
    @Autowired
    private SysTaskEmergencyMapper sysTaskEmergencyMapper;
    /**
     * æŸ¥è¯¢æ€¥æ•‘转运任务扩展信息
     *
     * @param id æ€¥æ•‘转运任务扩展信息主键
     * @return æ€¥æ•‘转运任务扩展信息
     */
    @Override
    public SysTaskEmergency selectSysTaskEmergencyById(Long id) {
        return sysTaskEmergencyMapper.selectSysTaskEmergencyById(id);
    }
    /**
     * é€šè¿‡ä»»åŠ¡ID查询急救转运任务扩展信息
     *
     * @param taskId ä»»åŠ¡ID
     * @return æ€¥æ•‘转运任务扩展信息
     */
    @Override
    public SysTaskEmergency selectSysTaskEmergencyByTaskId(Long taskId) {
        return sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
    }
    /**
     * æ–°å¢žæ€¥æ•‘转运任务扩展信息
     *
     * @param sysTaskEmergency æ€¥æ•‘转运任务扩展信息
     * @return ç»“æžœ
     */
    @Override
    public int insertSysTaskEmergency(SysTaskEmergency sysTaskEmergency) {
        return sysTaskEmergencyMapper.insertSysTaskEmergency(sysTaskEmergency);
    }
    /**
     * ä¿®æ”¹æ€¥æ•‘转运任务扩展信息
     *
     * @param sysTaskEmergency æ€¥æ•‘转运任务扩展信息
     * @return ç»“æžœ
     */
    @Override
    public int updateSysTaskEmergency(SysTaskEmergency sysTaskEmergency) {
        return sysTaskEmergencyMapper.updateSysTaskEmergency(sysTaskEmergency);
    }
    /**
     * åˆ é™¤æ€¥æ•‘转运任务扩展信息
     *
     * @param id æ€¥æ•‘转运任务扩展信息主键
     * @return ç»“æžœ
     */
    @Override
    public int deleteSysTaskEmergencyById(Long id) {
        return sysTaskEmergencyMapper.deleteSysTaskEmergencyById(id);
    }
    /**
     * é€šè¿‡ä»»åŠ¡ID删除急救转运任务扩展信息
     *
     * @param taskId ä»»åŠ¡ID
     * @return ç»“æžœ
     */
    @Override
    public int deleteSysTaskEmergencyByTaskId(Long taskId) {
        return sysTaskEmergencyMapper.deleteSysTaskEmergencyByTaskId(taskId);
    }
    /**
     * æŸ¥è¯¢å¾…同步的急救转运任务列表(同步状态为0或3的任务)
     *
     * @param offset åç§»é‡
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    @Override
    public List<SysTaskEmergency> selectPendingSyncTasks(Integer offset, Integer limit) {
        return sysTaskEmergencyMapper.selectPendingSyncTasks(offset, limit);
    }
    /**
     * æŸ¥è¯¢å¾…同步调度单的任务列表(已同步服务单但未同步调度单)
     *
     * @param offset åç§»é‡
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    @Override
    public List<SysTaskEmergency> selectPendingDispatchSyncTasks(Integer offset, Integer limit) {
        return sysTaskEmergencyMapper.selectPendingDispatchSyncTasks(offset, limit);
    }
    /**
     * æŸ¥è¯¢å·²åŒæ­¥è°ƒåº¦å•且状态未完成的任务列表(用于状态同步)
     *
     * @param offset åç§»é‡
     * @param limit æ¯é¡µæ•°é‡
     * @return æ€¥æ•‘转运任务列表
     */
    @Override
    public List<SysTaskEmergency> selectSyncedTasksForStatusUpdate(Integer offset, Integer limit) {
        return sysTaskEmergencyMapper.selectSyncedTasksForStatusUpdate(offset, limit);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusPushServiceImpl.java
New file
@@ -0,0 +1,235 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.config.LegacySystemConfig;
import com.ruoyi.system.domain.SysTask;
import com.ruoyi.system.domain.SysTaskEmergency;
import com.ruoyi.system.domain.enums.TaskStatus;
import com.ruoyi.system.mapper.SysTaskMapper;
import com.ruoyi.system.service.IDispatchOrdService;
import com.ruoyi.system.service.ISysTaskEmergencyService;
import com.ruoyi.system.service.ITaskStatusPushService;
import com.ruoyi.system.utils.TaskStatusPushConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
/**
 * ä»»åŠ¡çŠ¶æ€æŽ¨é€Service业务层处理
 * è´Ÿè´£å°†æ–°ç³»ç»Ÿçš„任务状态推送到旧系统
 *
 * @author ruoyi
 * @date 2024-01-16
 */
@Service
public class TaskStatusPushServiceImpl implements ITaskStatusPushService {
    private static final Logger log = LoggerFactory.getLogger(TaskStatusPushServiceImpl.class);
    @Autowired
    private LegacySystemConfig legacyConfig;
    @Autowired
    private SysTaskMapper sysTaskMapper;
    @Autowired
    private ISysTaskEmergencyService sysTaskEmergencyService;
    @Autowired
    private IDispatchOrdService dispatchOrdService;
    /**
     * å°†å•个任务状态推送到旧系统
     *
     * @param taskId ä»»åŠ¡ID
     * @return æ˜¯å¦æŽ¨é€æˆåŠŸ
     */
    @Override
    @Transactional
    public boolean pushTaskStatusToLegacy(Long taskId) {
        if (!legacyConfig.isEnabled()) {
            log.info("旧系统同步已禁用,跳过状态推送,任务ID: {}", taskId);
            return false;
        }
        try {
            // æŸ¥è¯¢ä»»åŠ¡ä¿¡æ¯
            log.debug("【新推旧】查询任务ID: {}", taskId);
            SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
            if (task == null) {
                log.error("【新推旧】任务不存在,任务ID: {}", taskId);
                return false;
            }
            // åªæŽ¨é€æ€¥æ•‘转运任务
            if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
                log.info("非急救转运任务,跳过状态推送,任务ID: {}", taskId);
                return false;
            }
            // æŸ¥è¯¢æ€¥æ•‘转运扩展信息
            SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId);
            if (emergency == null) {
                log.error("急救转运扩展信息不存在,任务ID: {}", taskId);
                return false;
            }
            // å¿…须已经同步过调度单
            if (emergency.getLegacyDispatchOrdId() == null || emergency.getLegacyDispatchOrdId() <= 0) {
                log.warn("调度单未同步,无法推送状态,任务ID: {}", taskId);
                return false;
            }
            // èŽ·å–æ–°ç³»ç»ŸçŠ¶æ€
            TaskStatus newTaskStatus = TaskStatus.getByCode(task.getTaskStatus());
            if (newTaskStatus == null) {
                log.error("无效的任务状态,任务ID: {}, çŠ¶æ€ç : {}", taskId, task.getTaskStatus());
                return false;
            }
            // è½¬æ¢ä¸ºæ—§ç³»ç»ŸçŠ¶æ€ç 
            Integer targetStatusCode = TaskStatusPushConverter.convertToLegacyStatus(newTaskStatus);
            if (targetStatusCode == null) {
                log.debug("【新推旧】任务状态不需要推送到旧系统,任务ID: {}, çŠ¶æ€: {}",
                    taskId, newTaskStatus.getInfo());
                return false;
            }
            // æŸ¥è¯¢æ—§ç³»ç»Ÿå½“前状态
            Integer currentLegacyStatus = dispatchOrdService.selectDispatchOrdStateByID(
                emergency.getLegacyDispatchOrdId());
            if (currentLegacyStatus == null) {
                log.error("【新推旧】查询旧系统状态失败,任务ID: {}, DispatchOrdID: {}",
                    taskId, emergency.getLegacyDispatchOrdId());
                return false;
            }
            // åˆ¤æ–­æ˜¯å¦éœ€è¦æ›´æ–°ï¼ˆåŒ…含防止状态倒退的检查)
            // å¦‚果旧系统状态已经 >= æ–°ç³»ç»Ÿè¦æŽ¨é€çš„状态,说明旧系统状态更新,新系统落后,不应该推送
            if (!TaskStatusPushConverter.shouldUpdateLegacyStatus(targetStatusCode, currentLegacyStatus)) {
                log.info("【新推旧】新系统状态落后或等于旧系统状态,跳过推送,任务ID: {}, æ–°ç³»ç»ŸçŠ¶æ€: {} ({}→{}), æ—§ç³»ç»ŸçŠ¶æ€: {} ({})",
                    taskId,
                    task.getTaskStatus(), newTaskStatus.getInfo(), targetStatusCode,
                    currentLegacyStatus, TaskStatusPushConverter.getLegacyStatusDescription(currentLegacyStatus));
                return true; // è¿”回true,因为这不算失败,只是不需要推送
            }
            // æŽ¨é€çŠ¶æ€åˆ°æ—§ç³»ç»Ÿ
            boolean result = updateLegacyTaskStatus(emergency.getLegacyDispatchOrdId(), targetStatusCode);
            if (result) {
                log.info("【新推旧】任务状态推送成功,任务ID: {}, DispatchOrdID: {}, æ—§çŠ¶æ€: {} ({}), æ–°çŠ¶æ€: {} ({})",
                    taskId, emergency.getLegacyDispatchOrdId(),
                    currentLegacyStatus, TaskStatusPushConverter.getLegacyStatusDescription(currentLegacyStatus),
                    targetStatusCode, TaskStatusPushConverter.getLegacyStatusDescription(targetStatusCode));
            } else {
                log.error("【新推旧】任务状态推送失败,任务ID: {}, DispatchOrdID: {}",
                    taskId, emergency.getLegacyDispatchOrdId());
            }
            return result;
        } catch (Exception e) {
            log.error("【新推旧】推送任务状态异常,任务ID: {}", taskId, e);
            return false;
        }
    }
    /**
     * æ‰¹é‡æŽ¨é€ä»»åŠ¡çŠ¶æ€åˆ°æ—§ç³»ç»Ÿ
     * ä½¿ç”¨åˆ†é¡µæŸ¥è¯¢ï¼Œç¡®ä¿æ‰€æœ‰ç¬¦åˆæ¡ä»¶çš„任务都能被推送
     *
     * @return æˆåŠŸæŽ¨é€çš„ä»»åŠ¡æ•°é‡
     */
    @Override
    public int batchPushTaskStatusToLegacy() {
        if (!legacyConfig.isEnabled()) {
            log.info("旧系统同步已禁用");
            return 0;
        }
        try {
            int totalSuccessCount = 0;
            int pageSize = 200; // æ¯é¡µ200条
            int offset = 0;
            while (true) {
                // åˆ†é¡µæŸ¥è¯¢å·²åŒæ­¥è°ƒåº¦å•且状态未完成的任务
                List<SysTaskEmergency> syncedTasks = sysTaskEmergencyService.selectSyncedTasksForStatusUpdate(offset, pageSize);
                if (syncedTasks == null || syncedTasks.isEmpty()) {
                    log.info("【新推旧】没有更多需要推送状态的任务,offset: {}", offset);
                    break; // æ²¡æœ‰æ›´å¤šæ•°æ®ï¼Œé€€å‡ºå¾ªçޝ
                }
                log.info("【新推旧】开始推送状态第 {} é¡µï¼Œä»»åŠ¡æ•°é‡: {}", (offset / pageSize) + 1, syncedTasks.size());
                int pageSuccessCount = 0;
                for (SysTaskEmergency emergency : syncedTasks) {
                    boolean result = pushTaskStatusToLegacy(emergency.getTaskId());
                    if (result) {
                        pageSuccessCount++;
                    }
                    // é¿å…è¿‡äºŽé¢‘繁的请求
                    try {
                        Thread.sleep(200); // æ¯ä¸ªè¯·æ±‚é—´éš”0.2秒
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        log.warn("【新推旧】推送状态被中断");
                        return totalSuccessCount + pageSuccessCount;
                    }
                }
                totalSuccessCount += pageSuccessCount;
                log.info("状态第 {} é¡µæŽ¨é€å®Œæˆï¼Œæ€»æ•°: {}, æˆåŠŸ: {}",
                    (offset / pageSize) + 1, syncedTasks.size(), pageSuccessCount);
                // å¦‚果本页数据少于每页大小,说明已经是最后一页
                if (syncedTasks.size() < pageSize) {
                    log.info("【新推旧】已到达最后一页,状态推送结束");
                    break;
                }
                offset += pageSize; // ä¸‹ä¸€é¡µ
            }
            log.info("【新推旧】批量推送任务状态完成,总成功数: {}", totalSuccessCount);
            return totalSuccessCount;
        } catch (Exception e) {
            log.error("【新推旧】批量推送任务状态异常", e);
            return 0;
        }
    }
    /**
     * æ›´æ–°æ—§ç³»ç»Ÿè°ƒåº¦å•状态(直接操作SQL Server数据库)
     *
     * @param dispatchOrdId è°ƒåº¦å•ID
     * @param statusCode ç›®æ ‡çŠ¶æ€ç 
     * @return æ˜¯å¦æˆåŠŸ
     */
    private boolean updateLegacyTaskStatus(Long dispatchOrdId, Integer statusCode) {
        try {
            // ç›´æŽ¥é€šè¿‡Service调用Mapper更新SQL Server数据库
            int rows = dispatchOrdService.updateDispatchOrdState(dispatchOrdId, statusCode);
            log.debug("更新旧系统状态,DispatchOrdID: {}, StateInt: {}", dispatchOrdId, statusCode);
            if (rows > 0) {
                log.debug("更新旧系统状态成功,DispatchOrdID: {}, StateInt: {}",
                    dispatchOrdId, statusCode);
                return true;
            } else {
                log.warn("更新旧系统状态失败,未找到对应调度单,DispatchOrdID: {}", dispatchOrdId);
                return false;
            }
        } catch (Exception e) {
            log.error("更新旧系统状态异常,DispatchOrdID: {}", dispatchOrdId, e);
            return false;
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusSyncServiceImpl.java
New file
@@ -0,0 +1,332 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.config.LegacySystemConfig;
import com.ruoyi.system.domain.DispatchOrd;
import com.ruoyi.system.domain.SysTask;
import com.ruoyi.system.domain.SysTaskEmergency;
import com.ruoyi.system.domain.enums.TaskStatus;
import com.ruoyi.system.mapper.SysTaskMapper;
import com.ruoyi.system.service.IDispatchOrdService;
import com.ruoyi.system.service.ISysTaskEmergencyService;
import com.ruoyi.system.service.ITaskStatusSyncService;
import com.ruoyi.system.utils.TaskStatusConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
/**
 * ä»»åŠ¡çŠ¶æ€åŒæ­¥Service业务层处理
 * è´Ÿè´£ä»Žæ—§ç³»ç»ŸåŒæ­¥ä»»åŠ¡çŠ¶æ€åˆ°æ–°ç³»ç»Ÿ
 *
 * @author ruoyi
 * @date 2024-01-16
 */
@Service
public class TaskStatusSyncServiceImpl implements ITaskStatusSyncService {
    private static final Logger log = LoggerFactory.getLogger(TaskStatusSyncServiceImpl.class);
    @Autowired
    private LegacySystemConfig legacyConfig;
    @Autowired
    private SysTaskMapper sysTaskMapper;
    @Autowired
    private ISysTaskEmergencyService sysTaskEmergencyService;
    @Autowired
    private IDispatchOrdService dispatchOrdService;
    /**
     * ä»Žæ—§ç³»ç»ŸåŒæ­¥å•个任务状态到新系统
     *
     * @param taskId ä»»åŠ¡ID
     * @return æ˜¯å¦åŒæ­¥æˆåŠŸ
     */
    @Override
    @Transactional
    public boolean syncTaskStatusFromLegacy(Long taskId) {
        if (!legacyConfig.isEnabled()) {
            log.info("旧系统同步已禁用,跳过状态同步,任务ID: {}", taskId);
            return false;
        }
        try {
            // æŸ¥è¯¢ä»»åŠ¡ä¿¡æ¯
            SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
            if (task == null) {
                log.error("任务不存在,任务ID: {}", taskId);
                return false;
            }
            // åªåŒæ­¥æ€¥æ•‘转运任务
            if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
                log.info("非急救转运任务,跳过状态同步,任务ID: {}", taskId);
                return false;
            }
            // æŸ¥è¯¢æ€¥æ•‘转运扩展信息
            SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId);
            if (emergency == null) {
                log.error("急救转运扩展信息不存在,任务ID: {}", taskId);
                return false;
            }
            // å¿…须已经同步过调度单
            if (emergency.getLegacyDispatchOrdId() == null || emergency.getLegacyDispatchOrdId() <= 0) {
                log.warn("调度单未同步,无法同步状态,任务ID: {}", taskId);
                return false;
            }
            // æŸ¥è¯¢æ—§ç³»ç»ŸçŠ¶æ€ï¼ˆç›´æŽ¥æŸ¥è¯¢SQL Server数据库)
            Integer legacyStatus = dispatchOrdService.selectDispatchOrdStateByID(emergency.getLegacyDispatchOrdId());
            if (legacyStatus == null) {
                log.error("查询旧系统状态失败,任务ID: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId());
                return false;
            }
            // è°ƒç”¨å†…部方法同步状态
            return syncTaskStatusWithLegacyState(taskId, legacyStatus);
        } catch (Exception e) {
            log.error("同步任务状态异常,任务ID: {}", taskId, e);
            return false;
        }
    }
    /**
     * æ‰¹é‡åŒæ­¥å·²åŒæ­¥è°ƒåº¦å•的任务状态(从旧系统到新系统)
     * ä½¿ç”¨åˆ†é¡µæŸ¥è¯¢ï¼Œæ‰¹é‡æŸ¥è¯¢SQL Server数据库,减少网络请求次数
     *
     * @return æˆåŠŸåŒæ­¥çš„ä»»åŠ¡æ•°é‡
     */
    @Override
    public int batchSyncTaskStatusFromLegacy() {
        if (!legacyConfig.isEnabled()) {
            log.info("旧系统同步已禁用");
            return 0;
        }
        try {
            int totalSuccessCount = 0;
            int pageSize = 200; // æ¯é¡µ200条
            int offset = 0;
            while (true) {
                // 1. åˆ†é¡µæŸ¥è¯¢æ–°ç³»ç»Ÿä¸­éœ€è¦åŒæ­¥çŠ¶æ€çš„ä»»åŠ¡ï¼ˆå·²åŒæ­¥è°ƒåº¦å•ä¸”çŠ¶æ€æœªå®Œæˆï¼‰
                List<SysTaskEmergency> syncedTasks = sysTaskEmergencyService.selectSyncedTasksForStatusUpdate(offset, pageSize);
                if (syncedTasks == null || syncedTasks.isEmpty()) {
                    log.info("没有更多需要同步状态的任务,offset: {}", offset);
                    break; // æ²¡æœ‰æ›´å¤šæ•°æ®ï¼Œé€€å‡ºå¾ªçޝ
                }
                log.info("开始同步状态第 {} é¡µï¼Œä»»åŠ¡æ•°é‡: {}", (offset / pageSize) + 1, syncedTasks.size());
                // 2. æå–调度单ID列表
                List<Long> dispatchOrdIDs = new ArrayList<>();
                Map<Long, SysTaskEmergency> dispatchIdToTaskMap = new HashMap<>();
                for (SysTaskEmergency emergency : syncedTasks) {
                    Long dispatchOrdId = emergency.getLegacyDispatchOrdId();
                    if (dispatchOrdId != null && dispatchOrdId > 0) {
                        dispatchOrdIDs.add(dispatchOrdId);
                        dispatchIdToTaskMap.put(dispatchOrdId, emergency);
                    }
                }
                if (dispatchOrdIDs.isEmpty()) {
                    log.warn("本页没有有效的调度单ID");
                    offset += pageSize;
                    continue;
                }
                // 3. æ‰¹é‡æŸ¥è¯¢æ—§ç³»ç»Ÿè°ƒåº¦å•状态(直接查询SQL Server数据库)
                List<DispatchOrd> dispatchOrds = dispatchOrdService.selectDispatchOrdStatesByIDs(dispatchOrdIDs);
                if (dispatchOrds == null || dispatchOrds.isEmpty()) {
                    log.warn("未查询到旧系统调度单状态");
                    offset += pageSize;
                    continue;
                }
                // 4. æž„建调度单ID到状态的映射
                Map<Long, Integer> dispatchIdToStateMap = new HashMap<>();
                for (DispatchOrd dispatchOrd : dispatchOrds) {
                    try {
                        Long dispatchOrdId = Long.parseLong(dispatchOrd.getDispatchOrdID());
                        Integer dispatchOrdState = Integer.parseInt(dispatchOrd.getDispatchOrdState());
                        if (dispatchOrdState != null) {
                            dispatchIdToStateMap.put(dispatchOrdId, dispatchOrdState);
                        }
                    } catch (NumberFormatException e) {
                        log.error("解析调度单ID失败: {}", dispatchOrd.getDispatchOrdID(), e);
                    }
                }
                // 5. éåŽ†ä»»åŠ¡ï¼ŒåŒæ­¥çŠ¶æ€
                int pageSuccessCount = 0;
                for (Map.Entry<Long, SysTaskEmergency> entry : dispatchIdToTaskMap.entrySet()) {
                    Long dispatchOrdId = entry.getKey();
                    SysTaskEmergency emergency = entry.getValue();
                    // èŽ·å–æ—§ç³»ç»ŸçŠ¶æ€
                    Integer legacyStatus = dispatchIdToStateMap.get(dispatchOrdId);
                    if (legacyStatus == null) {
                        log.warn("未找到调度单状态,DispatchOrdID: {}", dispatchOrdId);
                        continue;
                    }
                    // åŒæ­¥å•个任务状态
                    boolean result = syncTaskStatusWithLegacyState(emergency.getTaskId(), legacyStatus);
                    if (result) {
                        pageSuccessCount++;
                    }
                }
                totalSuccessCount += pageSuccessCount;
                log.info("状态第 {} é¡µåŒæ­¥å®Œæˆï¼Œæ€»æ•°: {}, æˆåŠŸ: {}",
                    (offset / pageSize) + 1, syncedTasks.size(), pageSuccessCount);
                // å¦‚果本页数据少于每页大小,说明已经是最后一页
                if (syncedTasks.size() < pageSize) {
                    log.info("已到达最后一页,状态同步结束");
                    break;
                }
                offset += pageSize; // ä¸‹ä¸€é¡µ
            }
            log.info("批量同步任务状态完成,总成功数: {}", totalSuccessCount);
            return totalSuccessCount;
        } catch (Exception e) {
            log.error("批量同步任务状态异常", e);
            return 0;
        }
    }
    /**
     * åŒæ­¥å•个任务状态(已知旧系统状态码)
     * å¢žåŠ çŠ¶æ€å¯¹æ¯”é€»è¾‘ï¼šå½“æ—§ç³»ç»ŸçŠ¶æ€è½åŽäºŽæ–°ç³»ç»ŸçŠ¶æ€æ—¶ï¼Œä¸è¿›è¡ŒåŒæ­¥
     *
     * @param taskId ä»»åŠ¡ID
     * @param legacyStatus æ—§ç³»ç»ŸçŠ¶æ€ç 
     * @return æ˜¯å¦æˆåŠŸ
     */
    @Transactional
    private boolean syncTaskStatusWithLegacyState(Long taskId, Integer legacyStatus) {
        try {
            // æŸ¥è¯¢ä»»åŠ¡ä¿¡æ¯
            SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
            if (task == null) {
                log.error("任务不存在,任务ID: {}", taskId);
                return false;
            }
            // è½¬æ¢ä¸ºæ–°ç³»ç»ŸçŠ¶æ€
            TaskStatus newStatus = TaskStatusConverter.convertFromLegacyStatus(legacyStatus);
            if (newStatus == null) {
                log.debug("旧系统状态码 > 10 æˆ–无法转换,跳过同步,任务ID: {}, çŠ¶æ€ç : {} ({})",
                    taskId, legacyStatus, TaskStatusConverter.getLegacyStatusDescription(legacyStatus));
                return false;
            }
            // æ£€æŸ¥çŠ¶æ€æ˜¯å¦å˜åŒ–
            if (newStatus.getCode().equals(task.getTaskStatus())) {
                log.debug("任务状态未变化,任务ID: {}, å½“前状态: {}", taskId, newStatus.getInfo());
                return true;
            }
            // æ¯”较新旧系统状态的优先级,防止状态倒退
            TaskStatus currentStatus = TaskStatus.getByCode(task.getTaskStatus());
            if (currentStatus != null && !shouldSyncStatus(currentStatus, newStatus, legacyStatus)) {
                log.info("【旧系统更新到新系统】 æ—§ç³»ç»ŸçŠ¶æ€è½åŽäºŽæ–°ç³»ç»ŸçŠ¶æ€ï¼Œè·³è¿‡åŒæ­¥ï¼Œä»»åŠ¡ID: {}, æ–°ç³»ç»ŸçŠ¶æ€: {} ({}), æ—§ç³»ç»ŸçŠ¶æ€: {} ({})",
                    taskId, task.getTaskStatus(), currentStatus.getInfo(),
                    newStatus.getCode(), TaskStatusConverter.getLegacyStatusDescription(legacyStatus));
                return false;
            }
            // æ›´æ–°ä»»åŠ¡çŠ¶æ€
            String oldStatus = task.getTaskStatus();
            task.setTaskStatus(newStatus.getCode());
            // æ ¹æ®çŠ¶æ€è®¾ç½®æ—¶é—´
            Date now = new Date();
            switch (newStatus) {
                case DEPARTING:
                case ARRIVED:
                case IN_PROGRESS:
                    // å¦‚果实际开始时间为空,设置实际开始时间
                    if (task.getActualStartTime() == null) {
                        task.setActualStartTime(now);
                    }
                    break;
                case COMPLETED:
                case CANCELLED:
                    // è®¾ç½®å®žé™…结束时间
                    if (task.getActualEndTime() == null) {
                        task.setActualEndTime(now);
                    }
                    // å¦‚果实际开始时间为空,也设置一下
                    if (task.getActualStartTime() == null) {
                        task.setActualStartTime(now);
                    }
                    break;
                default:
                    break;
            }
            sysTaskMapper.updateSysTask(task);
            log.info("任务状态同步成功,任务ID: {}, æ—§çŠ¶æ€: {}, æ–°çŠ¶æ€: {}, æ—§ç³»ç»ŸçŠ¶æ€ç : {} ({})",
                taskId, oldStatus, newStatus.getCode(), legacyStatus,
                TaskStatusConverter.getLegacyStatusDescription(legacyStatus));
            return true;
        } catch (Exception e) {
            log.error("同步任务状态异常,任务ID: {}", taskId, e);
            return false;
        }
    }
    /**
     * åˆ¤æ–­æ˜¯å¦åº”该同步状态
     * è§„则:旧系统状态码需要大于等于新系统当前状态对应的旧系统状态码
     * é˜²æ­¢å› ä¸ºæ—¶é—´å·®å¯¼è‡´æ–°ç³»ç»ŸçŠ¶æ€æ¯”æ—§ç³»ç»Ÿæ›´æ–°ï¼Œè€Œè¢«æ—§ç³»ç»Ÿçš„æ—§çŠ¶æ€è¦†ç›–
     *
     * @param currentStatus æ–°ç³»ç»Ÿå½“前状态
     * @param targetStatus æ—§ç³»ç»Ÿè½¬æ¢åŽçš„目标状态
     * @param legacyStatusCode æ—§ç³»ç»ŸçŠ¶æ€ç 
     * @return true-应该同步,false-不应该同步
     */
    private boolean shouldSyncStatus(TaskStatus currentStatus, TaskStatus targetStatus, Integer legacyStatusCode) {
        // èŽ·å–æ–°ç³»ç»Ÿå½“å‰çŠ¶æ€å¯¹åº”çš„æ—§ç³»ç»ŸçŠ¶æ€ç 
        Integer currentLegacyCode = TaskStatusConverter.convertToLegacyStatus(currentStatus);
        if (currentLegacyCode == null) {
            // å¦‚果当前状态无法转换为旧系统状态码,允许同步
            log.warn("新系统当前状态无法转换为旧系统状态码,允许同步,当前状态: {}", currentStatus.getCode());
            return true;
        }
        // æ¯”较状态码大小
        // æ—§ç³»ç»ŸçŠ¶æ€ç  >= æ–°ç³»ç»Ÿå½“前状态对应的旧系统状态码,才允许同步
        // ä¾‹å¦‚:新系统已经是"出发中"(4),旧系统还是"待处理"(3),则不同步
        //      æ–°ç³»ç»Ÿæ˜¯"出发中"(4),旧系统是"已到达"(5)或"出发中"(4),则同步
        boolean shouldSync = legacyStatusCode >= currentLegacyCode;
        if (!shouldSync) {
            log.debug("状态对比:旧系统状态码({}) < æ–°ç³»ç»Ÿå½“前状态对应码({})",
                legacyStatusCode, currentLegacyCode);
        }
        return shouldSync;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskCodeGenerator.java
@@ -19,36 +19,55 @@
    private SysTaskMapper sysTaskMapper;
    
    /**
     * ç”Ÿæˆä»»åŠ¡ç¼–å·
     * æ ¼å¼ï¼šTASK + YYYYMMDD + 4位序号
     * ç”Ÿæˆä»»åŠ¡ç¼–å·ï¼ˆä½¿ç”¨é»˜è®¤å‰ç¼€ï¼‰
     * æ ¼å¼ï¼šT + YYYYMMDD + 4位序号
     * 
     * @return ä»»åŠ¡ç¼–å·
     * @deprecated å»ºè®®ä½¿ç”¨ {@link #generateTaskCode(String)} æŒ‡å®šå•据类型前缀
     */
    @Deprecated
    public String generateTaskCode() {
        return generateTaskCode("T");
    }
    /**
     * ç”Ÿæˆä»»åŠ¡ç¼–å·
     * æ ¼å¼ï¼šå•据类型前缀 + YYYYMMDD + 4位序号
     *
     * @param serviceOrdClass å•据类型(如:BF、JZ等)
     * @return ä»»åŠ¡ç¼–å·
     */
    public String generateTaskCode(String serviceOrdClass) {
        String dateStr = DateUtils.dateTimeNow("yyyyMMdd");
        return generateTaskCode(dateStr);
        return generateTaskCode(serviceOrdClass, dateStr);
    }
    
    /**
     * æ ¹æ®æ—¥æœŸç”Ÿæˆä»»åŠ¡ç¼–å·
     * 
     * @param serviceOrdClass å•据类型(如:BF、JZ等)
     * @param date æ—¥æœŸ
     * @return ä»»åŠ¡ç¼–å·
     */
    public String generateTaskCode(Date date) {
    public String generateTaskCode(String serviceOrdClass, Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dateStr = sdf.format(date);
        return generateTaskCode(dateStr);
        return generateTaskCode(serviceOrdClass, dateStr);
    }
    
    /**
     * æ ¹æ®æ—¥æœŸå­—符串生成任务编号
     * 
     * @param serviceOrdClass å•据类型(如:BF、JZ等)
     * @param dateStr æ—¥æœŸå­—符串(格式:yyyyMMdd)
     * @return ä»»åŠ¡ç¼–å·
     */
    private String generateTaskCode(String dateStr) {
        String datePrefix = "TASK" + dateStr;
    private String generateTaskCode(String serviceOrdClass, String dateStr) {
        // ç¡®ä¿å•据类型前缀不为空,默认使用"T"
        String prefix = (serviceOrdClass != null && !serviceOrdClass.trim().isEmpty())
                        ? serviceOrdClass.trim() : "T";
        String datePrefix = prefix + dateStr;
        
        // æŸ¥è¯¢å½“日最大编号
        String maxTaskCode = sysTaskMapper.selectMaxTaskCodeByDatePrefix(datePrefix);
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusConverter.java
New file
@@ -0,0 +1,147 @@
package com.ruoyi.system.utils;
import com.ruoyi.system.domain.enums.TaskStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * ä»»åŠ¡çŠ¶æ€è½¬æ¢å·¥å…·ç±»
 * ç”¨äºŽæ–°æ—§ç³»ç»Ÿä»»åŠ¡çŠ¶æ€çš„æ˜ å°„è½¬æ¢
 *
 * @author ruoyi
 * @date 2025-01-30
 */
public class TaskStatusConverter {
    private static final Logger log = LoggerFactory.getLogger(TaskStatusConverter.class);
    /**
     * å°†æ—§ç³»ç»ŸçŠ¶æ€ç è½¬æ¢ä¸ºæ–°ç³»ç»ŸTaskStatus
     *
     * æ˜ å°„规则:
     * 0,1,2,3 -> PENDING (待处理)
     * 4 -> DEPARTING (出发中)
     * 5 -> ARRIVED (已到达)
     * 6 -> IN_PROGRESS (任务中)
     * 7 -> RETURNING (返程中)
     * 8,9 -> COMPLETED (已完成)
     *
     * æ³¨æ„ï¼šçŠ¶æ€ç  > 10 çš„不进行同步(审核类、驻点等由新系统自行管理)
     *
     * @param legacyStatusCode æ—§ç³»ç»ŸçŠ¶æ€ç 
     * @return æ–°ç³»ç»ŸTaskStatus,状态码>=10或未知状态返回null
     */
    public static TaskStatus convertFromLegacyStatus(Integer legacyStatusCode) {
        if (legacyStatusCode == null) {
            log.warn("旧系统状态码为空");
            return null;
        }
        // çŠ¶æ€ç  > 10 çš„不进行同步
        if (legacyStatusCode > 10) {
            log.debug("旧系统状态码 > 10,不进行同步: {} ({})", legacyStatusCode, getLegacyStatusDescription(legacyStatusCode));
            return null;
        }
        switch (legacyStatusCode) {
            case 0:  // æ–°è°ƒåº¦å•(未下发)
            case 1:  // å®Œå…¨æœªç¡®è®¤
            case 2:  // éƒ¨åˆ†å·²ç¡®è®¤
            case 3:  // æœªå‡ºè½¦
                return TaskStatus.PENDING;
            case 4:  // å·²å‡ºè½¦ï¼ˆåŽ»æŽ¥æ‚£è€…é€”ä¸­ï¼‰
                return TaskStatus.DEPARTING;
            case 5:  // å·²å‡ºè½¦ï¼ˆç­‰å¾…患者)
                return TaskStatus.ARRIVED;
            case 6:  // å·²å‡ºè½¦ï¼ˆæœåŠ¡ä¸­ï¼‰
                return TaskStatus.IN_PROGRESS;
            case 7:  // å·²é€è¾¾ï¼ˆå›žç¨‹ä¸­ï¼‰
                return TaskStatus.RETURNING;
            case 8:  // å·²è¿”回
            case 9:  // è·‘空单,已返回
                return TaskStatus.COMPLETED;
            case 10:
                return TaskStatus.CANCELLED;
            default:
                log.warn("未知的旧系统状态码: {}", legacyStatusCode);
                return null;
        }
    }
    /**
     * å°†æ–°ç³»ç»ŸTaskStatus转换为旧系统状态码
     * æ³¨æ„ï¼šç”±äºŽå¤šå¯¹ä¸€çš„æ˜ å°„关系,这里返回的是最常用的状态码
     *
     * @param taskStatus æ–°ç³»ç»ŸTaskStatus
     * @return æ—§ç³»ç»ŸçŠ¶æ€ç ï¼ŒæœªçŸ¥çŠ¶æ€è¿”å›žnull
     */
    public static Integer convertToLegacyStatus(TaskStatus taskStatus) {
        if (taskStatus == null) {
            log.warn("新系统任务状态为空");
            return null;
        }
        switch (taskStatus) {
            case PENDING:
                return 3;  // æœªå‡ºè½¦
            case DEPARTING:
                return 4;  // å·²å‡ºè½¦ï¼ˆåŽ»æŽ¥æ‚£è€…é€”ä¸­ï¼‰
            case ARRIVED:
                return 5;  // å·²å‡ºè½¦ï¼ˆç­‰å¾…患者)
            case IN_PROGRESS:
                return 6;  // å·²å‡ºè½¦ï¼ˆæœåŠ¡ä¸­ï¼‰
            case RETURNING:
                return 7;  // å·²é€è¾¾ï¼ˆå›žç¨‹ä¸­ï¼‰
            case COMPLETED:
                return 8;  // å·²è¿”回
            case CANCELLED:
                return 10; // å–消
            default:
                log.warn("未知的新系统任务状态: {}", taskStatus);
                return null;
        }
    }
    /**
     * èŽ·å–æ—§ç³»ç»ŸçŠ¶æ€ç çš„æè¿°
     *
     * @param legacyStatusCode æ—§ç³»ç»ŸçŠ¶æ€ç 
     * @return çŠ¶æ€æè¿°
     */
    public static String getLegacyStatusDescription(Integer legacyStatusCode) {
        if (legacyStatusCode == null) {
            return "未知状态";
        }
        switch (legacyStatusCode) {
            case 0:  return "新调度单(未下发)";
            case 1:  return "完全未确认";
            case 2:  return "部分已确认";
            case 3:  return "未出车";
            case 4:  return "已出车(去接患者途中)";
            case 5:  return "已出车(等待患者)";
            case 6:  return "已出车(服务中)";
            case 7:  return "已送达(回程中)";
            case 8:  return "已返回";
            case 9:  return "跑空单,已返回";
            case 10: return "取消";
            case 11: return "已提交,等待审核";
            case 12: return "审核完成";
            case 13: return "审核不通过";
            case 14: return "已驻点";
            default: return "未知状态(" + legacyStatusCode + ")";
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusPushConverter.java
New file
@@ -0,0 +1,121 @@
package com.ruoyi.system.utils;
import com.ruoyi.system.domain.enums.TaskStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * æ–°ç³»ç»ŸçŠ¶æ€å‘æ—§ç³»ç»ŸçŠ¶æ€è½¬æ¢å·¥å…·ç±»
 *
 * @author ruoyi
 * @date 2024-01-16
 */
public class TaskStatusPushConverter {
    private static final Logger log = LoggerFactory.getLogger(TaskStatusPushConverter.class);
    /**
     * å°†æ–°ç³»ç»ŸTaskStatus转换为旧系统状态码
     *
     * @param taskStatus æ–°ç³»ç»Ÿä»»åŠ¡çŠ¶æ€æžšä¸¾
     * @return æ—§ç³»ç»ŸçŠ¶æ€ç ï¼Œå¦‚æžœä¸éœ€è¦åŒæ­¥åˆ™è¿”å›žnull
     */
    public static Integer convertToLegacyStatus(TaskStatus taskStatus) {
        if (taskStatus == null) {
            log.warn("新系统状态为空");
            return null;
        }
        switch (taskStatus) {
            case DEPARTING:      // å‡ºå‘中
                return 4;
            case IN_PROGRESS:    // ä»»åС䏭
                return 6;
            case RETURNING:      // è¿”程中
                return 7;
            case COMPLETED:      // å·²å®Œæˆ
                return 8;
            case CANCELLED:      // å·²å–消
                return 10;
            case PENDING:        // å¾…处理 - ä¸åŒæ­¥
            case ARRIVED:        // å·²åˆ°è¾¾ - ä¸åŒæ­¥
            default:
                log.debug("新系统状态不需要同步到旧系统: {}", taskStatus.getInfo());
                return null;
        }
    }
    /**
     * åˆ¤æ–­æ˜¯å¦éœ€è¦æ›´æ–°æ—§ç³»ç»ŸçŠ¶æ€
     * å¢žåŠ é˜²æ­¢çŠ¶æ€å€’é€€æœºåˆ¶ï¼šå½“æ–°ç³»ç»ŸçŠ¶æ€è½åŽäºŽæ—§ç³»ç»Ÿæ—¶ï¼Œä¸è¿›è¡ŒæŽ¨é€
     *
     * @param newStatusCode æ–°ç³»ç»Ÿè¦æŽ¨é€çš„状态码
     * @param oldStatusCode æ—§ç³»ç»Ÿå½“前状态码
     * @return æ˜¯å¦éœ€è¦æ›´æ–°
     */
    public static boolean shouldUpdateLegacyStatus(Integer newStatusCode, Integer oldStatusCode) {
        if (newStatusCode == null || oldStatusCode == null) {
            log.warn("状态码为空,跳过更新,新状态码: {}, æ—§çŠ¶æ€ç : {}", newStatusCode, oldStatusCode);
            return false;
        }
        // é˜²æ­¢çŠ¶æ€å€’é€€ï¼šæ—§ç³»ç»ŸçŠ¶æ€ >= æ–°ç³»ç»Ÿè¦æŽ¨é€çš„状态时,不更新
        // åŽŸå› ï¼šå¯èƒ½æ˜¯æ—§ç³»ç»Ÿå·²ç»å¤„ç†äº†æ›´æ–°çš„çŠ¶æ€ï¼Œè€Œæ–°ç³»ç»Ÿç”±äºŽæ—¶é—´å·®è¿˜æ²¡æœ‰åŒæ­¥åˆ°
        if (oldStatusCode >= newStatusCode) {
            log.info("旧系统状态({}) >= æ–°ç³»ç»Ÿç›®æ ‡çŠ¶æ€({}),跳过推送,防止状态倒退," +
                "旧系统: {} ({}), æ–°ç³»ç»Ÿç›®æ ‡: {} ({})",
                oldStatusCode, newStatusCode,
                oldStatusCode, getLegacyStatusDescription(oldStatusCode),
                newStatusCode, getLegacyStatusDescription(newStatusCode));
            return false;
        }
        // ç‰¹æ®ŠçŠ¶æ€æ£€æŸ¥ï¼šå·²å®Œæˆæˆ–å·²å–æ¶ˆçš„ä»»åŠ¡ä¸åº”è¯¥è¢«æ›´æ–°ä¸ºä¸­é—´çŠ¶æ€
        if (oldStatusCode >= 8) {
            // æ—§ç³»ç»Ÿå·²ç»æ˜¯å®Œæˆæ€ï¼ˆ8,9,10),不应该被任何中间状态覆盖
            if (newStatusCode < 8) {
                log.warn("旧系统已是终态({})(:{}),拒绝推送中间状态({})(:{})",
                    oldStatusCode, getLegacyStatusDescription(oldStatusCode),
                    newStatusCode, getLegacyStatusDescription(newStatusCode));
                return false;
            }
        }
        log.debug("允许推送状态,旧系统: {} ({}), æ–°ç³»ç»Ÿç›®æ ‡: {} ({})",
            oldStatusCode, getLegacyStatusDescription(oldStatusCode),
            newStatusCode, getLegacyStatusDescription(newStatusCode));
        return true;
    }
    /**
     * èŽ·å–æ—§ç³»ç»ŸçŠ¶æ€æè¿°
     *
     * @param statusCode æ—§ç³»ç»ŸçŠ¶æ€ç 
     * @return çŠ¶æ€æè¿°
     */
    public static String getLegacyStatusDescription(Integer statusCode) {
        if (statusCode == null) {
            return "未知";
        }
        switch (statusCode) {
            case 0: return "新调度单(未下发)";
            case 1: return "完全未确认";
            case 2: return "部分已确认";
            case 3: return "未出车";
            case 4: return "已出车(去接患者途中)";
            case 5: return "已出车(等待患者)";
            case 6: return "已出车(服务中)";
            case 7: return "已送达(回程中)";
            case 8: return "已返回";
            case 9: return "跑空单,已返回";
            case 10: return "取消";
            case 11: return "审核中";
            case 12: return "审核通过";
            case 13: return "审核不通过";
            case 14: return "驻点";
            default: return "未知状态(" + statusCode + ")";
        }
    }
}
ruoyi-system/src/main/resources/mapper/system/DispatchOrdMapper.xml
@@ -83,5 +83,29 @@
        and ImageType in (1,2)
        order by UpImageTime desc
    </select>
    <!-- æ ¹æ®è°ƒåº¦å•ID查询调度单状态 -->
    <select id="selectDispatchOrdStateByID" parameterType="Long" resultType="Integer">
        select DispatchOrdState
        from DispatchOrd
        where DispatchOrdID = #{dispatchOrdID}
    </select>
    <!-- æ‰¹é‡æŸ¥è¯¢è°ƒåº¦å•状态 -->
    <select id="selectDispatchOrdStatesByIDs" parameterType="java.util.List" resultMap="DispatchOrdResult">
        select DispatchOrdID, DispatchOrdState
        from DispatchOrd
        where DispatchOrdID in
        <foreach collection="list" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>
    <!-- æ›´æ–°è°ƒåº¦å•状态 -->
    <update id="updateDispatchOrdState">
        update DispatchOrd
        set DispatchOrdState = #{dispatchOrdState}
        where DispatchOrdID = #{dispatchOrdID}
    </update>
</mapper> 
ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
@@ -223,8 +223,21 @@
    <select id="selectPendingSyncTasks" resultMap="SysTaskEmergencyResult">
        <include refid="selectSysTaskEmergencyVo"/>
        where (sync_status = 0 or sync_status = 3)
          and task_id in (
              select task_id from sys_task
              where task_type = 'EMERGENCY_TRANSFER'
                and del_flag = '0'
          )
        order by id asc
        limit 100
        <if test="offset != null and limit != null">
            limit #{offset}, #{limit}
        </if>
        <if test="offset == null and limit != null">
            limit #{limit}
        </if>
        <if test="offset == null and limit == null">
            limit 100
        </if>
    </select>
    
    <!-- æŸ¥è¯¢å¾…同步调度单的任务(已同步服务单但未同步调度单) -->
@@ -233,8 +246,44 @@
        where sync_status = 2 
          and legacy_service_ord_id is not null 
          and (dispatch_sync_status = 0 or dispatch_sync_status = 3 or dispatch_sync_status is null)
          and task_id in (
              select task_id from sys_task
              where task_type = 'EMERGENCY_TRANSFER'
                and task_status not in ('COMPLETED', 'CANCELLED')  <!-- è¿‡æ»¤å·²å®Œæˆ/已取消的任务 -->
                and del_flag = '0'
          )
        order by id asc
        limit 100
        <if test="offset != null and limit != null">
            limit #{offset}, #{limit}
        </if>
        <if test="offset == null and limit != null">
            limit #{limit}
        </if>
        <if test="offset == null and limit == null">
            limit 100
        </if>
    </select>
    <!-- æŸ¥è¯¢å·²åŒæ­¥è°ƒåº¦å•且状态未完成的任务(用于状态同步) -->
    <select id="selectSyncedTasksForStatusUpdate" resultMap="SysTaskEmergencyResult">
        <include refid="selectSysTaskEmergencyVo"/>
        where dispatch_sync_status = 2
          and legacy_dispatch_ord_id is not null
          and task_id in (
              select task_id from sys_task
              where task_type = 'EMERGENCY_TRANSFER'
                and del_flag = '0'
          )
        order by id asc
        <if test="offset != null and limit != null">
            limit #{offset}, #{limit}
        </if>
        <if test="offset == null and limit != null">
            limit #{limit}
        </if>
        <if test="offset == null and limit == null">
            limit 200
        </if>
    </select>
</mapper>
ruoyi-ui/src/views/task/general/index.vue
@@ -112,24 +112,7 @@
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="同步状态" align="center" prop="syncStatus" width="120" v-if="hasEmergencyTask">
        <template slot-scope="scope">
          <span v-if="scope.row.taskType !== 'EMERGENCY_TRANSFER'" style="color: #C0C4CC;">--</span>
          <el-tag v-else-if="!scope.row.emergencyInfo" type="info" size="mini">--</el-tag>
          <el-tag v-else-if="scope.row.emergencyInfo.syncStatus === 0" type="info" size="mini">
            <i class="el-icon-warning"></i> æœªåŒæ­¥
          </el-tag>
          <el-tag v-else-if="scope.row.emergencyInfo.syncStatus === 1" type="warning" size="mini">
            <i class="el-icon-loading"></i> åŒæ­¥ä¸­
          </el-tag>
          <el-tag v-else-if="scope.row.emergencyInfo.syncStatus === 2" type="success" size="mini">
            <i class="el-icon-success"></i> å·²åŒæ­¥
          </el-tag>
          <el-tag v-else-if="scope.row.emergencyInfo.syncStatus === 3" type="danger" size="mini">
            <i class="el-icon-error"></i> åŒæ­¥å¤±è´¥
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="任务状态" align="center" prop="taskStatus">
        <template slot-scope="scope">
          <dict-tag :options="dict.type.sys_task_status" :value="scope.row.taskStatus"/>
sql/legacy_status_sync_job.sql
New file
@@ -0,0 +1,133 @@
-- ==========================================
-- æ—§ç³»ç»Ÿä»»åŠ¡çŠ¶æ€åŒæ­¥å®šæ—¶ä»»åŠ¡é…ç½®è„šæœ¬
-- ==========================================
--
-- åŠŸèƒ½è¯´æ˜Ž:
-- ä»Žæ—§ç³»ç»ŸåŒæ­¥ä»»åŠ¡çŠ¶æ€åˆ°æ–°ç³»ç»Ÿï¼Œå®žçŽ°çŠ¶æ€çš„å®žæ—¶æ›´æ–°
--
-- ä½¿ç”¨åœºæ™¯:
-- 1. æ—§ç³»ç»Ÿæ“ä½œäººå‘˜æ›´æ–°äº†è°ƒåº¦å•状态
-- 2. æ–°ç³»ç»Ÿéœ€è¦åæ˜ æ—§ç³»ç»Ÿçš„状态变更
-- 3. ä¿æŒæ–°æ—§ç³»ç»ŸçŠ¶æ€çš„ä¸€è‡´æ€§
--
-- åŒæ­¥æ¡ä»¶:
-- 1. è°ƒåº¦å•已同步成功(dispatch_sync_status = 2)
-- 2. æœ‰DispatchOrdID(legacy_dispatch_ord_id IS NOT NULL)
-- 3. ä»»åŠ¡çŠ¶æ€æœªå®Œæˆï¼ˆtask_status NOT IN ('COMPLETED', 'CANCELLED'))
--
-- æ‰§è¡Œé¢‘率建议:
-- - ç”Ÿäº§çŽ¯å¢ƒ: æ¯5分钟执行一次 (0 0/5 * * * ?)
-- - æµ‹è¯•环境: æ¯2分钟执行一次 (0 0/2 * * * ?)
--
-- æ³¨æ„äº‹é¡¹:
-- 1. ä¾èµ–调度单同步完成
-- 2. ä»…同步未完成状态的任务
-- 3. çŠ¶æ€æ˜ å°„è§„åˆ™è§TaskStatusConverterç±»
-- ==========================================
-- æ’入定时任务配置
INSERT INTO `sys_job` (
    `job_name`,
    `job_group`,
    `invoke_target`,
    `cron_expression`,
    `misfire_policy`,
    `concurrent`,
    `status`,
    `create_by`,
    `create_time`,
    `update_by`,
    `update_time`,
    `remark`
) VALUES (
    '任务状态同步',
    'DEFAULT',
    'legacySystemSyncTask.syncTaskStatusFromLegacy()',
    '0 0/5 * * * ?',
    '2',
    '1',
    '0',
    'admin',
    NOW(),
    'admin',
    NOW(),
    '从旧系统同步任务状态到新系统,每5分钟执行一次。同步已同步调度单且状态未完成的任务。'
);
-- ==========================================
-- éªŒè¯æŸ¥è¯¢
-- ==========================================
-- 1. æŸ¥çœ‹å®šæ—¶ä»»åŠ¡æ˜¯å¦æ·»åŠ æˆåŠŸ
SELECT
    job_id,
    job_name,
    job_group,
    invoke_target,
    cron_expression,
    CASE status
        WHEN '0' THEN '正常'
        WHEN '1' THEN '暂停'
    END AS job_status,
    remark
FROM sys_job
WHERE job_name = '任务状态同步';
-- 2. æŸ¥çœ‹éœ€è¦åŒæ­¥çŠ¶æ€çš„ä»»åŠ¡æ•°é‡
SELECT
    COUNT(*) AS total_tasks,
    SUM(CASE WHEN t.task_status = 'PENDING' THEN 1 ELSE 0 END) AS pending,
    SUM(CASE WHEN t.task_status = 'DEPARTING' THEN 1 ELSE 0 END) AS departing,
    SUM(CASE WHEN t.task_status = 'ARRIVED' THEN 1 ELSE 0 END) AS arrived,
    SUM(CASE WHEN t.task_status = 'IN_PROGRESS' THEN 1 ELSE 0 END) AS in_progress,
    SUM(CASE WHEN t.task_status = 'RETURNING' THEN 1 ELSE 0 END) AS returning
FROM sys_task_emergency e
INNER JOIN sys_task t ON e.task_id = t.task_id
WHERE e.dispatch_sync_status = 2
  AND e.legacy_dispatch_ord_id IS NOT NULL
  AND t.task_status NOT IN ('COMPLETED', 'CANCELLED')
  AND t.del_flag = '0';
-- 3. æŸ¥çœ‹ä»»åŠ¡çŠ¶æ€åˆ†å¸ƒè¯¦æƒ…
SELECT
    t.task_id,
    t.task_code,
    t.task_status,
    e.legacy_service_ord_id,
    e.legacy_dispatch_ord_id,
    t.create_time,
    t.update_time
FROM sys_task_emergency e
INNER JOIN sys_task t ON e.task_id = t.task_id
WHERE e.dispatch_sync_status = 2
  AND e.legacy_dispatch_ord_id IS NOT NULL
  AND t.task_status NOT IN ('COMPLETED', 'CANCELLED')
  AND t.del_flag = '0'
ORDER BY t.update_time DESC
LIMIT 10;
-- ==========================================
-- çŠ¶æ€æ˜ å°„è§„åˆ™å‚è€ƒ
-- ==========================================
/*
旧系统状态码 -> æ–°ç³»ç»ŸçŠ¶æ€:
0,1,2,3,11,12 -> PENDING (待处理)
4 -> DEPARTING (出发中)
5,14 -> ARRIVED (已到达)
6 -> IN_PROGRESS (任务中)
7 -> RETURNING (返程中)
8,9 -> COMPLETED (已完成)
10,13 -> CANCELLED (已取消)
详细说明见: com.ruoyi.system.utils.TaskStatusConverter
*/
-- ==========================================
-- æ‰‹åŠ¨è§¦å‘æµ‹è¯•
-- ==========================================
/*
-- åœ¨å®šæ—¶ä»»åŠ¡ç®¡ç†é¡µé¢æ‰‹åŠ¨æ‰§è¡Œä¸€æ¬¡ä»»åŠ¡ï¼Œæˆ–è€…åœ¨ä»£ç ä¸­è°ƒç”¨:
-- legacySystemSyncTask.syncTaskStatusFromLegacy()
-- æŸ¥çœ‹åŒæ­¥æ—¥å¿—(需要查看应用日志文件)
*/
sql/task_status_push_job.sql
New file
@@ -0,0 +1,7 @@
-- ----------------------------
-- ä»»åŠ¡çŠ¶æ€æŽ¨é€å®šæ—¶ä»»åŠ¡é…ç½®ï¼ˆä»Žæ–°ç³»ç»ŸæŽ¨é€åˆ°æ—§ç³»ç»Ÿï¼‰
-- ----------------------------
INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, update_by, update_time, remark)
VALUES
('任务状态推送', 'DEFAULT', 'legacySystemSyncTask.pushTaskStatusToLegacy()', '0 0/3 * * * ?', '3', '1', '1', 'admin', sysdate(), 'admin', sysdate(),
'每3分钟执行一次,将新系统中状态已变化的任务推送到旧系统。推送规则:出发中->4,任务中->6,返程中->7,已完成->8,已取消->10。旧系统状态>=目标状态时不推送。');
sql/update_task_status_dict.sql
New file
@@ -0,0 +1,72 @@
-- ===================================================================
-- æ›´æ–°ä»»åŠ¡çŠ¶æ€å­—å…¸è¡¨
--
-- è¯´æ˜Žï¼šæ·»åŠ è½¬è¿ä»»åŠ¡çš„å®Œæ•´çŠ¶æ€æµç¨‹
-- PENDING -> DEPARTING -> ARRIVED -> RETURNING -> COMPLETED/CANCELLED
-- ===================================================================
-- 1. å…ˆåˆ é™¤æ—§çš„任务状态字典数据
DELETE FROM sys_dict_data WHERE dict_type = 'sys_task_status';
-- 2. é‡æ–°æ’入完整的任务状态字典数据
-- ----------------------------
-- ä»»åŠ¡çŠ¶æ€å­—å…¸æ•°æ®ï¼ˆæŒ‰çŠ¶æ€æµç¨‹æŽ’åºï¼‰
-- ----------------------------
-- å¾…处理(初始状态)
INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark)
VALUES(1, '待处理', 'PENDING', 'sys_task_status', '', 'warning', 'N', '0', 'admin', SYSDATE(), '', NULL, '任务已创建,等待出发');
-- å‡ºå‘中
INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark)
VALUES(2, '出发中', 'DEPARTING', 'sys_task_status', '', 'primary', 'N', '0', 'admin', SYSDATE(), '', NULL, '任务已出发,前往目的地');
-- å·²åˆ°è¾¾
INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark)
VALUES(3, '已到达', 'ARRIVED', 'sys_task_status', '', 'primary', 'N', '0', 'admin', SYSDATE(), '', NULL, '已到达目的地');
-- è¿”程中
INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark)
VALUES(4, '返程中', 'RETURNING', 'sys_task_status', '', 'primary', 'N', '0', 'admin', SYSDATE(), '', NULL, '任务返程中');
-- å·²å®Œæˆï¼ˆç»“束状态)
INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark)
VALUES(5, '已完成', 'COMPLETED', 'sys_task_status', '', 'success', 'N', '0', 'admin', SYSDATE(), '', NULL, '任务已完成');
-- å·²å–消(结束状态)
INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark)
VALUES(6, '已取消', 'CANCELLED', 'sys_task_status', '', 'danger', 'N', '0', 'admin', SYSDATE(), '', NULL, '任务已取消');
-- ä»»åŠ¡ä¸­ï¼ˆå…¼å®¹æ—§æ•°æ®ï¼‰
INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark)
VALUES(7, '任务中', 'IN_PROGRESS', 'sys_task_status', '', 'primary', 'N', '0', 'admin', SYSDATE(), '', NULL, '任务执行中(兼容旧数据)');
-- ===================================================================
-- éªŒè¯æŸ¥è¯¢
-- ===================================================================
-- æŸ¥çœ‹æ›´æ–°åŽçš„任务状态字典数据
SELECT
    dict_sort AS '排序',
    dict_label AS '状态名称',
    dict_value AS '状态值',
    list_class AS '样式',
    remark AS '说明'
FROM sys_dict_data
WHERE dict_type = 'sys_task_status'
ORDER BY dict_sort;
-- ===================================================================
-- ä»»åŠ¡çŠ¶æ€æµç¨‹è¯´æ˜Ž
-- ===================================================================
--
-- æ­£å¸¸æµç¨‹ï¼š
-- PENDING(待处理)-> DEPARTING(出发中)-> ARRIVED(已到达)-> RETURNING(返程中)-> COMPLETED(已完成)
--
-- å–消流程:
-- ä»»ä½•状态(COMPLETED除外)-> CANCELLED(已取消)
--
-- å…¼å®¹æ—§æ•°æ®ï¼š
-- IN_PROGRESS(任务中)可以转换为 COMPLETED、CANCELLED æˆ– PENDING
--
-- ===================================================================