From 77b8624957ea9afafc81af72e52212c15b5f091e Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期四, 25 十二月 2025 01:34:32 +0800
Subject: [PATCH] feat: 优化新建 保存同步

---
 ruoyi-system/src/main/java/com/ruoyi/system/domain/ServiceOrderEntity.java                  |  319 ++++++++++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java                     |   22 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncUtilService.java   |   24 
 ruoyi-system/src/main/resources/mapper/system/ServiceOrderMapper.xml                        |   27 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysWelfareTaskServiceImpl.java     |    8 
 ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml                    |   13 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java                        |   15 
 ruoyi-system/src/main/java/com/ruoyi/system/service/IServiceOrderService.java               |   23 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java |    2 
 sql/insert_dict_task_cancel_reason.sql                                                      |   42 +
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ServiceOrderServiceImpl.java       |   31 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java                    |   33 +
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java                    |   17 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/ServiceOrderMapper.java                  |   30 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusPushServiceImpl.java     |   63 +
 app/pages/task/create.vue                                                                   |   18 
 app/pages/index.vue                                                                         |  173 +++++
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java              |   16 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysEmergencyTaskServiceImpl.java   |   10 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusSyncServiceImpl.java     |  101 +-
 app/main.js                                                                                 |    1 
 app/pages/task/index.vue                                                                    |  201 +++++
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java            |  115 ++
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskEmergencySyncServiceImpl.java  |    2 
 取消原因功能实现说明.md                                                                               |  309 +++++++++
 app/pagesTask/detail.vue                                                                    |  195 ++++++
 sql/add_cancel_reason_fields.sql                                                            |   24 
 27 files changed, 1,679 insertions(+), 155 deletions(-)

diff --git a/app/main.js b/app/main.js
index 3985b1b..694c5e6 100644
--- a/app/main.js
+++ b/app/main.js
@@ -11,6 +11,7 @@
 App.mpType = 'app'
 
 const app = new Vue({
+  store,
   ...App
 })
 
diff --git a/app/pages/index.vue b/app/pages/index.vue
index 7f37adb..7b2aeb4 100644
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -232,6 +232,26 @@
         </view>
       </view>
     </scroll-view>
+    
+    <!-- 鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗� -->
+    <uni-popup ref="cancelPopup" type="center" :is-mask-click="false">
+      <view class="cancel-dialog">
+        <view class="dialog-title">璇烽�夋嫨鍙栨秷鍘熷洜</view>
+        <picker mode="selector" :range="cancelReasonList" range-key="label" @change="selectCancelReason">
+          <view class="reason-picker">
+            <view class="picker-label">鍙栨秷鍘熷洜</view>
+            <view class="picker-value">
+              {{ selectedCancelReasonLabel }}
+            </view>
+            <uni-icons type="arrowright" size="16"></uni-icons>
+          </view>
+        </picker>
+        <view class="dialog-buttons">
+          <button class="cancel-btn" @click="closeCancelDialog">鍙栨秷</button>
+          <button class="confirm-btn" @click="confirmCancelTask">纭畾</button>
+        </view>
+      </view>
+    </uni-popup>
   </view>
 </template>
 
@@ -241,6 +261,7 @@
 import { getUserProfile } from "@/api/system/user";
 import { getUserBoundVehicle } from "@/api/vehicle";
 import { getUnreadCount } from "@/api/message";
+import { getDicts } from "@/api/dict";
 import { formatDateTime } from "@/utils/common";
 import subscribeManager from "@/utils/subscribe";
 import { checkTaskCanDepart } from "@/utils/taskValidator";
@@ -268,6 +289,12 @@
       currentPage: 1,
       pageSize: 10,
       hasMore: true,
+      
+      // 鍙栨秷鍘熷洜鐩稿叧
+      cancelReasonList: [], // 鍙栨秷鍘熷洜鍒楄〃
+      showCancelDialog: false, // 鏄剧ず鍙栨秷鍘熷洜瀵硅瘽妗�
+      selectedCancelReason: '', // 閫変腑鐨勫彇娑堝師鍥�
+      currentCancelTask: null // 褰撳墠瑕佸彇娑堢殑浠诲姟
     };
   },
   computed: {
@@ -288,6 +315,15 @@
           "IN_PROGRESS",
         ].includes(task.taskStatus);
       });
+    },
+    
+    // 鑾峰彇閫変腑鐨勫彇娑堝師鍥犳爣绛撅紙鐢ㄤ簬寮圭獥鏄剧ず锛�
+    selectedCancelReasonLabel() {
+      if (!this.selectedCancelReason || !this.cancelReasonList.length) {
+        return '璇烽�夋嫨'
+      }
+      const reason = this.cancelReasonList.find(r => r.value === this.selectedCancelReason)
+      return reason ? reason.label : '璇烽�夋嫨'
     },
   },
   onLoad() {
@@ -310,6 +346,8 @@
     this.loadRunningTasks();
     // 鍔犺浇鏈娑堟伅鏁伴噺
     this.loadUnreadMessageCount();
+    // 鍔犺浇鍙栨秷鍘熷洜瀛楀吀
+    this.loadCancelReasonDict();
   },
   onShow() {
     // 妫�鏌ョ敤鎴锋槸鍚﹀凡鐧诲綍
@@ -707,13 +745,9 @@
           break;
 
         case "cancel":
-          // 鍙栨秷 -> 浜屾纭鍚庣姸鎬佸彉涓哄凡鍙栨秷
-          this.$modal
-            .confirm("纭畾瑕佸彇娑堟浠诲姟鍚楋紵")
-            .then(() => {
-              this.updateTaskStatus(task.taskId, "CANCELLED", "浠诲姟宸插彇娑�");
-            })
-            .catch(() => {});
+          // 鍙栨秷 -> 鏄剧ず鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗�
+          this.currentCancelTask = task;
+          this.showCancelReasonDialog();
           break;
 
         case "arrive":
@@ -760,6 +794,56 @@
       this.getLocationAndUpdateStatus(taskId, status, remark);
     },
     
+    // 鍔犺浇鍙栨秷鍘熷洜瀛楀吀
+    loadCancelReasonDict() {
+      getDicts('task_cancel_reason').then(response => {
+        if (response.code === 200 && response.data) {
+          this.cancelReasonList = response.data.map(item => ({
+            value: item.dictValue,
+            label: item.dictLabel
+          }))
+        }
+      }).catch(error => {
+        console.error('鍔犺浇鍙栨秷鍘熷洜瀛楀吀澶辫触:', error)
+      })
+    },
+    
+    // 鏄剧ず鍙栨秷鍘熷洜瀵硅瘽妗�
+    showCancelReasonDialog() {
+      this.selectedCancelReason = ''
+      this.$refs.cancelPopup.open()
+    },
+    
+    // 纭鍙栨秷浠诲姟
+    confirmCancelTask() {
+      if (!this.selectedCancelReason) {
+        this.$modal.showToast('璇烽�夋嫨鍙栨秷鍘熷洜')
+        return
+      }
+      
+      this.$refs.cancelPopup.close()
+      
+      // 璋冪敤鏇存柊鐘舵�佹柟娉曪紝浼犻�掑彇娑堝師鍥�
+      this.updateTaskStatusWithCancelReason(this.currentCancelTask.taskId, 'CANCELLED', '浠诲姟宸插彇娑�', this.selectedCancelReason)
+    },
+    
+    // 鍙栨秷瀵硅瘽妗嗗叧闂�
+    closeCancelDialog() {
+      this.$refs.cancelPopup.close()
+      this.selectedCancelReason = ''
+      this.currentCancelTask = null
+    },
+    
+    // 閫夋嫨鍙栨秷鍘熷洜
+    selectCancelReason(e) {
+      this.selectedCancelReason = this.cancelReasonList[e.detail.value].value
+    },
+    
+    // 甯﹀彇娑堝師鍥犵殑鐘舵�佹洿鏂�
+    updateTaskStatusWithCancelReason(taskId, status, remark, cancelReason) {
+      this.getLocationAndUpdateStatus(taskId, status, remark, cancelReason)
+    },
+    
     // 妫�鏌ョ煡鎯呭悓鎰忎功闄勪欢骞舵洿鏂扮姸鎬�
     async checkConsentAttachmentAndThen(taskId, status, remark) {
       try {
@@ -798,7 +882,7 @@
     },
 
     // 鑾峰彇浣嶇疆淇℃伅骞舵洿鏂扮姸鎬�
-    getLocationAndUpdateStatus(taskId, status, remark) {
+    getLocationAndUpdateStatus(taskId, status, remark, cancelReason) {
       const that = this;
 
       // 浣跨敤uni.getLocation鑾峰彇GPS浣嶇疆
@@ -825,6 +909,11 @@
             speed: res.speed,
             heading: res.direction || res.heading,
           };
+          
+          // 濡傛灉鏈夊彇娑堝師鍥狅紝娣诲姞鍒拌姹傛暟鎹腑
+          if (cancelReason) {
+            statusData.cancelReason = cancelReason
+          }
 
           changeTaskStatus(taskId, statusData)
             .then((response) => {
@@ -846,6 +935,11 @@
                 taskStatus: status,
                 remark: remark,
               };
+              
+              // 濡傛灉鏈夊彇娑堝師鍥狅紝娣诲姞鍒拌姹傛暟鎹腑
+              if (cancelReason) {
+                statusData.cancelReason = cancelReason
+              }
 
               changeTaskStatus(taskId, statusData)
                 .then((response) => {
@@ -1383,4 +1477,67 @@
     }
   }
 }
+
+// 鍙栨秷鍘熷洜瀵硅瘽妗嗘牱寮�
+.cancel-dialog {
+  width: 600rpx;
+  background-color: white;
+  border-radius: 20rpx;
+  padding: 40rpx;
+  
+  .dialog-title {
+    font-size: 32rpx;
+    font-weight: bold;
+    text-align: center;
+    margin-bottom: 30rpx;
+    color: #333;
+  }
+  
+  .reason-picker {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 20rpx 30rpx;
+    background-color: #f5f5f5;
+    border-radius: 10rpx;
+    margin-bottom: 30rpx;
+    
+    .picker-label {
+      font-size: 28rpx;
+      color: #666;
+    }
+    
+    .picker-value {
+      flex: 1;
+      text-align: right;
+      margin: 0 20rpx;
+      font-size: 28rpx;
+      color: #333;
+    }
+  }
+  
+  .dialog-buttons {
+    display: flex;
+    gap: 20rpx;
+    
+    button {
+      flex: 1;
+      height: 80rpx;
+      line-height: 80rpx;
+      border-radius: 10rpx;
+      font-size: 28rpx;
+      border: none;
+    }
+    
+    .cancel-btn {
+      background-color: #f5f5f5;
+      color: #666;
+    }
+    
+    .confirm-btn {
+      background-color: #007AFF;
+      color: white;
+    }
+  }
+}
 </style>
\ No newline at end of file
diff --git a/app/pages/task/create.vue b/app/pages/task/create.vue
index 23fa2dd..748bc8e 100644
--- a/app/pages/task/create.vue
+++ b/app/pages/task/create.vue
@@ -58,15 +58,15 @@
           page: '/pagesTask/create-normal'
         },
 
-        {
-          type: 'welfare',
-          name: '绂忕杞�',
-          icon: 'car',
-          color: '#F37B1D',
-          description: '鑰佸勾浜恒�佹畫鐤句汉绛夌壒娈婄兢浣撶敤杞︽湇鍔�',
-          taskType: 'WELFARE',
-          page: '/pagesTask/create-welfare'
-        }
+        // {
+        //   type: 'welfare',
+        //   name: '绂忕杞�',
+        //   icon: 'car',
+        //   color: '#F37B1D',
+        //   description: '鑰佸勾浜恒�佹畫鐤句汉绛夌壒娈婄兢浣撶敤杞︽湇鍔�',
+        //   taskType: 'WELFARE',
+        //   page: '/pagesTask/create-welfare'
+        // }
       ]
     }
   },
diff --git a/app/pages/task/index.vue b/app/pages/task/index.vue
index a0432b3..3b0a399 100644
--- a/app/pages/task/index.vue
+++ b/app/pages/task/index.vue
@@ -5,12 +5,12 @@
       <view class="task-header">
         <view class="header-title">浠诲姟鍒楄〃</view>
         <view class="header-actions">
-          <button class="search-toggle-btn" @click="toggleSearch">
+          <!-- <button class="search-toggle-btn" @click="toggleSearch">
             <uni-icons
               :type="showSearch ? 'close' : 'search'"
               size="20"
             ></uni-icons>
-          </button>
+          </button> -->
           <button class="refresh-btn" @click="refreshList">
             <uni-icons type="refresh" size="20"></uni-icons>
           </button>
@@ -270,12 +270,33 @@
         </view>
       </scroll-view>
     </view>
+    
+    <!-- 鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗� -->
+    <uni-popup ref="cancelPopup" type="center" :is-mask-click="false">
+      <view class="cancel-dialog">
+        <view class="dialog-title">璇烽�夋嫨鍙栨秷鍘熷洜</view>
+        <picker mode="selector" :range="cancelReasonList" range-key="label" @change="selectCancelReason">
+          <view class="reason-picker">
+            <view class="picker-label">鍙栨秷鍘熷洜</view>
+            <view class="picker-value">
+              {{ selectedCancelReasonLabel }}
+            </view>
+            <uni-icons type="arrowright" size="16"></uni-icons>
+          </view>
+        </picker>
+        <view class="dialog-buttons">
+          <button class="cancel-btn" @click="closeCancelDialog">鍙栨秷</button>
+          <button class="confirm-btn" @click="confirmCancelTask">纭畾</button>
+        </view>
+      </view>
+    </uni-popup>
   </view>
 </template>
 
 <script>
 import uniDatetimePicker from "@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue";
 import { listTask, changeTaskStatus, checkTaskConsentAttachment } from "@/api/task";
+import { getDicts } from "@/api/dict";
 import { mapState } from "vuex";
 import { formatDateTime } from "@/utils/common";
 import { checkTaskCanDepart } from "@/utils/taskValidator";
@@ -294,8 +315,8 @@
         vehicle: "",
         taskNo: "",
       },
-      statusOptions: ["鍏ㄩ儴鐘舵��", "寰呭鐞�", "澶勭悊涓�", "宸插畬鎴�"],
-      statusValues: ["", "pending", "processing", "completed"],
+      statusOptions: ["鍏ㄩ儴鐘舵��", "寰呭鐞�", "澶勭悊涓�", "宸插畬鎴�", "宸插彇娑�"],
+      statusValues: ["", "pending", "processing", "completed", "cancelled"],
       selectedStatus: "",
       selectedStatusText: "",
       startDate: "",
@@ -312,6 +333,12 @@
       pageSize: 10,
       total: 0,
       hasMore: true,
+      
+      // 鍙栨秷鍘熷洜鐩稿叧
+      cancelReasonList: [], // 鍙栨秷鍘熷洜鍒楄〃
+      showCancelDialog: false, // 鏄剧ず鍙栨秷鍘熷洜瀵硅瘽妗�
+      selectedCancelReason: '', // 閫変腑鐨勫彇娑堝師鍥�
+      currentCancelTask: null // 褰撳墠瑕佸彇娑堢殑浠诲姟
     };
   },
   computed: {
@@ -323,12 +350,24 @@
       // 瀹為檯鐨勭瓫閫夊皢鍦ㄨ姹傛湇鍔″櫒鏃跺畬鎴�
       return this.taskList;
     },
+    
+    // 鑾峰彇閫変腑鐨勫彇娑堝師鍥犳爣绛撅紙鐢ㄤ簬寮圭獥鏄剧ず锛�
+    selectedCancelReasonLabel() {
+      if (!this.selectedCancelReason || !this.cancelReasonList.length) {
+        return '璇烽�夋嫨'
+      }
+      const reason = this.cancelReasonList.find(r => r.value === this.selectedCancelReason)
+      return reason ? reason.label : '璇烽�夋嫨'
+    },
   },
   onLoad() {
     this.loadTaskList();
 
     // 鐩戝惉浠诲姟鍒楄〃鍒锋柊浜嬩欢
     uni.$on("refreshTaskList", this.handleRefreshEvent);
+    
+    // 鍔犺浇鍙栨秷鍘熷洜瀛楀吀
+    this.loadCancelReasonDict();
   },
   onShow() {
     // 椤甸潰鏄剧ず鏃跺埛鏂板垪琛紙浠庡叾浠栭〉闈㈣繑鍥炴椂锛�
@@ -382,7 +421,8 @@
           "IN_PROGRESS",
         ].join(",");
       } else if (this.currentFilter === "completed") {
-        queryParams.taskStatus = "COMPLETED";
+        // 宸插畬鎴愬寘鍚細宸插畬鎴愬拰宸插彇娑�
+        queryParams.taskStatusList = "COMPLETED,CANCELLED";
       } else {
         // 濡傛灉娌℃湁浣跨敤椤堕儴tab绛涢�夛紝鍒欎娇鐢ㄦ煡璇㈡潯浠朵腑鐨勭姸鎬佺瓫閫�
         if (this.selectedStatus) {
@@ -395,11 +435,13 @@
               "IN_PROGRESS",
             ].join(","),
             completed: "COMPLETED",
+            cancelled: "CANCELLED",
           };
           if (statusMap[this.selectedStatus]) {
             if (
               this.selectedStatus === "pending" ||
-              this.selectedStatus === "completed"
+              this.selectedStatus === "completed" ||
+              this.selectedStatus === "cancelled"
             ) {
               queryParams.taskStatus = statusMap[this.selectedStatus];
             } else {
@@ -497,7 +539,8 @@
           "IN_PROGRESS",
         ].join(",");
       } else if (this.currentFilter === "completed") {
-        queryParams.taskStatus = "COMPLETED";
+        // 宸插畬鎴愬寘鍚細宸插畬鎴愬拰宸插彇娑�
+        queryParams.taskStatusList = "COMPLETED,CANCELLED";
       } else {
         // 濡傛灉娌℃湁浣跨敤椤堕儴tab绛涢�夛紝鍒欎娇鐢ㄦ煡璇㈡潯浠朵腑鐨勭姸鎬佺瓫閫�
         if (this.selectedStatus) {
@@ -510,11 +553,13 @@
               "IN_PROGRESS",
             ].join(","),
             completed: "COMPLETED",
+            cancelled: "CANCELLED",
           };
           if (statusMap[this.selectedStatus]) {
             if (
               this.selectedStatus === "pending" ||
-              this.selectedStatus === "completed"
+              this.selectedStatus === "completed" ||
+              this.selectedStatus === "cancelled"
             ) {
               queryParams.taskStatus = statusMap[this.selectedStatus];
             } else {
@@ -654,6 +699,8 @@
       this.endDate = "";
       this.searchForm.vehicle = "";
       this.searchForm.taskNo = "";
+      // 閲嶇疆鍚庨噸鏂板姞杞芥暟鎹�
+      this.loadTaskList();
     },
 
     // 鍒锋柊鍒楄〃
@@ -671,6 +718,9 @@
     // 绛涢��
     changeFilter(filter) {
       this.currentFilter = filter;
+      // 閲嶇疆鍒嗛〉
+      this.currentPage = 1;
+      this.hasMore = true;
       // 閲嶆柊鍔犺浇鏁版嵁
       this.loadTaskList();
     },
@@ -784,13 +834,9 @@
           break;
 
         case "cancel":
-          // 鍙栨秷 -> 浜屾纭鍚庣姸鎬佸彉涓哄凡鍙栨秷
-          this.$modal
-            .confirm("纭畾瑕佸彇娑堟浠诲姟鍚楋紵")
-            .then(() => {
-              this.updateTaskStatus(task.taskId, "CANCELLED", "浠诲姟宸插彇娑�");
-            })
-            .catch(() => {});
+          // 鍙栨秷 -> 鏄剧ず鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗�
+          this.currentCancelTask = task;
+          this.showCancelReasonDialog();
           break;
 
         case "arrive":
@@ -837,6 +883,56 @@
       this.getLocationAndUpdateStatus(taskId, status, remark);
     },
     
+    // 鍔犺浇鍙栨秷鍘熷洜瀛楀吀
+    loadCancelReasonDict() {
+      getDicts('task_cancel_reason').then(response => {
+        if (response.code === 200 && response.data) {
+          this.cancelReasonList = response.data.map(item => ({
+            value: item.dictValue,
+            label: item.dictLabel
+          }))
+        }
+      }).catch(error => {
+        console.error('鍔犺浇鍙栨秷鍘熷洜瀛楀吀澶辫触:', error)
+      })
+    },
+    
+    // 鏄剧ず鍙栨秷鍘熷洜瀵硅瘽妗�
+    showCancelReasonDialog() {
+      this.selectedCancelReason = ''
+      this.$refs.cancelPopup.open()
+    },
+    
+    // 纭鍙栨秷浠诲姟
+    confirmCancelTask() {
+      if (!this.selectedCancelReason) {
+        this.$modal.showToast('璇烽�夋嫨鍙栨秷鍘熷洜')
+        return
+      }
+      
+      this.$refs.cancelPopup.close()
+      
+      // 璋冪敤鏇存柊鐘舵�佹柟娉曪紝浼犻�掑彇娑堝師鍥�
+      this.updateTaskStatusWithCancelReason(this.currentCancelTask.taskId, 'CANCELLED', '浠诲姟宸插彇娑�', this.selectedCancelReason)
+    },
+    
+    // 鍙栨秷瀵硅瘽妗嗗叧闂�
+    closeCancelDialog() {
+      this.$refs.cancelPopup.close()
+      this.selectedCancelReason = ''
+      this.currentCancelTask = null
+    },
+    
+    // 閫夋嫨鍙栨秷鍘熷洜
+    selectCancelReason(e) {
+      this.selectedCancelReason = this.cancelReasonList[e.detail.value].value
+    },
+    
+    // 甯﹀彇娑堝師鍥犵殑鐘舵�佹洿鏂�
+    updateTaskStatusWithCancelReason(taskId, status, remark, cancelReason) {
+      this.getLocationAndUpdateStatus(taskId, status, remark, cancelReason)
+    },
+    
     // 妫�鏌ョ煡鎯呭悓鎰忎功闄勪欢骞舵洿鏂扮姸鎬�
     async checkConsentAttachmentAndThen(taskId, status, remark) {
       try {
@@ -877,7 +973,7 @@
     },
 
     // 鑾峰彇浣嶇疆淇℃伅骞舵洿鏂扮姸鎬�
-    getLocationAndUpdateStatus(taskId, status, remark) {
+    getLocationAndUpdateStatus(taskId, status, remark, cancelReason) {
       const that = this;
 
       // 浣跨敤uni.getLocation鑾峰彇GPS浣嶇疆
@@ -904,6 +1000,11 @@
             speed: res.speed,
             heading: res.direction || res.heading,
           };
+          
+          // 濡傛灉鏈夊彇娑堝師鍥狅紝娣诲姞鍒拌姹傛暟鎹腑
+          if (cancelReason) {
+            statusData.cancelReason = cancelReason
+          }
 
           changeTaskStatus(taskId, statusData)
             .then((response) => {
@@ -926,6 +1027,11 @@
                 taskStatus: status,
                 remark: remark,
               };
+              
+              // 濡傛灉鏈夊彇娑堝師鍥狅紝娣诲姞鍒拌姹傛暟鎹腑
+              if (cancelReason) {
+                statusData.cancelReason = cancelReason
+              }
 
               changeTaskStatus(taskId, statusData)
                 .then((response) => {
@@ -1410,4 +1516,67 @@
     vertical-align: middle;
   }
 }
+
+// 鍙栨秷鍘熷洜瀵硅瘽妗嗘牱寮�
+.cancel-dialog {
+  width: 600rpx;
+  background-color: white;
+  border-radius: 20rpx;
+  padding: 40rpx;
+  
+  .dialog-title {
+    font-size: 32rpx;
+    font-weight: bold;
+    text-align: center;
+    margin-bottom: 30rpx;
+    color: #333;
+  }
+  
+  .reason-picker {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 20rpx 30rpx;
+    background-color: #f5f5f5;
+    border-radius: 10rpx;
+    margin-bottom: 30rpx;
+    
+    .picker-label {
+      font-size: 28rpx;
+      color: #666;
+    }
+    
+    .picker-value {
+      flex: 1;
+      text-align: right;
+      margin: 0 20rpx;
+      font-size: 28rpx;
+      color: #333;
+    }
+  }
+  
+  .dialog-buttons {
+    display: flex;
+    gap: 20rpx;
+    
+    button {
+      flex: 1;
+      height: 80rpx;
+      line-height: 80rpx;
+      border-radius: 10rpx;
+      font-size: 28rpx;
+      border: none;
+    }
+    
+    .cancel-btn {
+      background-color: #f5f5f5;
+      color: #666;
+    }
+    
+    .confirm-btn {
+      background-color: #007AFF;
+      color: white;
+    }
+  }
+}
 </style>
\ No newline at end of file
diff --git a/app/pagesTask/detail.vue b/app/pagesTask/detail.vue
index 6e0fdee..c6b060a 100644
--- a/app/pagesTask/detail.vue
+++ b/app/pagesTask/detail.vue
@@ -249,6 +249,23 @@
         </view>
       </view>
       
+      <!-- 鍙栨秷淇℃伅锛堜粎鍦ㄤ换鍔″凡鍙栨秷涓旀湁鍙栨秷鍘熷洜鏃舵樉绀猴級 -->
+      <view class="detail-section" v-if="taskDetail.taskStatus === 'CANCELLED' && taskDetail.emergencyInfo && taskDetail.emergencyInfo.cancelReason">
+        <view class="section-title">鍙栨秷淇℃伅</view>
+        <view class="info-item">
+          <view class="label">鍙栨秷鍘熷洜</view>
+          <view class="value">{{ getCancelReasonLabel(taskDetail.emergencyInfo.cancelReason) }}</view>
+        </view>
+        <view class="info-item" v-if="taskDetail.emergencyInfo.cancelBy">
+          <view class="label">鍙栨秷浜�</view>
+          <view class="value">{{ taskDetail.emergencyInfo.cancelBy }}</view>
+        </view>
+        <view class="info-item" v-if="taskDetail.emergencyInfo.cancelTime">
+          <view class="label">鍙栨秷鏃堕棿</view>
+          <view class="value">{{ formatTime(taskDetail.emergencyInfo.cancelTime) }}</view>
+        </view>
+      </view>
+      
       <!-- 鏀粯璁板綍鏄庣粏 -->
       <view class="detail-section" v-if="paymentInfo && paymentInfo.paidPayments && paymentInfo.paidPayments.length > 0">
         <view class="section-title">鏀粯璁板綍</view>
@@ -355,6 +372,26 @@
       <uni-icons type="spinner-cycle" size="40" color="#007AFF"></uni-icons>
       <text>鍔犺浇涓�...</text>
     </view>
+    
+    <!-- 鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗� -->
+    <uni-popup ref="cancelPopup" type="center" :is-mask-click="false">
+      <view class="cancel-dialog">
+        <view class="dialog-title">璇烽�夋嫨鍙栨秷鍘熷洜</view>
+        <picker mode="selector" :range="cancelReasonList" range-key="label" @change="selectCancelReason">
+          <view class="reason-picker">
+            <view class="picker-label">鍙栨秷鍘熷洜</view>
+            <view class="picker-value">
+              {{ selectedCancelReasonLabel }}
+            </view>
+            <uni-icons type="arrowright" size="16"></uni-icons>
+          </view>
+        </picker>
+        <view class="dialog-buttons">
+          <button class="cancel-btn" @click="closeCancelDialog">鍙栨秷</button>
+          <button class="confirm-btn" @click="confirmCancelTask">纭畾</button>
+        </view>
+      </view>
+    </uni-popup>
     
     <!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
     <view class="action-buttons" v-if="taskDetail">
@@ -467,6 +504,7 @@
   import { getTask, changeTaskStatus, setAssigneeReady, checkTaskConsentAttachment } from '@/api/task'
   import { checkVehicleActiveTasks } from '@/api/task'
   import { getPaymentInfo } from '@/api/payment'
+  import { getDicts } from '@/api/dict'
   import { formatDateTime } from '@/utils/common'
   import { validateTaskForDepart, validateTaskForSettlement, getTaskVehicleId, checkTaskCanDepart } from '@/utils/taskValidator'
   import AttachmentUpload from './components/AttachmentUpload.vue'
@@ -480,7 +518,10 @@
       return {
         taskDetail: null,
         taskId: null,
-        paymentInfo: null // 鏀粯淇℃伅
+        paymentInfo: null, // 鏀粯淇℃伅
+        cancelReasonList: [], // 鍙栨秷鍘熷洜鍒楄〃
+        showCancelDialog: false, // 鏄剧ず鍙栨秷鍘熷洜瀵硅瘽妗�
+        selectedCancelReason: '' // 閫変腑鐨勫彇娑堝師鍥�
       }
     },
     computed: {
@@ -503,7 +544,17 @@
           }
           return [baseClass, roleClasses[userType] || '']
         }
-      },      // 鏄剧ず浠诲姟绫诲瀷
+      },
+      
+      // 鑾峰彇閫変腑鐨勫彇娑堝師鍥犳爣绛撅紙鐢ㄤ簬寮圭獥鏄剧ず锛�
+      selectedCancelReasonLabel() {
+        if (!this.selectedCancelReason || !this.cancelReasonList.length) {
+          return '璇烽�夋嫨'
+        }
+        const reason = this.cancelReasonList.find(r => r.value === this.selectedCancelReason)
+        return reason ? reason.label : '璇烽�夋嫨'
+      },
+      // 鏄剧ず浠诲姟绫诲瀷
       displayTaskType() {
         if (!this.taskDetail || !this.taskDetail.taskType) {
           return '鏈缃�'
@@ -581,6 +632,7 @@
     onLoad(options) {
       this.taskId = options.id
       this.loadTaskDetail()
+      this.loadCancelReasonDict() // 鍔犺浇鍙栨秷鍘熷洜瀛楀吀
     },
     onShow() {
       // 姣忔椤甸潰鏄剧ず鏃堕噸鏂板姞杞芥暟鎹紝纭繚浠庣紪杈戦〉闈㈣繑鍥炲悗鑳界湅鍒版渶鏂版暟鎹�
@@ -810,10 +862,8 @@
             break;
             
           case 'cancel':
-            // 鍙栨秷 -> 浜屾纭鍚庣姸鎬佸彉涓哄凡鍙栨秷
-            this.$modal.confirm('纭畾瑕佸彇娑堟浠诲姟鍚楋紵').then(() => {
-              this.updateTaskStatus('CANCELLED', '浠诲姟宸插彇娑�')
-            }).catch(() => {});
+            // 鍙栨秷 -> 鏄剧ず鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗�
+            this.showCancelReasonDialog();
             break;
             
           case 'arrive':
@@ -995,7 +1045,7 @@
       },
       
       // 鑾峰彇浣嶇疆淇℃伅骞舵洿鏂扮姸鎬�
-      getLocationAndUpdateStatus(status, remark) {
+      getLocationAndUpdateStatus(status, remark, cancelReason) {
         const that = this
         
         // 浣跨敤uni.getLocation鑾峰彇GPS浣嶇疆
@@ -1022,6 +1072,11 @@
               heading: res.direction || res.heading
             }
             
+            // 濡傛灉鏈夊彇娑堝師鍥狅紝娣诲姞鍒拌姹傛暟鎹腑
+            if (cancelReason) {
+              statusData.cancelReason = cancelReason
+            }
+            
             changeTaskStatus(that.taskId, statusData).then(response => {
               that.$modal.showToast('鐘舵�佹洿鏂版垚鍔�')
               // 閲嶆柊鍔犺浇浠诲姟璇︽儏
@@ -1039,6 +1094,11 @@
               const statusData = {
                 taskStatus: status,
                 remark: remark
+              }
+              
+              // 濡傛灉鏈夊彇娑堝師鍥狅紝娣诲姞鍒拌姹傛暟鎹腑
+              if (cancelReason) {
+                statusData.cancelReason = cancelReason
               }
               
               changeTaskStatus(that.taskId, statusData).then(response => {
@@ -1470,6 +1530,65 @@
         return 'payment-' + (key !== null && key !== undefined ? key : index);
       },
       
+      // 鍔犺浇鍙栨秷鍘熷洜瀛楀吀
+      loadCancelReasonDict() {
+        // 浠庡悗绔幏鍙栧彇娑堝師鍥犲瓧鍏�
+        getDicts('task_cancel_reason').then(response => {
+          if (response.code === 200 && response.data) {
+            this.cancelReasonList = response.data.map(item => ({
+              value: item.dictValue,
+              label: item.dictLabel
+            }))
+          }
+        }).catch(error => {
+          console.error('鍔犺浇鍙栨秷鍘熷洜瀛楀吀澶辫触:', error)
+        })
+      },
+      
+      // 鏄剧ず鍙栨秷鍘熷洜瀵硅瘽妗�
+      showCancelReasonDialog() {
+        this.selectedCancelReason = ''
+        this.$refs.cancelPopup.open()
+      },
+      
+      // 纭鍙栨秷浠诲姟
+      confirmCancelTask() {
+        if (!this.selectedCancelReason) {
+          this.$modal.showToast('璇烽�夋嫨鍙栨秷鍘熷洜')
+          return
+        }
+        
+        this.$refs.cancelPopup.close()
+        
+        // 璋冪敤鏇存柊鐘舵�佹柟娉曪紝浼犻�掑彇娑堝師鍥�
+        this.updateTaskStatusWithCancelReason('CANCELLED', '浠诲姟宸插彇娑�', this.selectedCancelReason)
+      },
+      
+      // 鍙栨秷瀵硅瘽妗嗗叧闂�
+      closeCancelDialog() {
+        this.$refs.cancelPopup.close()
+        this.selectedCancelReason = ''
+      },
+      
+      // 閫夋嫨鍙栨秷鍘熷洜
+      selectCancelReason(e) {
+        this.selectedCancelReason = e.detail.value
+      },
+      
+      // 甯﹀彇娑堝師鍥犵殑鐘舵�佹洿鏂�
+      updateTaskStatusWithCancelReason(status, remark, cancelReason) {
+        this.getLocationAndUpdateStatus(status, remark, cancelReason)
+      },
+      
+      // 鏍规嵁鍙栨秷鍘熷洜value鑾峰彇label
+      getCancelReasonLabel(value) {
+        if (!value || !this.cancelReasonList.length) {
+          return value || '鏈煡'
+        }
+        const reason = this.cancelReasonList.find(r => r.value === value)
+        return reason ? reason.label : value
+      },
+      
     }
   }
 </script>
@@ -1867,5 +1986,67 @@
       margin-left: 10rpx;
       vertical-align: middle;
     }
+    
+    // 鍙栨秷鍘熷洜瀵硅瘽妗嗘牱寮�
+    .cancel-dialog {
+      width: 600rpx;
+      background-color: white;
+      border-radius: 20rpx;
+      padding: 40rpx;
+      
+      .dialog-title {
+        font-size: 32rpx;
+        font-weight: bold;
+        text-align: center;
+        margin-bottom: 30rpx;
+        color: #333;
+      }
+      
+      .reason-picker {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        padding: 20rpx 30rpx;
+        background-color: #f5f5f5;
+        border-radius: 10rpx;
+        margin-bottom: 30rpx;
+        
+        .picker-label {
+          font-size: 28rpx;
+          color: #666;
+        }
+        
+        .picker-value {
+          flex: 1;
+          text-align: right;
+          font-size: 28rpx;
+          color: #333;
+          margin: 0 10rpx;
+        }
+      }
+      
+      .dialog-buttons {
+        display: flex;
+        gap: 20rpx;
+        
+        button {
+          flex: 1;
+          height: 80rpx;
+          border-radius: 10rpx;
+          font-size: 30rpx;
+          border: none;
+          
+          &.cancel-btn {
+            background-color: #f0f0f0;
+            color: #666;
+          }
+          
+          &.confirm-btn {
+            background-color: #007AFF;
+            color: white;
+          }
+        }
+      }
+    }
   }
 </style>
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java
index 3260878..8d94003 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java
@@ -277,6 +277,11 @@
             return error("鏃犳晥鐨勪换鍔$姸鎬�");
         }
         
+        // 濡傛灉鏄彇娑堢姸鎬侊紝淇濆瓨鍙栨秷鍘熷洜
+        if (newStatus == TaskStatus.CANCELLED && StringUtils.isNotEmpty(request.getCancelReason())) {
+            sysTaskService.saveCancelInfo(taskId, request.getCancelReason());
+        }
+        
         // 濡傛灉鍖呭惈GPS浣嶇疆淇℃伅锛屼娇鐢ㄥ甫浣嶇疆鐨勬柟娉�
         if (request.getLatitude() != null && request.getLongitude() != null) {
            String address= mapService.reverseGeocoding(request.getLongitude(), request.getLatitude());
@@ -430,6 +435,9 @@
         private Double altitude;
         private Double speed;
         private Double heading;
+        
+        // 鍙栨秷鐩稿叧瀛楁
+        private String cancelReason;  // 鍙栨秷鍘熷洜锛堝叧鑱旀暟鎹瓧鍏竧ask_cancel_reason锛�
 
         public String getTaskStatus() {
             return taskStatus;
@@ -526,5 +534,13 @@
         public void setHeading(Double heading) {
             this.heading = heading;
         }
+
+        public String getCancelReason() {
+            return cancelReason;
+        }
+
+        public void setCancelReason(String cancelReason) {
+            this.cancelReason = cancelReason;
+        }
     }
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
index f4a3eb3..a442e16 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
@@ -69,6 +69,21 @@
     }
 
     /**
+     * 鑾峰彇鐢ㄦ埛鏄电О
+     **/
+    public static String getNickName()
+    {
+        try
+        {
+            return getLoginUser().getUser().getNickName();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("鑾峰彇鐢ㄦ埛鏄电О寮傚父", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
      * 鑾峰彇鐢ㄦ埛
      **/
     public static LoginUser getLoginUser()
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/ServiceOrderEntity.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/ServiceOrderEntity.java
new file mode 100644
index 0000000..8abf260
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/ServiceOrderEntity.java
@@ -0,0 +1,319 @@
+package com.ruoyi.system.domain;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.common.core.domain.BaseEntity;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.ibatis.type.Alias;
+import java.util.Date;
+
+/**
+ * ServiceOrder瀵硅薄 service_order
+ * 
+ * @author ruoyi
+ * @date 2025-12-24
+ */
+@Alias("ServiceOrderEntity")
+@DataSource(DataSourceType.SQLSERVER)
+public class ServiceOrderEntity extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ServiceOrdID */
+    private Long serviceOrdId;
+
+    /** ServiceOrdPtServices */
+    private String serviceOrdPtServices;
+
+    /** ServiceOrdPtInServices */
+    private String serviceOrdPtInServices;
+
+    /** ServiceOrdClass */
+    private String serviceOrdClass;
+
+    /** ServiceOrdAreaType */
+    private Long serviceOrdAreaType;
+
+    /** ServiceOrdType */
+    private Long serviceOrdType;
+
+    /** ServiceOrdApptDate */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date serviceOrdApptDate;
+
+    /** ServiceOrdCoTies */
+    private String serviceOrdCoTies;
+
+    /** ServiceOrdPtSex */
+    private String serviceOrdPtSex;
+
+    /** ServiceOrdPtNat */
+    private String serviceOrdPtNat;
+
+    /** ServiceOrdPtIDCard */
+    private String serviceOrdPtIdcard;
+    /**
+     * 鎶ヤ环閲戦
+     */
+    private Long serviceOrdTraTxnPrice;
+
+    /** ServiceOrdPtOutHospID_New (瀵瑰簲ServiceOrdPtOutHospID瀛楁) */
+    private Long serviceOrdPtOutHospIdNew;
+
+    /** ServiceOrdPtOutHospID */
+    private String serviceOrdPtOutHospId;
+
+    /** ServiceOrdPtInHospID_New (瀵瑰簲ServiceOrdPtInHospID瀛楁) */
+    private Long serviceOrdPtInHospIdNew;
+
+    /** ServiceOrdPtInHospID */
+    private String serviceOrdPtInHospId;
+
+    /** ServiceOrdPtCondition */
+    private String serviceOrdPtCondition;
+
+    /** ServiceOrdTaskRemarks */
+    private String serviceOrdTaskRemarks;
+
+    /** ServiceOrdTraStreet */
+    private String serviceOrdTraStreet;
+
+    /** ServiceOrdTraStreetCoo */
+    private String serviceOrdTraStreetCoo;
+
+    /** ServiceOrdTraEnd */
+    private String serviceOrdTraEnd;
+
+    /** ServiceOrdTraEndCoo */
+    private String serviceOrdTraEndCoo;
+
+    /** ServiceOrd_CC_ID */
+    private Long serviceOrdCcId;
+
+    public Long getServiceOrdId()
+    {
+        return serviceOrdId;
+    }
+
+    public void setServiceOrdId(Long serviceOrdId)
+    {
+        this.serviceOrdId = serviceOrdId;
+    }
+
+    public String getServiceOrdPtServices()
+    {
+        return serviceOrdPtServices;
+    }
+
+    public void setServiceOrdPtServices(String serviceOrdPtServices)
+    {
+        this.serviceOrdPtServices = serviceOrdPtServices;
+    }
+
+    public String getServiceOrdPtInServices()
+    {
+        return serviceOrdPtInServices;
+    }
+
+    public void setServiceOrdPtInServices(String serviceOrdPtInServices)
+    {
+        this.serviceOrdPtInServices = serviceOrdPtInServices;
+    }
+
+    public Long getServiceOrdTraTxnPrice() {
+        return serviceOrdTraTxnPrice;
+    }
+    public void setServiceOrdTraTxnPrice(Long serviceOrdTraTxnPrice) {
+        this.serviceOrdTraTxnPrice = serviceOrdTraTxnPrice;
+    }
+
+    public String getServiceOrdClass()
+    {
+        return serviceOrdClass;
+    }
+
+    public void setServiceOrdClass(String serviceOrdClass)
+    {
+        this.serviceOrdClass = serviceOrdClass;
+    }
+
+    public Long getServiceOrdAreaType()
+    {
+        return serviceOrdAreaType;
+    }
+
+    public void setServiceOrdAreaType(Long serviceOrdAreaType)
+    {
+        this.serviceOrdAreaType = serviceOrdAreaType;
+    }
+
+    public Long getServiceOrdType()
+    {
+        return serviceOrdType;
+    }
+
+    public void setServiceOrdType(Long serviceOrdType)
+    {
+        this.serviceOrdType = serviceOrdType;
+    }
+
+    public Date getServiceOrdApptDate()
+    {
+        return serviceOrdApptDate;
+    }
+
+    public void setServiceOrdApptDate(Date serviceOrdApptDate)
+    {
+        this.serviceOrdApptDate = serviceOrdApptDate;
+    }
+
+    public String getServiceOrdCoTies()
+    {
+        return serviceOrdCoTies;
+    }
+
+    public void setServiceOrdCoTies(String serviceOrdCoTies)
+    {
+        this.serviceOrdCoTies = serviceOrdCoTies;
+    }
+
+    public String getServiceOrdPtSex()
+    {
+        return serviceOrdPtSex;
+    }
+
+    public void setServiceOrdPtSex(String serviceOrdPtSex)
+    {
+        this.serviceOrdPtSex = serviceOrdPtSex;
+    }
+
+    public String getServiceOrdPtNat()
+    {
+        return serviceOrdPtNat;
+    }
+
+    public void setServiceOrdPtNat(String serviceOrdPtNat)
+    {
+        this.serviceOrdPtNat = serviceOrdPtNat;
+    }
+
+    public String getServiceOrdPtIdcard()
+    {
+        return serviceOrdPtIdcard;
+    }
+
+    public void setServiceOrdPtIdcard(String serviceOrdPtIdcard)
+    {
+        this.serviceOrdPtIdcard = serviceOrdPtIdcard;
+    }
+
+    public Long getServiceOrdPtOutHospIdNew()
+    {
+        return serviceOrdPtOutHospIdNew;
+    }
+
+    public void setServiceOrdPtOutHospIdNew(Long serviceOrdPtOutHospIdNew)
+    {
+        this.serviceOrdPtOutHospIdNew = serviceOrdPtOutHospIdNew;
+    }
+
+    public String getServiceOrdPtOutHospId()
+    {
+        return serviceOrdPtOutHospId;
+    }
+
+    public void setServiceOrdPtOutHospId(String serviceOrdPtOutHospId)
+    {
+        this.serviceOrdPtOutHospId = serviceOrdPtOutHospId;
+    }
+
+    public Long getServiceOrdPtInHospIdNew()
+    {
+        return serviceOrdPtInHospIdNew;
+    }
+
+    public void setServiceOrdPtInHospIdNew(Long serviceOrdPtInHospIdNew)
+    {
+        this.serviceOrdPtInHospIdNew = serviceOrdPtInHospIdNew;
+    }
+
+    public String getServiceOrdPtInHospId()
+    {
+        return serviceOrdPtInHospId;
+    }
+
+    public void setServiceOrdPtInHospId(String serviceOrdPtInHospId)
+    {
+        this.serviceOrdPtInHospId = serviceOrdPtInHospId;
+    }
+
+    public String getServiceOrdPtCondition()
+    {
+        return serviceOrdPtCondition;
+    }
+
+    public void setServiceOrdPtCondition(String serviceOrdPtCondition)
+    {
+        this.serviceOrdPtCondition = serviceOrdPtCondition;
+    }
+
+    public String getServiceOrdTaskRemarks()
+    {
+        return serviceOrdTaskRemarks;
+    }
+
+    public void setServiceOrdTaskRemarks(String serviceOrdTaskRemarks)
+    {
+        this.serviceOrdTaskRemarks = serviceOrdTaskRemarks;
+    }
+
+    public String getServiceOrdTraStreet()
+    {
+        return serviceOrdTraStreet;
+    }
+
+    public void setServiceOrdTraStreet(String serviceOrdTraStreet)
+    {
+        this.serviceOrdTraStreet = serviceOrdTraStreet;
+    }
+
+    public String getServiceOrdTraStreetCoo()
+    {
+        return serviceOrdTraStreetCoo;
+    }
+
+    public void setServiceOrdTraStreetCoo(String serviceOrdTraStreetCoo)
+    {
+        this.serviceOrdTraStreetCoo = serviceOrdTraStreetCoo;
+    }
+
+    public String getServiceOrdTraEnd()
+    {
+        return serviceOrdTraEnd;
+    }
+
+    public void setServiceOrdTraEnd(String serviceOrdTraEnd)
+    {
+        this.serviceOrdTraEnd = serviceOrdTraEnd;
+    }
+
+    public String getServiceOrdTraEndCoo()
+    {
+        return serviceOrdTraEndCoo;
+    }
+
+    public void setServiceOrdTraEndCoo(String serviceOrdTraEndCoo)
+    {
+        this.serviceOrdTraEndCoo = serviceOrdTraEndCoo;
+    }
+
+    public Long getServiceOrdCcId()
+    {
+        return serviceOrdCcId;
+    }
+
+    public void setServiceOrdCcId(Long serviceOrdCcId)
+    {
+        this.serviceOrdCcId = serviceOrdCcId;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java
index 3d641c5..80e7a9f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java
@@ -156,6 +156,15 @@
     
     /** 鏄惁骞垮窞鎬婚儴鎺ㄩ�侊紙0鍚� 1鏄級 */
     private String fromHq2Is;
+    
+    /** 鍙栨秷鍘熷洜锛堝叧鑱旀暟鎹瓧鍏竧ask_cancel_reason锛� */
+    private String cancelReason;
+    
+    /** 鍙栨秷浜� */
+    private String cancelBy;
+    
+    /** 鍙栨秷鏃堕棿 */
+    private java.util.Date cancelTime;
 
     public String getServiceCode(){
         if(this.legacyServiceOrdClass!=null && this.legacyServiceNsTime!=null && this.legacyServiceOrdNo!=null) {
@@ -562,6 +571,30 @@
         this.fromHq2Is = fromHq2Is;
     }
 
+    public String getCancelReason() {
+        return cancelReason;
+    }
+
+    public void setCancelReason(String cancelReason) {
+        this.cancelReason = cancelReason;
+    }
+
+    public String getCancelBy() {
+        return cancelBy;
+    }
+
+    public void setCancelBy(String cancelBy) {
+        this.cancelBy = cancelBy;
+    }
+
+    public java.util.Date getCancelTime() {
+        return cancelTime;
+    }
+
+    public void setCancelTime(java.util.Date cancelTime) {
+        this.cancelTime = cancelTime;
+    }
+
     @Override
     public String toString() {
         return "SysTaskEmergency{" +
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
index 1229e0b..d6ff46f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
@@ -62,9 +62,6 @@
     /** 鐩殑鍦扮含搴� */
     private BigDecimal destinationLatitude;
 
-    /** 棰勮鍏噷鏁� */
-    private BigDecimal estimatedDistance;
-
     /** 杞繍鏃堕棿 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date transferTime;
@@ -96,8 +93,8 @@
     /** 缁撴潫鍦板潃 */
     private String endAddress;
 
-    /** 绂忕杞﹀叕閲屾暟 */
-    private BigDecimal distance;
+    /** 鍏噷鏁� */
+    private BigDecimal transferDistance;
 
     /** 鍗曟嵁绫诲瀷ID锛堝搴擲QL Server鐨刣ictionary琛╲ID锛� */
     private String documentTypeId;
@@ -460,14 +457,6 @@
         this.destinationLatitude = destinationLatitude;
     }
 
-    public BigDecimal getEstimatedDistance() {
-        return estimatedDistance;
-    }
-
-    public void setEstimatedDistance(BigDecimal estimatedDistance) {
-        this.estimatedDistance = estimatedDistance;
-    }
-
     public Date getTransferTime() {
         return transferTime;
     }
@@ -549,13 +538,8 @@
         this.vehicleIds = vehicleIds;
     }
 
-    public BigDecimal getDistance() {
-        return distance;
-    }
 
-    public void setDistance(BigDecimal distance) {
-        this.distance = distance;
-    }
+
 
     public String getDocumentTypeId() {
         return documentTypeId;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ServiceOrderMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ServiceOrderMapper.java
index 9e6e200..7071286 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ServiceOrderMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ServiceOrderMapper.java
@@ -1,6 +1,8 @@
 package com.ruoyi.system.mapper;
 
 import java.util.List;
+import java.util.Map;
+
 import com.ruoyi.system.domain.ServiceOrder;
 import com.ruoyi.common.annotation.DataSource;
 import com.ruoyi.common.enums.DataSourceType;
@@ -70,4 +72,32 @@
      * @return 缁撴灉
      */
     public int deleteServiceOrderByIds(Long[] serviceOrdIds);
+    
+    /**
+     * 鏇存柊鏈嶅姟璁㈠崟鍙栨秷淇℃伅
+     * 
+     * @param serviceOrdId 鏈嶅姟璁㈠崟ID
+     * @param cancelReason 鍙栨秷鍘熷洜ID
+     * @param cancelReasonText 鍙栨秷鍘熷洜鏂囨湰
+     * @return 褰卞搷琛屾暟
+     */
+    public int updateServiceOrderCancelInfo(@Param("serviceOrdId") Long serviceOrdId, 
+                                           @Param("cancelReason") Integer cancelReason,
+                                           @Param("cancelReasonText") String cancelReasonText);
+    
+    /**
+     * 鏍规嵁鏈嶅姟璁㈠崟ID鏌ヨ璁㈠崟鐘舵��
+     * 
+     * @param serviceOrdId 鏈嶅姟璁㈠崟ID
+     * @return 璁㈠崟鐘舵�佺爜
+     */
+    public Integer selectServiceOrderStateById(Long serviceOrdId);
+
+    /**
+     * 鏍规嵁鏈嶅姟璁㈠崟ID鏌ヨ鍙栨秷淇℃伅
+     * 
+     * @param serviceOrdId 鏈嶅姟璁㈠崟ID
+     * @return 鍙栨秷淇℃伅
+     */
+    public Map<String, Object> selectServiceCancelInfoById(Long serviceOrdId);
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IServiceOrderService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IServiceOrderService.java
index 8f41b31..5ef7d22 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IServiceOrderService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IServiceOrderService.java
@@ -1,6 +1,9 @@
 package com.ruoyi.system.service;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
 import com.ruoyi.system.domain.ServiceOrder;
 
 /**
@@ -62,4 +65,24 @@
      * @return 缁撴灉
      */
     public int deleteServiceOrderById(Long serviceOrdId);
+    
+    /**
+     * 鏇存柊鏈嶅姟璁㈠崟鍙栨秷淇℃伅
+     * 
+     * @param serviceOrdId 鏈嶅姟璁㈠崟ID
+     * @param cancelReason 鍙栨秷鍘熷洜ID
+     * @param cancelReasonText 鍙栨秷鍘熷洜鏂囨湰
+     * @return 褰卞搷琛屾暟
+     */
+    public int updateServiceOrderCancelInfo(Long serviceOrdId, Integer cancelReason, String cancelReasonText);
+    
+    /**
+     * 鏍规嵁鏈嶅姟璁㈠崟ID鏌ヨ璁㈠崟鐘舵��
+     * 
+     * @param serviceOrdId 鏈嶅姟璁㈠崟ID
+     * @return 璁㈠崟鐘舵�佺爜
+     */
+    public Integer selectServiceOrderStateById(Long serviceOrdId);
+
+    public Map<String, Object> selectCancelInfoById(Long serviceOrdId);
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
index 0e06417..4d42c86 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
@@ -136,6 +136,23 @@
     public int changeTaskStatusWithLocation(Long taskId, TaskStatus newStatus, String remark, SysTaskLog locationLog);
 
     /**
+     * 淇濆瓨浠诲姟鍙栨秷淇℃伅锛堜粎闄愯浆杩愪换鍔★級
+     * 
+     * @param taskId 浠诲姟ID
+     * @param cancelReason 鍙栨秷鍘熷洜锛堟暟鎹瓧鍏竧ask_cancel_reason鐨剉alue锛�
+     * @return 缁撴灉
+     */
+    public int saveCancelInfo(Long taskId, String cancelReason);
+
+    /**
+     * 淇濆瓨浠诲姟鍙栨秷淇℃伅锛堝惈鍙栨秷浜猴級
+     * @param taskId
+     * @param cancelReason
+     * @param cancelBy
+     * @return
+     */
+    public int saveCancel(Long taskId, String cancelReason,String cancelBy,Date cancelTime);
+    /**
      * 涓婁紶浠诲姟闄勪欢
      * 
      * @param taskId 浠诲姟ID
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
index 58e1a02..8aaafd8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
@@ -508,7 +508,7 @@
             String ServiceOrdTraDistance=MapValueUtils.getStringValue(order, "ServiceOrdTraDistance");
             if(ServiceOrdTraDistance!=null){
                 ServiceOrdTraDistance=ServiceOrdTraDistance.replaceAll("[^0-9]", "");
-                createTaskVo.setDistance(new BigDecimal(ServiceOrdTraDistance));
+                createTaskVo.setTransferDistance(new BigDecimal(ServiceOrdTraDistance));
             }
 
             
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ServiceOrderServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ServiceOrderServiceImpl.java
index ec075dc..d31909e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ServiceOrderServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ServiceOrderServiceImpl.java
@@ -1,6 +1,8 @@
 package com.ruoyi.system.service.impl;
 
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 import com.ruoyi.common.annotation.DataSource;
 import com.ruoyi.common.enums.DataSourceType;
@@ -95,4 +97,33 @@
     public int deleteServiceOrderById(Long serviceOrdId) {
         return serviceOrderMapper.deleteServiceOrderById(serviceOrdId);
     }
+    
+    /**
+     * 鏇存柊鏈嶅姟璁㈠崟鍙栨秷淇℃伅
+     * 
+     * @param serviceOrdId 鏈嶅姟璁㈠崟ID
+     * @param cancelReason 鍙栨秷鍘熷洜ID
+     * @param cancelReasonText 鍙栨秷鍘熷洜鏂囨湰
+     * @return 褰卞搷琛屾暟
+     */
+    @Override
+    public int updateServiceOrderCancelInfo(Long serviceOrdId, Integer cancelReason, String cancelReasonText) {
+        return serviceOrderMapper.updateServiceOrderCancelInfo(serviceOrdId, cancelReason, cancelReasonText);
+    }
+    
+    /**
+     * 鏍规嵁鏈嶅姟璁㈠崟ID鏌ヨ璁㈠崟鐘舵��
+     * 
+     * @param serviceOrdId 鏈嶅姟璁㈠崟ID
+     * @return 璁㈠崟鐘舵�佺爜
+     */
+    @Override
+    public Integer selectServiceOrderStateById(Long serviceOrdId) {
+        return serviceOrderMapper.selectServiceOrderStateById(serviceOrdId);
+    }
+
+    @Override
+    public Map<String, Object> selectCancelInfoById(Long serviceOrdId) {
+        return serviceOrderMapper.selectServiceCancelInfoById(serviceOrdId);
+    }
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysEmergencyTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysEmergencyTaskServiceImpl.java
index a2dbe88..7ea9400 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysEmergencyTaskServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysEmergencyTaskServiceImpl.java
@@ -113,7 +113,7 @@
             }
         }
 
-        emergencyInfo.setTransferDistance(createVO.getDistance());
+        emergencyInfo.setTransferDistance(createVO.getTransferDistance());
         emergencyInfo.setTransferPrice(createVO.getPrice());
         emergencyInfo.setDocumentTypeId(createVO.getDocumentTypeId());
         emergencyInfo.setTaskTypeId(createVO.getTaskTypeId());
@@ -269,8 +269,8 @@
             }
         }
 
-        if (updateVO.getDistance() != null) {
-            oldEmergency.setTransferDistance(updateVO.getDistance());
+        if (updateVO.getTransferDistance() != null) {
+            oldEmergency.setTransferDistance(updateVO.getTransferDistance());
         }
         if (updateVO.getPrice() != null) {
             oldEmergency.setTransferPrice(updateVO.getPrice());
@@ -434,8 +434,8 @@
         }
         
         // 鏇存柊璐圭敤淇℃伅
-        if (createVO.getDistance() != null && BigDecimalUtil.izBigZero(createVO.getDistance())) {
-            existingInfo.setTransferDistance(createVO.getDistance());
+        if (createVO.getTransferDistance() != null && BigDecimalUtil.izBigZero(createVO.getTransferDistance())) {
+            existingInfo.setTransferDistance(createVO.getTransferDistance());
         }
         if (createVO.getPrice() != null) {
             existingInfo.setTransferPrice(createVO.getPrice());
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
index 461aae1..abbeaab 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
@@ -252,24 +252,29 @@
      * @return 缁撴灉
      */
     @Override
-    @Transactional
     public int insertSysTask(TaskCreateVO createVO) {
+    // 鑾峰彇褰撳墠鐢ㄦ埛鍚嶅拰鐢ㄦ埛ID
         String username = SecurityUtils.getUsername();
         Long userId = SecurityUtils.getUserId();
+    // 鏍¢獙鐢ㄦ埛ID鏄惁涓虹┖鎴栦负0
         if(userId==null || userId==0){
             log.error("insertSysTask 鐢ㄦ埛ID涓虹┖ userName:{}",username);
             return 0;
         }
         SysTask task = new SysTask();
+    // 鍒涘缓鏂扮殑浠诲姟瀵硅薄
         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.setAssigneeId(createVO.getAssigneeId());
 
+    // 璁剧疆浠诲姟鍩烘湰淇℃伅
+        task.setTaskType(createVO.getTaskType()); // 鐢熸垚浠诲姟缂栫爜
+        task.setTaskStatus(TaskStatus.PENDING.getCode()); // 璁剧疆浠诲姟绫诲瀷
+        task.setTaskDescription(createVO.getTaskDescription()); // 璁剧疆浠诲姟鐘舵�佷负寰呭鐞�
+        task.setPlannedStartTime(createVO.getPlannedStartTime()); // 璁剧疆浠诲姟鎻忚堪
+        task.setPlannedEndTime(createVO.getPlannedEndTime()); // 璁剧疆璁″垝寮�濮嬫椂闂�
+        task.setAssigneeId(createVO.getAssigneeId()); // 璁剧疆璁″垝缁撴潫鏃堕棿
+ // 璁剧疆鎸囨淳浜篒D
         task.setCreatorId(userId);
+    // 璁剧疆鍒涘缓浜轰俊鎭�
         // 浼樺厛浣跨敤鍓嶇浼犲叆鐨勯儴闂↖D锛屽鏋滄病鏈夊垯浣跨敤褰撳墠鐢ㄦ埛鐨勯儴闂↖D
         task.setDeptId(createVO.getDeptId() != null ? createVO.getDeptId() : SecurityUtils.getDeptId());
         task.setCreateBy(username);
@@ -388,8 +393,8 @@
         if (createVO.getTransferTime() != null) {
             task.setPlannedStartTime(createVO.getTransferTime());
         }
-        if (createVO.getDistance() != null) {
-            task.setEstimatedDistance(createVO.getDistance());
+        if (createVO.getTransferDistance() != null) {
+            task.setEstimatedDistance(createVO.getTransferDistance());
         }
         if (createVO.getPlannedStartTime() != null) {
             task.setPlannedStartTime(createVO.getPlannedStartTime());
@@ -400,9 +405,7 @@
         if (createVO.getEndAddress() != null) {
             task.setDestinationAddress(createVO.getEndAddress());
         }
-        if (createVO.getDistance() != null) {
-            task.setEstimatedDistance(createVO.getDistance());
-        }
+
         // 鑷姩濉厖缂哄け鐨凣PS鍧愭爣
         autoFillMissingGpsCoordinates(task);
         
@@ -503,11 +506,8 @@
 
         
         // 璁剧疆棰勮璺濈
-        if (updateVO.getEstimatedDistance() != null) {
-            task.setEstimatedDistance(updateVO.getEstimatedDistance());
-        } else if (updateVO.getDistance() != null) {
-            // 鍏煎鎬ユ晳杞繍瀛楁
-            task.setEstimatedDistance(updateVO.getDistance());
+        if (updateVO.getTransferDistance() != null) {
+            task.setEstimatedDistance(updateVO.getTransferDistance());
         }
         
         // 濡傛灉鏇存柊浜嗛儴闂↖D
@@ -812,7 +812,7 @@
             taskEmergency.setUpdateTime(DateUtils.getNowDate());
 
             Boolean hasEmergencyInfo = updateVO.getHospitalOut() != null || updateVO.getHospitalIn() != null || updateVO.getPatient() != null
-                    || updateVO.getPrice() != null || updateVO.getDistance() != null;
+                    || updateVO.getPrice() != null || updateVO.getTransferDistance() != null;
 //            Boolean isHeadPush=isTaskHeaderPush(task.getCreatorId(),task.getDeptId());
 //            updateVO.setFromHQ2_is(isHeadPush?"1":"0");
 
@@ -1013,6 +1013,71 @@
         }
         
         return result;
+    }
+
+    /**
+     * 淇濆瓨浠诲姟鍙栨秷淇℃伅锛堜粎闄愯浆杩愪换鍔★級
+     * 
+     * @param taskId 浠诲姟ID
+     * @param cancelReason 鍙栨秷鍘熷洜锛堟暟鎹瓧鍏竧ask_cancel_reason鐨剉alue锛�
+     * @return 缁撴灉
+     */
+    @Override
+    public int saveCancelInfo(Long taskId, String cancelReason) {
+        // 鑾峰彇浠诲姟淇℃伅
+        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
+        if (task == null) {
+            throw new RuntimeException("浠诲姟涓嶅瓨鍦�");
+        }
+        
+        // 鍙湁杞繍浠诲姟鎵嶄繚瀛樺彇娑堜俊鎭�
+        if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+            return 0;
+        }
+        
+        // 鑾峰彇杞繍浠诲姟鎵╁睍淇℃伅
+        SysTaskEmergency emergency = sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
+        if (emergency == null) {
+            return 0;
+        }
+        
+        // 璁剧疆鍙栨秷淇℃伅
+        emergency.setCancelReason(cancelReason);
+        emergency.setCancelBy(SecurityUtils.getNickName());
+        emergency.setCancelTime(DateUtils.getNowDate());
+        emergency.setUpdateBy(SecurityUtils.getUsername());
+        emergency.setUpdateTime(DateUtils.getNowDate());
+        
+        // 鏇存柊鏁版嵁搴�
+        return sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
+    }
+
+    @Override
+    public int saveCancel(Long taskId, String cancelReason, String cancelBy,Date cancelTime) {
+        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
+        if (task == null) {
+            throw new RuntimeException("浠诲姟涓嶅瓨鍦�");
+        }
+
+        // 鍙湁杞繍浠诲姟鎵嶄繚瀛樺彇娑堜俊鎭�
+        if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+            return 0;
+        }
+
+        // 鑾峰彇杞繍浠诲姟鎵╁睍淇℃伅
+        SysTaskEmergency emergency = sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
+        if (emergency == null) {
+            return 0;
+        }
+
+        // 璁剧疆鍙栨秷淇℃伅
+        emergency.setCancelReason(cancelReason);
+        emergency.setCancelBy(cancelBy);
+        emergency.setCancelTime(cancelTime);
+        emergency.setUpdateTime(DateUtils.getNowDate());
+
+        // 鏇存柊鏁版嵁搴�
+        return sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
     }
 
     /**
@@ -1420,8 +1485,8 @@
         if (createVO.getDestinationLatitude() != null) {
             task.setDestinationLatitude(createVO.getDestinationLatitude());
         }
-        if (createVO.getEstimatedDistance() != null) {
-            task.setEstimatedDistance(createVO.getEstimatedDistance());
+        if (createVO.getTransferDistance() != null) {
+            task.setEstimatedDistance(createVO.getTransferDistance());
         }
     }
 
@@ -1436,8 +1501,8 @@
         if (createVO.getTransferTime() != null) {
             task.setPlannedStartTime(createVO.getTransferTime());
         }
-        if (createVO.getDistance() != null) {
-            task.setEstimatedDistance(createVO.getDistance());
+        if (createVO.getTransferDistance() != null) {
+            task.setEstimatedDistance(createVO.getTransferDistance());
         }
         
         // 璁剧疆绂忕杞︾壒瀹氫俊鎭�
@@ -1450,9 +1515,7 @@
         if (createVO.getEndAddress() != null) {
             task.setDestinationAddress(createVO.getEndAddress());
         }
-        if (createVO.getDistance() != null) {
-            task.setEstimatedDistance(createVO.getDistance());
-        }
+
     }
 
     /**
@@ -1654,5 +1717,7 @@
     public AjaxResult cancelAssigneeReady(Long taskId, Long userId) {
         return sysTaskAssigneeService.cancelAssigneeReady(taskId, userId);
     }
+
+
    
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysWelfareTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysWelfareTaskServiceImpl.java
index 954e0db..59a66a4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysWelfareTaskServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysWelfareTaskServiceImpl.java
@@ -44,7 +44,7 @@
         
         // 璁剧疆璺濈鍜岃垂鐢�
         // 浼樺厛浣跨敤绂忕杞︿笓鐢ㄧ殑distance瀛楁锛屽鏋滄病鏈夊垯浣跨敤閫氱敤鐨別stimatedDistance
-        BigDecimal serviceDistance = createVO.getDistance() != null ? createVO.getDistance() : createVO.getEstimatedDistance();
+        BigDecimal serviceDistance = createVO.getTransferDistance() != null ? createVO.getTransferDistance() : BigDecimal.ZERO;
         welfareInfo.setServiceDistance(serviceDistance);
         welfareInfo.setServicePrice(createVO.getPrice());
         
@@ -102,10 +102,8 @@
         }
         
         // 鏇存柊璺濈鍜岃垂鐢�
-        if (createVO.getDistance() != null) {
-            existingInfo.setServiceDistance(createVO.getDistance());
-        } else if (createVO.getEstimatedDistance() != null) {
-            existingInfo.setServiceDistance(createVO.getEstimatedDistance());
+        if (createVO.getTransferDistance() != null) {
+            existingInfo.setServiceDistance(createVO.getTransferDistance());
         }
         if (createVO.getPrice() != null) {
             existingInfo.setServicePrice(createVO.getPrice());
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncUtilService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncUtilService.java
index 8300d98..46d91b1 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncUtilService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncUtilService.java
@@ -42,7 +42,7 @@
 
         // 鑾峰彇绠$悊鍛業D锛堝垱寤轰汉ID瀵瑰簲鐨凮A_UserID锛�
         String adminID = taskSyncUtilService.getAdminID(task);
-
+        String serviceOrdClass = "BF";
         // 鑾峰彇璋冨害鍗曠被鍨嬶紙浠庝换鍔℃墍灞為儴闂ㄧ殑璋冨害鍗曠紪鐮佽幏鍙栵級
         String dispatchOrdClass = "SA"; // 榛樿鍊�
         if (task.getDeptId() != null) {
@@ -50,6 +50,7 @@
                 SysDept dept = sysDeptMapper.selectDeptById(task.getDeptId());
                 if (dept != null && StringUtils.isNotEmpty(dept.getDispatchOrderClass())) {
                     dispatchOrdClass = dept.getDispatchOrderClass();
+                    serviceOrdClass = dept.getServiceOrderClass();
 //                    log.info("鑾峰彇浠诲姟鎵�灞為儴闂ㄧ殑璋冨害鍗曠紪鐮佹垚鍔燂紝閮ㄩ棬ID: {}, 璋冨害鍗曠紪鐮�: {}", task.getDeptId(), dispatchOrdClass);
                 }
             } catch (Exception e) {
@@ -57,7 +58,23 @@
             }
         }
         params.put("AdminID", adminID);
-
+        params.put("ServiceOrdClass", serviceOrdClass);
+        String serviceOrdAreaType = "1"; // 榛樿鍊�
+        if (StringUtils.isNotEmpty(emergency.getDocumentTypeId())) {
+            serviceOrdAreaType = emergency.getDocumentTypeId();
+//            log.info("鑾峰彇鍗曟嵁绫诲瀷ID鎴愬姛锛屼换鍔D: {}, 鍗曟嵁绫诲瀷ID: {}", task.getTaskId(), serviceOrdAreaType);
+        } else {
+            log.warn("浠诲姟鏈厤缃崟鎹被鍨婭D锛屼换鍔D: {}锛屼娇鐢ㄩ粯璁ゅ��", task.getTaskId());
+        }
+        params.put("ServiceOrdAreaType", serviceOrdAreaType); // 浠庝换鍔$殑document_type_id鑾峰彇
+        String serviceOrdType = "1"; // 榛樿鍊�
+        if (StringUtils.isNotEmpty(emergency.getTaskTypeId())) {
+            serviceOrdType = emergency.getTaskTypeId();
+//            log.info("鑾峰彇浠诲姟绫诲瀷ID鎴愬姛锛屼换鍔D: {}, 浠诲姟绫诲瀷ID: {}", taskId, serviceOrdType);
+        } else {
+            log.warn("浠诲姟鏈厤缃换鍔$被鍨婭D锛屼换鍔D: {}锛屼娇鐢ㄩ粯璁ゅ��", task.getTaskId());
+        }
+        params.put("ServiceOrdType", serviceOrdType); // 鏈嶅姟鍗曟墽琛岀被鍨嬶紙浠庝换鍔$殑task_type_id鑾峰彇锛�
         // 鍩烘湰淇℃伅
         params.put("DispatchOrdClass", dispatchOrdClass);
         params.put("ServiceOrdID", emergency.getLegacyServiceOrdId().toString());
@@ -104,7 +121,8 @@
                 transferPrice = "0";
             }
         }
-        params.put("DispatchOrdPerfomance", transferPrice);
+        //鎴愪氦浠�
+        params.put("ServiceOrdTraTxnPrice", transferPrice);
         params.put("StretcherMoney", "0"); // 鎶媴鏋惰垂
         params.put("AddMoneyType", ""); // 闄勫姞椤圭洰
         params.put("AddMoney", "0"); // 闄勫姞椤圭洰璐圭敤
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskEmergencySyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskEmergencySyncServiceImpl.java
index 91b1425..4919f36 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskEmergencySyncServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskEmergencySyncServiceImpl.java
@@ -86,7 +86,7 @@
             // 瑙f瀽鍝嶅簲
             Long serviceOrdId = taskSyncUtilService.parseResponse(response);
 
-            if (LongUtil.isNotEmpty(serviceOrderId)) {
+            if (LongUtil.isNotEmpty(serviceOrdId)) {
                 // 鍚屾鎴愬姛锛屾洿鏂拌褰�
                 emergency.setLegacyServiceOrdId(serviceOrdId);
                 emergency.setSyncStatus(2); // 鍚屾鎴愬姛
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusPushServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusPushServiceImpl.java
index 98a4b8f..a9b79e8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusPushServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusPushServiceImpl.java
@@ -1,11 +1,14 @@
 package com.ruoyi.system.service.impl;
 
 import com.ruoyi.common.config.LegacySystemConfig;
+import com.ruoyi.common.utils.LongUtil;
 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.IServiceOrderService;
+import com.ruoyi.system.service.ISysDictDataService;
 import com.ruoyi.system.service.ISysTaskEmergencyService;
 import com.ruoyi.system.service.ITaskStatusPushService;
 import com.ruoyi.system.utils.TaskStatusPushConverter;
@@ -40,6 +43,12 @@
     
     @Autowired
     private IDispatchOrdService dispatchOrdService;
+    
+    @Autowired
+    private IServiceOrderService serviceOrderService;
+    
+    @Autowired
+    private ISysDictDataService sysDictDataService;
     
     /**
      * 灏嗗崟涓换鍔$姸鎬佹帹閫佸埌鏃х郴缁�
@@ -115,7 +124,12 @@
 //                    currentLegacyStatus, TaskStatusPushConverter.getLegacyStatusDescription(currentLegacyStatus));
                 return true; // 杩斿洖true锛屽洜涓鸿繖涓嶇畻澶辫触锛屽彧鏄笉闇�瑕佹帹閫�
             }
-            
+            if(newTaskStatus.equals(TaskStatus.CANCELLED)){
+                if(LongUtil.isNotEmpty(emergency.getLegacyServiceOrdId()) ) {
+                    log.info("鍙栨秷杞繍浠诲姟: {}", emergency.getLegacyServiceOrdId());
+                    cancelTask(emergency.getLegacyServiceOrdId(), emergency.getCancelReason(), emergency.getCancelBy());
+                }
+            }
             // 鎺ㄩ�佺姸鎬佸埌鏃х郴缁�
             boolean result = updateLegacyTaskStatus(emergency.getLegacyDispatchOrdId(), targetStatusCode);
             
@@ -204,7 +218,52 @@
             return 0;
         }
     }
-    
+
+
+    private void cancelTask(Long serviceOrderId, String cancelReason, String cancelBy){
+        // 鍙栨秷浠诲姟锛屾洿鏂癝QL Server涓殑ServiceOrder琛�
+        try {
+            if (serviceOrderId == null || serviceOrderId <= 0) {
+                log.warn("ServiceOrderID涓虹┖锛屾棤娉曞彇娑堜换鍔�");
+                return;
+            }
+            
+            // 瑙f瀽鍙栨秷鍘熷洜ID
+            Integer cancelReasonId = null;
+            String cancelReasonText = "";
+            
+            if (cancelReason != null && !cancelReason.isEmpty()) {
+                try {
+                    cancelReasonId = Integer.parseInt(cancelReason);
+                    // 浠庢暟鎹瓧鍏告煡璇㈠彇娑堝師鍥犳枃鏈�
+                    String dictLabel = sysDictDataService.selectDictLabel("task_cancel_reason", cancelReason);
+                    if (dictLabel != null && !dictLabel.isEmpty()) {
+                        cancelReasonText = "[鍙栨秷鎿嶄綔:" + (cancelBy != null ? cancelBy : "绯荤粺") + "] " + dictLabel;
+                    } else {
+                        cancelReasonText = "[鍙栨秷鎿嶄綔:" + (cancelBy != null ? cancelBy : "绯荤粺") + "]";
+                    }
+                } catch (NumberFormatException e) {
+                    log.warn("鍙栨秷鍘熷洜ID鏍煎紡閿欒: {}", cancelReason);
+                    cancelReasonText = "[鍙栨秷鎿嶄綔:" + (cancelBy != null ? cancelBy : "绯荤粺") + "] " + cancelReason;
+                }
+            } else {
+                cancelReasonText = "[鍙栨秷鎿嶄綔:" + (cancelBy != null ? cancelBy : "绯荤粺") + "]";
+            }
+            
+            // 璋冪敤Service鏇存柊ServiceOrder琛�
+            int rows = serviceOrderService.updateServiceOrderCancelInfo(serviceOrderId, cancelReasonId, cancelReasonText);
+            
+            if (rows > 0) {
+                log.info("鎴愬姛鏇存柊鏃х郴缁烻erviceOrder鍙栨秷淇℃伅锛孲erviceOrdID: {}, 鍙栨秷鍘熷洜ID: {}, 鍙栨秷鍘熷洜鏂囨湰: {}", 
+                    serviceOrderId, cancelReasonId, cancelReasonText);
+            } else {
+                log.warn("鏇存柊鏃х郴缁烻erviceOrder鍙栨秷淇℃伅澶辫触锛屾湭鎵惧埌瀵瑰簲璁㈠崟锛孲erviceOrdID: {}", serviceOrderId);
+            }
+            
+        } catch (Exception e) {
+            log.error("鏇存柊鏃х郴缁烻erviceOrder鍙栨秷淇℃伅寮傚父锛孲erviceOrdID: {}", serviceOrderId, e);
+        }
+    }
     /**
      * 鏇存柊鏃х郴缁熻皟搴﹀崟鐘舵�侊紙鐩存帴鎿嶄綔SQL Server鏁版嵁搴擄級
      * 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusSyncServiceImpl.java
index 7c6ab7a..532ff64 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusSyncServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskStatusSyncServiceImpl.java
@@ -1,14 +1,14 @@
 package com.ruoyi.system.service.impl;
 
 import com.ruoyi.common.config.LegacySystemConfig;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.LongUtil;
 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.service.*;
 import com.ruoyi.system.utils.TaskStatusConverter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,6 +35,9 @@
     
     @Autowired
     private SysTaskMapper sysTaskMapper;
+
+    @Autowired
+    private ISysTaskService taskService;
     
     @Autowired
     private ISysTaskEmergencyService sysTaskEmergencyService;
@@ -97,7 +100,9 @@
             return false;
         }
     }
-    
+
+    @Autowired
+    private IServiceOrderService serviceOrderService;
     /**
      * 鎵归噺鍚屾宸插悓姝ヨ皟搴﹀崟鐨勪换鍔$姸鎬侊紙浠庢棫绯荤粺鍒版柊绯荤粺锛�
      * 浣跨敤鍒嗛〉鏌ヨ锛屾壒閲忔煡璇QL Server鏁版嵁搴擄紝鍑忓皯缃戠粶璇锋眰娆℃暟
@@ -128,69 +133,58 @@
 //                log.info("寮�濮嬪悓姝ョ姸鎬佺 {} 椤碉紝浠诲姟鏁伴噺: {}", (offset / pageSize) + 1, syncedTasks.size());
                 
                 // 2. 鎻愬彇璋冨害鍗旾D鍒楄〃
-                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 (LongUtil.isNotEmpty(emergency.getTaskId())) {
+
+                        if(!dispatchIdToTaskMap.containsKey(dispatchOrdId)) {
+                            dispatchIdToTaskMap.put(emergency.getTaskId(), emergency);
+                        }
+                    }
+                    Long serviceOrdId = emergency.getLegacyServiceOrdId();
+                    if(LongUtil.isNotEmpty(serviceOrdId)){
+                        if(!dispatchIdToTaskMap.containsKey(emergency.getTaskId())) {
+                            dispatchIdToTaskMap.put(emergency.getTaskId(), emergency);
+                        }
                     }
                 }
                 
-                if (dispatchOrdIDs.isEmpty()) {
+                if (dispatchIdToTaskMap.size()<=0) {
 //                    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. 鏋勫缓璋冨害鍗旾D鍒扮姸鎬佺殑鏄犲皠
-                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);
+                dispatchIdToTaskMap.forEach((taskId, emergency) -> {
+                    Long dispatchOrdId = emergency.getLegacyDispatchOrdId();
+                    Long serviceOrdId = emergency.getLegacyServiceOrdId();
+                    if(LongUtil.isNotEmpty(dispatchOrdId)){
+                       Integer state =dispatchOrdService.selectDispatchOrdStateByID(dispatchOrdId);
+                        syncTaskStatusWithLegacyState(taskId, state);
+                    }
+                    else if(LongUtil.isNotEmpty(serviceOrdId)){
+                        try {
+                            Integer serviceOrdState = serviceOrderService.selectServiceOrderStateById(serviceOrdId);
+                            if (serviceOrdState == 4) {
+                                //鍙栨秷
+                                Map<String, Object> cancelInfo = serviceOrderService.selectCancelInfoById(serviceOrdId);
+                                String cancelReasonText = (String) cancelInfo.get("ServiceOrdCancelReasonTXT");
+                                String cancelReason = (String) cancelInfo.get("ServiceOrdCancelReason");
+                                taskService.saveCancel(taskId, cancelReason, cancelReasonText, DateUtils.getNowDate());
+                            }
+                        }catch (Exception ex){
+                            log.error("鏌ヨ鏃х郴缁熺姸鎬佸け璐ワ紝浠诲姟ID: {}, ServiceOrdID: {}", taskId, serviceOrdId);
                         }
-                    } catch (NumberFormatException e) {
-                        log.error("瑙f瀽璋冨害鍗旾D澶辫触: {}", dispatchOrd.getDispatchOrdID(), e);
+
+//                        syncTaskStatusWithLegacyState(taskId, state);
                     }
-                }
-                
-                // 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) {
@@ -279,6 +273,7 @@
                 default:
                     break;
             }
+
             
             sysTaskMapper.updateSysTask(task);
             
diff --git a/ruoyi-system/src/main/resources/mapper/system/ServiceOrderMapper.xml b/ruoyi-system/src/main/resources/mapper/system/ServiceOrderMapper.xml
index 1da7841..d536817 100644
--- a/ruoyi-system/src/main/resources/mapper/system/ServiceOrderMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/ServiceOrderMapper.xml
@@ -33,7 +33,11 @@
         <result property="serviceOrdCCTime"    column="ServiceOrd_CC_Time"    />
         <result property="serviceOrdVisit"    column="ServiceOrdVisit"    />
     </resultMap>
-
+    <resultMap type="java.util.HashMap" id="ServiceCancelResult">
+        <result property="ServiceOrdState" column="ServiceOrdState" />
+        <result property="ServiceOrdCancelReason" column="ServiceOrdCancelReason" />
+        <result property="ServiceOrdCancelReasonTXT" column="ServiceOrdCancelReasonTXT" />
+    </resultMap>
     <sql id="selectServiceOrderVo">
         select ServiceOrdID, ServiceOrdUserID, ServiceOrdClass, ServiceOrdType, ServiceOrdState, ServiceOrdStartDate, ServiceOrdApptDate, ServiceOrdCoName, ServiceOrdCoPhone, ServiceOrdPtName, ServiceOrdPtAge, ServiceOrdPtSex, ServiceOrdPtKG, ServiceOrdPtNat, ServiceOrdPtIDCard, ServiceOrdTraProvince, ServiceOrdTraCity, ServiceOrdTraStreet, ServiceOrdTraEnd, ServiceOrdTraDistance, ServiceOrdTraUnitPrice, ServiceOrdTraTxnPrice, ServiceOrdTraPaidType, ServiceOrdTraPaidPrice, ServiceOrdUnitRemarks, ServiceOrd_CC_Time, ServiceOrdVisit from ServiceOrder
     </sql>
@@ -174,4 +178,25 @@
             #{serviceOrdId}
         </foreach>
     </delete>
+    
+    <!-- 鏇存柊鏈嶅姟璁㈠崟鍙栨秷淇℃伅 -->
+    <update id="updateServiceOrderCancelInfo">
+        update ServiceOrder 
+        set ServiceOrdState = 4,
+            ServiceOrdCancelReason = #{cancelReason},
+            ServiceOrdCancelReasonTXT = #{cancelReasonText}
+        where ServiceOrdID = #{serviceOrdId}
+    </update>
+    
+    <!-- 鏍规嵁鏈嶅姟璁㈠崟ID鏌ヨ璁㈠崟鐘舵�� -->
+    <select id="selectServiceOrderStateById" parameterType="Long" resultType="Integer">
+        select ServiceOrdState 
+        from ServiceOrder 
+        where ServiceOrdID = #{serviceOrdId}
+    </select>
+    <select id="selectServiceCancelInfoById" parameterType="Long" resultMap="ServiceCancelResult">
+        select ServiceOrdState, ServiceOrdCancelReason, ServiceOrdCancelReasonTXT
+        from ServiceOrder 
+        where ServiceOrdID = #{serviceOrdId}
+    </select>
 </mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
index 30e4c75..2df0e8c 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
@@ -53,6 +53,9 @@
         <result property="legacyServiceOrdClass"   column="legacy_service_ord_class" />
         <result property="serviceOrdVip"           column="service_ord_vip"         />
         <result property="fromHq2Is"               column="from_hq2_is"             />
+        <result property="cancelReason"            column="cancel_reason"           />
+        <result property="cancelBy"                column="cancel_by"               />
+        <result property="cancelTime"              column="cancel_time"             />
         <result property="createTime"              column="create_time"             />
         <result property="updateTime"              column="update_time"             />
         <result property="createBy"                column="create_by"               />
@@ -68,6 +71,7 @@
                hospital_in_latitude, transfer_distance, transfer_price, passenger_contact, 
                passenger_phone, disease_ids, document_type_id, task_type_id, legacy_service_ord_id, legacy_dispatch_ord_id, 
                sync_status, sync_time, sync_error_msg, dispatch_sync_status, dispatch_sync_time, dispatch_sync_error_msg, need_resync, legacy_service_ord_no, legacy_dispatch_ord_no, legacy_service_ns_time, legacy_dispatch_ns_time, legacy_dispatch_ord_class, legacy_service_ord_class, service_ord_vip, from_hq2_is,
+               cancel_reason, cancel_by, cancel_time,
                create_time, update_time, create_by, update_by
         from sys_task_emergency
     </sql>
@@ -132,6 +136,9 @@
             <if test="legacyServiceOrdClass != null">legacy_service_ord_class,</if>
             <if test="serviceOrdVip != null">service_ord_vip,</if>
             <if test="fromHq2Is != null">from_hq2_is,</if>
+            <if test="cancelReason != null">cancel_reason,</if>
+            <if test="cancelBy != null">cancel_by,</if>
+            <if test="cancelTime != null">cancel_time,</if>
             <if test="createTime != null">create_time,</if>
             <if test="updateTime != null">update_time,</if>
             <if test="createBy != null">create_by,</if>
@@ -185,6 +192,9 @@
             <if test="legacyServiceOrdClass != null">#{legacyServiceOrdClass},</if>
             <if test="serviceOrdVip != null">#{serviceOrdVip},</if>
             <if test="fromHq2Is != null">#{fromHq2Is},</if>
+            <if test="cancelReason != null">#{cancelReason},</if>
+            <if test="cancelBy != null">#{cancelBy},</if>
+            <if test="cancelTime != null">#{cancelTime},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="updateTime != null">#{updateTime},</if>
             <if test="createBy != null">#{createBy},</if>
@@ -241,6 +251,9 @@
             <if test="legacyServiceOrdClass != null">legacy_service_ord_class = #{legacyServiceOrdClass},</if>
             <if test="serviceOrdVip != null">service_ord_vip = #{serviceOrdVip},</if>
             <if test="fromHq2Is != null">from_hq2_is = #{fromHq2Is},</if>
+            <if test="cancelReason != null">cancel_reason = #{cancelReason},</if>
+            <if test="cancelBy != null">cancel_by = #{cancelBy},</if>
+            <if test="cancelTime != null">cancel_time = #{cancelTime},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="updateBy != null">update_by = #{updateBy},</if>
         </trim>
diff --git a/sql/add_cancel_reason_fields.sql b/sql/add_cancel_reason_fields.sql
new file mode 100644
index 0000000..e66fe43
--- /dev/null
+++ b/sql/add_cancel_reason_fields.sql
@@ -0,0 +1,24 @@
+-- ----------------------------
+-- 涓簊ys_task_emergency琛ㄦ坊鍔犲彇娑堢浉鍏冲瓧娈�
+-- 鐢ㄤ簬璁板綍浠诲姟鍙栨秷鐨勫師鍥犮�佸彇娑堜汉鍜屽彇娑堟椂闂�
+-- 鎵ц鏃堕棿锛�2024-12-24
+-- ----------------------------
+
+-- 娣诲姞鍙栨秷鍘熷洜瀛楁锛堝叧鑱旀暟鎹瓧鍏竧ask_cancel_reason锛�
+ALTER TABLE sys_task_emergency 
+ADD COLUMN cancel_reason VARCHAR(50) COMMENT '鍙栨秷鍘熷洜锛堝叧鑱旀暟鎹瓧鍏竧ask_cancel_reason锛�' AFTER from_hq2_is;
+
+-- 娣诲姞鍙栨秷浜哄瓧娈�
+ALTER TABLE sys_task_emergency 
+ADD COLUMN cancel_by VARCHAR(64) COMMENT '鍙栨秷浜�' AFTER cancel_reason;
+
+-- 娣诲姞鍙栨秷鏃堕棿瀛楁
+ALTER TABLE sys_task_emergency 
+ADD COLUMN cancel_time DATETIME COMMENT '鍙栨秷鏃堕棿' AFTER cancel_by;
+
+-- 鍒涘缓绱㈠紩浠ユ彁鍗囨煡璇㈡�ц兘
+CREATE INDEX idx_cancel_reason ON sys_task_emergency(cancel_reason);
+CREATE INDEX idx_cancel_time ON sys_task_emergency(cancel_time);
+
+-- 鏌ョ湅琛ㄧ粨鏋�
+DESC sys_task_emergency;
diff --git a/sql/insert_dict_task_cancel_reason.sql b/sql/insert_dict_task_cancel_reason.sql
new file mode 100644
index 0000000..87a207a
--- /dev/null
+++ b/sql/insert_dict_task_cancel_reason.sql
@@ -0,0 +1,42 @@
+-- ----------------------------
+-- 鎻掑叆浠诲姟鍙栨秷鍘熷洜鏁版嵁瀛楀吀
+-- 瀛楀吀绫诲瀷锛歵ask_cancel_reason
+-- 鎵ц鏃堕棿锛�2024-12-24
+-- ----------------------------
+
+-- 1. 鎻掑叆瀛楀吀绫诲瀷
+INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) 
+VALUES ('浠诲姟鍙栨秷鍘熷洜', 'task_cancel_reason', '0', 'admin', NOW(), '杞繍浠诲姟鍙栨秷鍘熷洜瀛楀吀');
+
+-- 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, remark) VALUES
+(1, '浠锋牸涓嶆帴鍙�', '1', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '瀹㈡埛瀵逛环鏍间笉婊℃剰'),
+(2, '鏃堕棿绱ф��', '2', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '鏃堕棿瑕佹眰绱ф��'),
+(3, '鍑鸿溅閫熷害鎱�', '3', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '鍑鸿溅閫熷害涓嶅蹇�'),
+(4, '閫夋嫨鍏朵粬杞�', '4', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '瀹㈡埛閫夋嫨鍏朵粬杞﹁締'),
+(5, '鐥呬汉娌℃湁鐢熷懡浣撳緛', '5', 'task_cancel_reason', '', 'danger', 'N', '0', 'admin', NOW(), '鐥呬汉宸叉棤鐢熷懡浣撳緛'),
+(6, '鍖荤敓鎶ゅ+鍧囦笉瓒�', '6', 'task_cancel_reason', '', 'warning', 'N', '0', 'admin', NOW(), '鍖绘姢浜哄憳涓嶈冻'),
+(7, '鐥呬汉鎯呭喌鏈夊彉', '7', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '鐥呬汉鎯呭喌鍙戠敓鍙樺寲'),
+(8, '鍏朵粬', '8', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '鍏朵粬鍘熷洜'),
+(9, '绗笁鏂瑰彇娑�', '9', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '绗笁鏂瑰彇娑堜换鍔�'),
+(10, '娴嬭瘯璁㈠崟', '10', 'task_cancel_reason', '', 'info', 'N', '0', 'admin', NOW(), '娴嬭瘯璁㈠崟'),
+(11, '浼犳煋鎬х柧鐥�', '11', 'task_cancel_reason', '', 'danger', 'N', '0', 'admin', NOW(), '鐥呬汉鎮f湁浼犳煋鎬х柧鐥�'),
+(12, '瀹跺睘鎸傛満/鎷掓帴/涓嶆帴鐢佃瘽', '12', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '瀹跺睘鏃犳硶鑱旂郴'),
+(13, '鎶ゅ+涓嶈冻', '13', 'task_cancel_reason', '', 'warning', 'N', '0', 'admin', NOW(), '鎶ゅ+浜哄憳涓嶈冻'),
+(14, '鍖荤敓涓嶈冻', '14', 'task_cancel_reason', '', 'warning', 'N', '0', 'admin', NOW(), '鍖荤敓浜哄憳涓嶈冻'),
+(15, '璁惧涓嶈冻(鍛煎惛鏈�)', '15', 'task_cancel_reason', '', 'warning', 'N', '0', 'admin', NOW(), '缂哄皯蹇呰璁惧'),
+(16, '瀹跺睘娌¤仈绯诲ソ搴婁綅', '16', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '鐩爣鍖婚櫌搴婁綅鏈‘璁�'),
+(17, '绉讳氦鍒嗘敮鏈烘瀯鎵ц', '17', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '浠诲姟绉讳氦缁欏垎鏀満鏋�'),
+(18, '绉讳氦鍔炰簨澶�(婀涙睙)', '18', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '浠诲姟绉讳氦婀涙睙鍔炰簨澶�'),
+(19, '绉讳氦鍔炰簨澶�(鑼傚悕)', '19', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '浠诲姟绉讳氦鑼傚悕鍔炰簨澶�'),
+(20, '瀹跺睘涓嶈偗閫忛湶淇℃伅', '20', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '瀹跺睘鎷掔粷鎻愪緵蹇呰淇℃伅'),
+(21, '鎵�鍦ㄥ尰闄�/鐩殑鍦板尰闄㈡淳杞�', '21', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '鍖婚櫌鑷繁瀹夋帓杞﹁締'),
+(22, '鑷┚杞︽帴閫佹偅鑰�', '22', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '瀹跺睘鑷繁寮�杞︽帴閫�'),
+(23, '閫夋嫨鍏朵粬鏈烘瀯杞﹁締', '23', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '閫夋嫨鍏朵粬鏁戞姢鏈烘瀯'),
+(24, '澶栬仈閫氱煡鍙栨秷', '24', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '澶栬仈鍚堜綔鏂归�氱煡鍙栨秷'),
+(25, '澶栬仈鏃犲弽棣�', '25', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '澶栬仈鏃犲搷搴�'),
+(26, '瀹跺睘鏃犲師鍥犵洿鎺ュ憡鐭ュ彇娑�', '26', 'task_cancel_reason', '', 'default', 'N', '0', 'admin', NOW(), '瀹跺睘鐩存帴瑕佹眰鍙栨秷');
+
+-- 鏌ヨ楠岃瘉
+SELECT * FROM sys_dict_type WHERE dict_type = 'task_cancel_reason';
+SELECT * FROM sys_dict_data WHERE dict_type = 'task_cancel_reason' ORDER BY dict_sort;
diff --git "a/\345\217\226\346\266\210\345\216\237\345\233\240\345\212\237\350\203\275\345\256\236\347\216\260\350\257\264\346\230\216.md" "b/\345\217\226\346\266\210\345\216\237\345\233\240\345\212\237\350\203\275\345\256\236\347\216\260\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..21c2c43
--- /dev/null
+++ "b/\345\217\226\346\266\210\345\216\237\345\233\240\345\212\237\350\203\275\345\256\236\347\216\260\350\257\264\346\230\216.md"
@@ -0,0 +1,309 @@
+# 杞繍浠诲姟鍙栨秷鍘熷洜鍔熻兘瀹炵幇璇存槑
+
+## 涓�銆佸姛鑳芥杩�
+
+涓鸿浆杩愪换鍔″鍔犲彇娑堝師鍥犺褰曞姛鑳�,褰撶敤鎴峰彇娑堜换鍔℃椂,闇�瑕侀�夋嫨鍙栨秷鍘熷洜骞惰褰曞彇娑堜汉鍜屽彇娑堟椂闂淬��
+
+## 浜屻�佹暟鎹簱鍙樻洿
+
+### 2.1 sys_task_emergency琛ㄥ鍔犱笁涓瓧娈�
+
+鎵цSQL鑴氭湰锛歚sql/add_cancel_reason_fields.sql`
+
+```sql
+ALTER TABLE sys_task_emergency 
+ADD COLUMN cancel_reason VARCHAR(50) COMMENT '鍙栨秷鍘熷洜锛堝叧鑱旀暟鎹瓧鍏竧ask_cancel_reason锛�';
+
+ALTER TABLE sys_task_emergency 
+ADD COLUMN cancel_by VARCHAR(64) COMMENT '鍙栨秷浜�';
+
+ALTER TABLE sys_task_emergency 
+ADD COLUMN cancel_time DATETIME COMMENT '鍙栨秷鏃堕棿';
+```
+
+### 2.2 鏁版嵁瀛楀吀閰嶇疆
+
+鎵цSQL鑴氭湰锛歚sql/insert_dict_task_cancel_reason.sql`
+
+娣诲姞鏁版嵁瀛楀吀绫诲瀷 `task_cancel_reason`锛屽寘鍚�26涓彇娑堝師鍥犻�夐」锛�
+
+1. 浠锋牸涓嶆帴鍙�
+2. 鏃堕棿绱ф��
+3. 鍑鸿溅閫熷害鎱�
+4. 閫夋嫨鍏朵粬杞�
+5. 鐥呬汉娌℃湁鐢熷懡浣撳緛
+6. 鍖荤敓鎶ゅ+鍧囦笉瓒�
+7. 鐥呬汉鎯呭喌鏈夊彉
+8. 鍏朵粬
+9. 绗笁鏂瑰彇娑�
+10. 娴嬭瘯璁㈠崟
+11. 浼犳煋鎬х柧鐥�
+12. 瀹跺睘鎸傛満/鎷掓帴/涓嶆帴鐢佃瘽
+13. 鎶ゅ+涓嶈冻
+14. 鍖荤敓涓嶈冻
+15. 璁惧涓嶈冻锛堝懠鍚告満锛�
+16. 瀹跺睘娌¤仈绯诲ソ搴婁綅
+17. 绉讳氦鍒嗘敮鏈烘瀯鎵ц
+18. 绉讳氦鍔炰簨澶勶紙婀涙睙锛�
+19. 绉讳氦鍔炰簨澶勶紙鑼傚悕锛�
+20. 瀹跺睘涓嶈偗閫忛湶淇℃伅
+21. 鎵�鍦ㄥ尰闄�/鐩殑鍦板尰闄㈡淳杞�
+22. 鑷┚杞︽帴閫佹偅鑰�
+23. 閫夋嫨鍏朵粬鏈烘瀯杞﹁締
+24. 澶栬仈閫氱煡鍙栨秷
+25. 澶栬仈鏃犲弽棣�
+26. 瀹跺睘鏃犲師鍥犵洿鎺ュ憡鐭ュ彇娑�
+
+## 涓夈�佸悗绔慨鏀�
+
+### 3.1 瀹炰綋绫讳慨鏀�
+
+**鏂囦欢**: `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java`
+
+娣诲姞涓変釜瀛楁灞炴�э細
+- `private String cancelReason;` - 鍙栨秷鍘熷洜
+- `private String cancelBy;` - 鍙栨秷浜�  
+- `private java.util.Date cancelTime;` - 鍙栨秷鏃堕棿
+
+### 3.2 Mapper XML淇敼
+
+**鏂囦欢**: `ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml`
+
+鍦╜resultMap`銆乣selectSysTaskEmergencyVo`銆乣insertSysTaskEmergency`銆乣updateSysTaskEmergency`涓坊鍔犱笁涓瓧娈电殑鏄犲皠鍜屽鐞嗐��
+
+### 3.3 鎺у埗鍣ㄤ慨鏀�
+
+**鏂囦欢**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java`
+
+#### 3.3.1 ChangeStatusRequest澧炲姞瀛楁
+
+```java
+private String cancelReason;  // 鍙栨秷鍘熷洜锛堝叧鑱旀暟鎹瓧鍏竧ask_cancel_reason锛�
+```
+
+#### 3.3.2 淇敼appChangeTaskStatus鏂规硶
+
+鍦ㄧ姸鎬佸彉鏇存柟娉曚腑娣诲姞鍙栨秷鍘熷洜澶勭悊閫昏緫锛�
+
+```java
+// 濡傛灉鏄彇娑堢姸鎬侊紝淇濆瓨鍙栨秷鍘熷洜
+if (newStatus == TaskStatus.CANCELLED && StringUtils.isNotEmpty(request.getCancelReason())) {
+    sysTaskService.saveCancelInfo(taskId, request.getCancelReason());
+}
+```
+
+### 3.4 鏈嶅姟灞備慨鏀�
+
+**鏂囦欢**: `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java`
+
+娣诲姞鎺ュ彛鏂规硶锛�
+
+```java
+/**
+ * 淇濆瓨浠诲姟鍙栨秷淇℃伅锛堜粎闄愯浆杩愪换鍔★級
+ * 
+ * @param taskId 浠诲姟ID
+ * @param cancelReason 鍙栨秷鍘熷洜锛堟暟鎹瓧鍏竧ask_cancel_reason鐨剉alue锛�
+ * @return 缁撴灉
+ */
+public int saveCancelInfo(Long taskId, String cancelReason);
+```
+
+**鏂囦欢**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java`
+
+瀹炵幇saveCancelInfo鏂规硶锛屼繚瀛樺彇娑堝師鍥犮�佸彇娑堜汉鍜屽彇娑堟椂闂达細
+
+```java
+@Override
+@Transactional
+public int saveCancelInfo(Long taskId, String cancelReason) {
+    // 鑾峰彇浠诲姟淇℃伅
+    SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
+    if (task == null) {
+        throw new RuntimeException("浠诲姟涓嶅瓨鍦�");
+    }
+    
+    // 鍙湁杞繍浠诲姟鎵嶄繚瀛樺彇娑堜俊鎭�
+    if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+        return 0;
+    }
+    
+    // 鑾峰彇杞繍浠诲姟鎵╁睍淇℃伅
+    SysTaskEmergency emergency = sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
+    if (emergency == null) {
+        return 0;
+    }
+    
+    // 璁剧疆鍙栨秷淇℃伅
+    emergency.setCancelReason(cancelReason);
+    emergency.setCancelBy(SecurityUtils.getUsername());
+    emergency.setCancelTime(DateUtils.getNowDate());
+    emergency.setUpdateBy(SecurityUtils.getUsername());
+    emergency.setUpdateTime(DateUtils.getNowDate());
+    
+    // 鏇存柊鏁版嵁搴�
+    return sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
+}
+```
+
+## 鍥涖�佸墠绔慨鏀�
+
+### 4.1 浠诲姟璇︽儏椤典慨鏀�
+
+**鏂囦欢**: `app/pagesTask/detail.vue`
+
+#### 4.1.1 data涓坊鍔犲瓧娈�
+
+```javascript
+data() {
+  return {
+    taskDetail: null,
+    taskId: null,
+    paymentInfo: null,
+    cancelReasonList: [],      // 鍙栨秷鍘熷洜鍒楄〃
+    showCancelDialog: false,   // 鏄剧ず鍙栨秷鍘熷洜瀵硅瘽妗�
+    selectedCancelReason: ''   // 閫変腑鐨勫彇娑堝師鍥�
+  }
+}
+```
+
+#### 4.1.2 onLoad涓姞杞藉瓧鍏�
+
+```javascript
+onLoad(options) {
+  this.taskId = options.id
+  this.loadTaskDetail()
+  this.loadCancelReasonDict() // 鍔犺浇鍙栨秷鍘熷洜瀛楀吀
+}
+```
+
+#### 4.1.3 淇敼鍙栨秷鎸夐挳澶勭悊閫昏緫
+
+```javascript
+case 'cancel':
+  // 鍙栨秷 -> 鏄剧ず鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗�
+  this.showCancelReasonDialog();
+  break;
+```
+
+#### 4.1.4 娣诲姞鏂规硶
+
+- `loadCancelReasonDict()` - 浠庡悗绔姞杞藉彇娑堝師鍥犲瓧鍏�
+- `showCancelReasonDialog()` - 鏄剧ず鍙栨秷鍘熷洜閫夋嫨寮圭獥
+- `confirmCancelTask()` - 纭鍙栨秷浠诲姟
+- `closeCancelDialog()` - 鍏抽棴鍙栨秷寮圭獥
+- `selectCancelReason(e)` - 閫夋嫨鍙栨秷鍘熷洜
+- `updateTaskStatusWithCancelReason()` - 甯﹀彇娑堝師鍥犵殑鐘舵�佹洿鏂�
+- `getCancelReasonLabel()` - 鏍规嵁value鑾峰彇label鏄剧ず
+
+#### 4.1.5 淇敼getLocationAndUpdateStatus鏂规硶
+
+娣诲姞cancelReason鍙傛暟锛屽湪鐘舵�佹洿鏂拌姹備腑浼犻�掑彇娑堝師鍥狅細
+
+```javascript
+// 濡傛灉鏈夊彇娑堝師鍥狅紝娣诲姞鍒拌姹傛暟鎹腑
+if (cancelReason) {
+  statusData.cancelReason = cancelReason
+}
+```
+
+#### 4.1.6 娣诲姞UI缁勪欢
+
+**鍙栨秷鍘熷洜閫夋嫨寮圭獥**锛�
+
+```vue
+<uni-popup ref="cancelPopup" type="center" :is-mask-click="false">
+  <view class="cancel-dialog">
+    <view class="dialog-title">璇烽�夋嫨鍙栨秷鍘熷洜</view>
+    <picker mode="selector" :range="cancelReasonList" range-key="label" @change="selectCancelReason">
+      <view class="reason-picker">
+        <view class="picker-label">鍙栨秷鍘熷洜</view>
+        <view class="picker-value">
+          {{ selectedCancelReason ? cancelReasonList.find(r => r.value === selectedCancelReason)?.label : '璇烽�夋嫨' }}
+        </view>
+        <uni-icons type="arrowright" size="16"></uni-icons>
+      </view>
+    </picker>
+    <view class="dialog-buttons">
+      <button class="cancel-btn" @click="closeCancelDialog">鍙栨秷</button>
+      <button class="confirm-btn" @click="confirmCancelTask">纭畾</button>
+    </view>
+  </view>
+</uni-popup>
+```
+
+**鍙栨秷淇℃伅鏄剧ず鍖哄煙**锛堜粎鍦ㄤ换鍔″凡鍙栨秷涓旀湁鍙栨秷鍘熷洜鏃舵樉绀猴級锛�
+
+```vue
+<view class="detail-section" v-if="taskDetail.taskStatus === 'CANCELLED' && taskDetail.emergencyInfo && taskDetail.emergencyInfo.cancelReason">
+  <view class="section-title">鍙栨秷淇℃伅</view>
+  <view class="info-item">
+    <view class="label">鍙栨秷鍘熷洜</view>
+    <view class="value">{{ getCancelReasonLabel(taskDetail.emergencyInfo.cancelReason) }}</view>
+  </view>
+  <view class="info-item" v-if="taskDetail.emergencyInfo.cancelBy">
+    <view class="label">鍙栨秷浜�</view>
+    <view class="value">{{ taskDetail.emergencyInfo.cancelBy }}</view>
+  </view>
+  <view class="info-item" v-if="taskDetail.emergencyInfo.cancelTime">
+    <view class="label">鍙栨秷鏃堕棿</view>
+    <view class="value">{{ formatTime(taskDetail.emergencyInfo.cancelTime) }}</view>
+  </view>
+</view>
+```
+
+#### 4.1.7 娣诲姞鏍峰紡
+
+涓哄彇娑堝師鍥犲脊绐楁坊鍔犳牱寮忥紝鍖呮嫭瀵硅瘽妗嗐�侀�夋嫨鍣ㄥ拰鎸夐挳鏍峰紡銆�
+
+## 浜斻�佷娇鐢ㄦ祦绋�
+
+### 5.1 鍙栨秷浠诲姟娴佺▼
+
+1. 鐢ㄦ埛鍦ㄤ换鍔¤鎯呴〉鐐瑰嚮"鍙栨秷"鎸夐挳
+2. 绯荤粺寮瑰嚭鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗�
+3. 鐢ㄦ埛浠�26涓璁鹃�夐」涓�夋嫨鍙栨秷鍘熷洜
+4. 鐢ㄦ埛鐐瑰嚮"纭畾"鎸夐挳
+5. 绯荤粺璋冪敤鐘舵�佹洿鏂版帴鍙o紝浼犻�掑彇娑堝師鍥�
+6. 鍚庣淇濆瓨鍙栨秷鍘熷洜銆佸彇娑堜汉锛堝綋鍓嶇敤鎴凤級鍜屽彇娑堟椂闂达紙褰撳墠鏃堕棿锛�
+7. 浠诲姟鐘舵�佸彉鏇翠负"宸插彇娑�"
+
+### 5.2 鏌ョ湅鍙栨秷淇℃伅
+
+鍦ㄤ换鍔¤鎯呴〉锛屽鏋滀换鍔$姸鎬佷负"宸插彇娑�"涓旇褰曚簡鍙栨秷鍘熷洜锛屼細鍦ㄨ垂鐢ㄤ俊鎭笅鏂规樉绀�"鍙栨秷淇℃伅"鍖哄潡锛屽寘鎷細
+- 鍙栨秷鍘熷洜锛堟樉绀轰腑鏂囨爣绛撅級
+- 鍙栨秷浜�
+- 鍙栨秷鏃堕棿
+
+## 鍏�佹敞鎰忎簨椤�
+
+1. **浠呴檺杞繍浠诲姟**锛氬彇娑堝師鍥犲姛鑳戒粎瀵硅浆杩愪换鍔★紙EMERGENCY_TRANSFER锛夌敓鏁�
+2. **寮哄埗閫夋嫨**锛氬彇娑堜换鍔℃椂蹇呴』閫夋嫨鍙栨秷鍘熷洜锛屽惁鍒欐棤娉曟彁浜�
+3. **鑷姩璁板綍**锛氬彇娑堜汉鍜屽彇娑堟椂闂寸敱绯荤粺鑷姩璁板綍锛屾棤闇�鐢ㄦ埛杈撳叆
+4. **涓嶅彲淇敼**锛氬彇娑堜俊鎭竴鏃︿繚瀛樹笉鍙慨鏀�
+5. **鏁版嵁瀛楀吀渚濊禆**锛氶渶瑕佸厛鎵ц鏁版嵁瀛楀吀SQL鑴氭湰锛屽惁鍒欏墠绔棤娉曞姞杞藉彇娑堝師鍥犲垪琛�
+
+## 涓冦�佹枃浠舵竻鍗�
+
+### SQL鏂囦欢
+- `sql/add_cancel_reason_fields.sql` - 娣诲姞鏁版嵁搴撳瓧娈�
+- `sql/insert_dict_task_cancel_reason.sql` - 鎻掑叆鏁版嵁瀛楀吀
+
+### 鍚庣鏂囦欢
+- `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java`
+- `ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml`
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java`
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java`
+- `ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java`
+
+### 鍓嶇鏂囦欢
+- `app/pagesTask/detail.vue`
+
+## 鍏�佹祴璇曞缓璁�
+
+1. 娴嬭瘯鍙栨秷鍘熷洜寮圭獥鏄惁姝e父鏄剧ず
+2. 娴嬭瘯閫夋嫨涓嶅悓鍙栨秷鍘熷洜鍚庢槸鍚︽纭繚瀛�
+3. 娴嬭瘯鏈�夋嫨鍙栨秷鍘熷洜鏃舵槸鍚﹂樆姝㈡彁浜�
+4. 娴嬭瘯鍙栨秷淇℃伅鏄惁姝g‘鏄剧ず
+5. 娴嬭瘯闈炶浆杩愪换鍔$偣鍑诲彇娑堟槸鍚︽甯革紙涓嶅簲鏄剧ず鍙栨秷鍘熷洜寮圭獥锛�
+6. 娴嬭瘯宸插彇娑堢殑浠诲姟鏄惁姝g‘鏄剧ず鍙栨秷淇℃伅

--
Gitblit v1.9.1