From 09e6dc3fb7266620fafb5e341808a8eb36e080a1 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期六, 13 十二月 2025 22:51:52 +0800
Subject: [PATCH] feat:增加企业微信消息提醒

---
 ruoyi-system/src/main/java/com/ruoyi/system/service/INotifySendLogService.java               |   29 
 ruoyi-system/src/main/java/com/ruoyi/system/service/INotifyDispatchService.java              |    8 
 sql/sys_notify_task.sql                                                                      |    3 
 ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml                     |   22 
 sql/sys_task_emergency.sql                                                                   |    6 
 ruoyi-ui/src/api/system/qywechat/index.js                                                    |   43 
 sql/notify_menu.sql                                                                          |   18 
 sql/qy_wechat_config.sql                                                                     |   19 
 ruoyi-ui/src/views/system/notify/log/index.vue                                               |   14 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java                          |   14 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java  |  291 ++---
 sql/update_sys_task_emergency.sql                                                            |   19 
 sql/ry_20250417.sql                                                                          |   12 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifyDispatchServiceImpl.java      |   54 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java                  |   28 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java                     |   12 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QyWechatAccessTokenServiceImpl.java |  285 +++++
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotifySendLogMapper.java                  |    4 
 sql/notify_dict.sql                                                                          |    3 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java                              |   22 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java           |   41 
 ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml                   |  117 ++
 ruoyi-ui/src/views/system/notify/channelConfig.vue                                           |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QyWechatServiceImpl.java            |  431 +++++++
 app/pages/index.vue                                                                          |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java                |  155 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/QyWechatArticle.java                      |   78 +
 ruoyi-ui/src/api/system/qywechat/test.js                                                     |    0 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java               |   20 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysEmergencyTaskServiceImpl.java    |   52 
 ruoyi-ui/src/views/task/general/detail.vue                                                   |   18 
 ruoyi-system/src/main/java/com/ruoyi/system/service/IQyWechatService.java                    |   46 
 app/pages/task/index.vue                                                                     |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifySendLog.java                        |   12 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/sms/NotifyController.java                 |   34 
 sql/add_qy_wechat_user_id_to_sys_user.sql                                                    |   11 
 ruoyi-ui/src/views/task/general/index.vue                                                    |   26 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysEmergencyTaskService.java            |    1 
 app/pagesTask/detail.vue                                                                     |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java             |   17 
 sql/update_sys_task_emergency_add_service_ord_class.sql                                      |    8 
 ruoyi-admin/src/main/resources/application-dev.yml                                           |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java                      |   49 
 ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml                              |   11 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifySendLogServiceImpl.java       |   44 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/QyWechatUserSyncTask.java                   |   68 +
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java                   |    9 
 ruoyi-system/src/main/java/com/ruoyi/system/service/IQyWechatAccessTokenService.java         |   35 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java                     |   81 +
 ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml                             |    2 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/QyWechatTestController.java        |  141 ++
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java            |   13 
 ruoyi-ui/src/views/system/qywechat/index.vue                                                 |   18 
 sql/sys_notify_send_log.sql                                                                  |    3 
 ruoyi-system/src/main/java/com/ruoyi/system/event/TaskServiceOrderSyncEvent.java             |   16 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java    |  188 +++
 ruoyi-common/src/main/java/com/ruoyi/common/utils/MapValueUtils.java                         |  142 ++
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java             |  114 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifyChannelConfig.java                  |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/event/TaskDispatchSyncEvent.java                 |   27 
 ruoyi-ui/src/views/system/qywechat/test.vue                                                  |  226 ++++
 ruoyi-system/src/main/resources/mapper/system/NotifySendLogMapper.xml                        |    7 
 sql/qy_wechat_sync_job.sql                                                                   |   86 +
 63 files changed, 2,942 insertions(+), 326 deletions(-)

diff --git a/app/pages/index.vue b/app/pages/index.vue
index 556f5aa..e458aba 100644
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -124,7 +124,7 @@
 
             <!-- 浠诲姟缂栧彿鍗曠嫭涓�琛� -->
             <view class="task-code-row">
-              <text class="task-code">{{ task.taskNo }}</text>
+              <text class="task-code">{{ task.showTaskCode }}</text>
             </view>
 
             <!-- 浠诲姟璇︾粏淇℃伅 -->
diff --git a/app/pages/task/index.vue b/app/pages/task/index.vue
index cf1dbff..c1b7a0d 100644
--- a/app/pages/task/index.vue
+++ b/app/pages/task/index.vue
@@ -120,7 +120,7 @@
               
               <!-- 浠诲姟缂栧彿鍗曠嫭涓�琛� -->
               <view class="task-code-row">
-                <text class="task-code">{{ task.taskCode }}</text>
+                <text class="task-code">{{ task.showTaskCode }}</text>
               </view>
               
               <!-- 浠诲姟璇︾粏淇℃伅 -->
@@ -297,7 +297,7 @@
         // 搴旂敤浠诲姟缂栧彿绛涢�� - 浣跨敤taskCode鑰屼笉鏄痶askNo
         if (this.searchForm.taskNo) {
           filtered = filtered.filter(task => 
-            task.taskCode && task.taskCode.includes(this.searchForm.taskNo)
+            task.showTaskCode && task.showTaskCode.includes(this.searchForm.taskNo)
           );
         }
         
diff --git a/app/pagesTask/detail.vue b/app/pagesTask/detail.vue
index 0006bca..022152d 100644
--- a/app/pagesTask/detail.vue
+++ b/app/pagesTask/detail.vue
@@ -12,7 +12,7 @@
         <view class="section-title">鍩烘湰淇℃伅</view>
         <view class="info-item">
           <view class="label">浠诲姟缂栧彿</view>
-          <view class="value">{{ taskDetail.taskCode }}</view>
+          <view class="value">{{ taskDetail.showTaskCode }}</view>
         </view>
         <view class="info-item">
           <view class="label">浠诲姟绫诲瀷</view>
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sms/NotifyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sms/NotifyController.java
index 9520acc..7aebd33 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sms/NotifyController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sms/NotifyController.java
@@ -1,14 +1,14 @@
 package com.ruoyi.web.controller.sms;
 
 import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.service.IQyWechatService;
+import com.ruoyi.system.service.ISysTaskService;
 import com.ruoyi.system.service.IWechatTaskNotifyService;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 
@@ -19,6 +19,12 @@
 
     @Autowired
     private IWechatTaskNotifyService wechatTaskNotifyService;
+
+    @Autowired
+    private IQyWechatService qyWechatService;
+
+    @Autowired
+    private ISysTaskService taskService;
     @Anonymous
     @PostMapping("/sendWeiXin")
     public String notify(@RequestBody @Validated SendTaskReq req) {
@@ -28,4 +34,24 @@
         System.out.println(result);
         return "success";
     }
+
+    @Anonymous()
+    @GetMapping("/dispatchSyncEvent")
+    public Boolean dispatchSyncEvent(@RequestParam Long taskId) {
+        return taskService.dispatchSyncEvent(taskId);
+    }
+
+    @Anonymous()
+    @PostMapping("sendQyWeiXin")
+    public String sendQyWeiXin(@RequestBody @Validated SendTaskReq req) {
+
+
+        String title="鍖荤枟杩愯浆鍗曟淳閫�";
+        String content="鎮ㄦ湁鏂扮殑鍖荤枟杩愯浆鍗曟淳閫侊紝璇峰強鏃跺鐞�";
+        String notifyUrl="https://sys.966120.com.cn/m_DispatchOrder.gds?dispatchId=102311";
+        java.lang.Boolean result =qyWechatService.sendNotifyMessage(req.getUserId(), title,content,notifyUrl);
+        System.out.println(result);
+        return "success";
+
+    }
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/QyWechatTestController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/QyWechatTestController.java
new file mode 100644
index 0000000..8e131f8
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/QyWechatTestController.java
@@ -0,0 +1,141 @@
+package com.ruoyi.web.controller.system;
+
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.service.IQyWechatAccessTokenService;
+import com.ruoyi.system.service.IQyWechatService;
+import com.ruoyi.system.service.ISysConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 浼佷笟寰俊娴嬭瘯鎺у埗鍣�
+ * 鐢ㄤ簬娴嬭瘯浼佷笟寰俊AccessToken鑾峰彇鍜屾秷鎭彂閫佸姛鑳�
+ * 
+ * @author ruoyi
+ * @date 2025-12-11
+ */
+@Anonymous()
+@RestController
+@RequestMapping("/system/qywechat/test")
+public class QyWechatTestController extends BaseController {
+
+    @Autowired
+    private IQyWechatAccessTokenService qyWechatAccessTokenService;
+
+    @Autowired
+    private IQyWechatService qyWechatService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    /**
+     * 娴嬭瘯鑾峰彇浼佷笟寰俊AccessToken
+     */
+    @Anonymous()
+    @GetMapping("/token")
+    public AjaxResult testGetToken() {
+        try {
+            String corpId = configService.selectConfigByKey("qy_wechat.corp_id");
+            String corpSecret = configService.selectConfigByKey("qy_wechat.corp_secret");
+
+            if (corpId == null || corpSecret == null) {
+                return AjaxResult.error("浼佷笟寰俊閰嶇疆涓嶅畬鏁达紝璇锋鏌orp_id鍜宑orp_secret閰嶇疆");
+            }
+
+            String accessToken = qyWechatAccessTokenService.getAppAccessToken(corpId, corpSecret);
+            
+            if (accessToken != null) {
+                return AjaxResult.success("鑾峰彇AccessToken鎴愬姛", accessToken);
+            } else {
+                return AjaxResult.error("鑾峰彇AccessToken澶辫触");
+            }
+        } catch (Exception e) {
+            return AjaxResult.error("鑾峰彇AccessToken寮傚父锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 娴嬭瘯鍒锋柊浼佷笟寰俊AccessToken
+     */
+    @Anonymous()
+    @PostMapping("/refreshToken")
+    public AjaxResult testRefreshToken() {
+        try {
+            String corpId = configService.selectConfigByKey("qy_wechat.corp_id");
+            String corpSecret = configService.selectConfigByKey("qy_wechat.corp_secret");
+
+            if (corpId == null || corpSecret == null) {
+                return AjaxResult.error("浼佷笟寰俊閰嶇疆涓嶅畬鏁达紝璇锋鏌orp_id鍜宑orp_secret閰嶇疆");
+            }
+
+            String accessToken = qyWechatAccessTokenService.refreshAppAccessToken(corpId, corpSecret);
+            
+            if (accessToken != null) {
+                return AjaxResult.success("鍒锋柊AccessToken鎴愬姛", accessToken);
+            } else {
+                return AjaxResult.error("鍒锋柊AccessToken澶辫触");
+            }
+        } catch (Exception e) {
+            return AjaxResult.error("鍒锋柊AccessToken寮傚父锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 娴嬭瘯鍙戦�佷紒涓氬井淇℃秷鎭�
+     */
+    @Anonymous()
+    @PostMapping("/sendMessage")
+    public AjaxResult testSendMessage(@RequestParam Long userId, 
+                                     @RequestParam String title, 
+                                     @RequestParam String content,@RequestParam String notifyUrl) {
+        try {
+            boolean result = qyWechatService.sendNotifyMessage(userId, title, content,notifyUrl);
+            
+            if (result) {
+                return AjaxResult.success("鍙戦�佷紒涓氬井淇℃秷鎭垚鍔�");
+            } else {
+                return AjaxResult.error("鍙戦�佷紒涓氬井淇℃秷鎭け璐�");
+            }
+        } catch (Exception e) {
+            return AjaxResult.error("鍙戦�佷紒涓氬井淇℃秷鎭紓甯革細" + e.getMessage());
+        }
+    }
+
+    /**
+     * 娴嬭瘯鍙戦�佷紒涓氬井淇℃枃鏈秷鎭�
+     */
+    @Anonymous()
+    @PostMapping("/sendTextMessage")
+    public AjaxResult testSendTextMessage(@RequestParam String qyUserId, 
+                                         @RequestParam String title, 
+                                         @RequestParam String content, 
+                                         @RequestParam String notifyUrl) {
+        try {
+            boolean result = qyWechatService.sendTextMessage(qyUserId, title, content, notifyUrl);
+            
+            if (result) {
+                return AjaxResult.success("鍙戦�佷紒涓氬井淇℃枃鏈秷鎭垚鍔�");
+            } else {
+                return AjaxResult.error("鍙戦�佷紒涓氬井淇℃枃鏈秷鎭け璐�");
+            }
+        } catch (Exception e) {
+            return AjaxResult.error("鍙戦�佷紒涓氬井淇℃枃鏈秷鎭紓甯革細" + e.getMessage());
+        }
+    }
+
+    /**
+     * 妫�鏌ヤ紒涓氬井淇℃湇鍔℃槸鍚﹀惎鐢�
+     */
+    @Anonymous()
+    @GetMapping("/enabled")
+    public AjaxResult checkEnabled() {
+        try {
+            boolean enabled = qyWechatService.isEnabled();
+            return AjaxResult.success("浼佷笟寰俊鏈嶅姟鐘舵�侊細" + (enabled ? "鍚敤" : "绂佺敤"), enabled);
+        } catch (Exception e) {
+            return AjaxResult.error("妫�鏌ヤ紒涓氬井淇℃湇鍔$姸鎬佸紓甯革細" + e.getMessage());
+        }
+    }
+}
\ 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 4181398..3260878 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
@@ -4,6 +4,8 @@
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.system.domain.SysTaskEmergency;
 import com.ruoyi.system.service.*;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -47,6 +49,9 @@
     
     @Autowired
     private ISysTaskService sysTaskService;
+
+    @Autowired
+    private ISysTaskEmergencyService sysTaskEmergencyService;
     
     @Autowired
     private IVehicleInfoService vehicleInfoService;
@@ -70,7 +75,18 @@
     @GetMapping("/admin/list")
     public TableDataInfo adminList(TaskQueryVO queryVO) {
         startPage();
-        List<SysTask> list = sysTaskService.selectSysTaskList(queryVO);
+        // Handle multi-field task code search
+        String searchTaskCode = queryVO.getTaskCode();
+        List<SysTask> list;
+        if(searchTaskCode != null && !searchTaskCode.trim().isEmpty()){
+            // Search across task_code, emergency_info.dispatch_code, and emergency_info.service_code
+            list = sysTaskService.selectSysTaskListByMultiCode(queryVO, searchTaskCode);
+        } else {
+            queryVO.setTaskCode(null);
+            list = sysTaskService.selectSysTaskList(queryVO);
+        }
+
+
         return getDataTable(list);
     }
 
@@ -167,6 +183,8 @@
         return toAjax(sysTaskService.insertSysTask(createVO));
     }
 
+
+
     /**
      * 鏂板浠诲姟锛圓PP绔級
      */
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index be0ae20..f0a97bc 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -98,6 +98,10 @@
   appId: wx70f6a7346ee842c0
   appSecret: 2d6c59de85e876b7eadebeba62e5417a
   redirectUri: http://yourdomain.com/evaluation
+# 浼佷笟寰俊閰嶇疆
+qyWeixin:
+  appId: wx248505bfbab6d0c1
+  appSecret: 2MCilqWYC0FWjOQ894sbb-s7Lb5sVH4HHuJgOsd9l1k
 # 璋冨害鐢ㄧ殑weixin閰嶇疆
 transferConfigWeixin:
   appId: wx40692cc44953a8cb
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
index b08d680..36ca34a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -104,6 +104,12 @@
     /** 寰俊鏄电О */
     private String wechatNickname;
     
+    /** 浼佷笟寰俊鐢ㄦ埛ID */
+    private String qyWechatUserId;
+    
+    /** 浼佷笟寰俊鐢ㄦ埛ID鏇存柊鏃堕棿 */
+    private Date qyWechatUpdateTime;
+    
     /** 鏄惁鍙煡鐪嬫墍鏈夊挩璇㈠崟锛�0鍚� 1鏄級 */
     @Excel(name = "鍙煡鐪嬫墍鏈夊挩璇㈠崟", readConverterExp = "0=鍚�,1=鏄�")
     private String canViewAllConsult;
@@ -368,6 +374,26 @@
         this.wechatNickname = wechatNickname;
     }
     
+    public String getQyWechatUserId()
+    {
+        return qyWechatUserId;
+    }
+    
+    public void setQyWechatUserId(String qyWechatUserId)
+    {
+        this.qyWechatUserId = qyWechatUserId;
+    }
+    
+    public Date getQyWechatUpdateTime()
+    {
+        return qyWechatUpdateTime;
+    }
+    
+    public void setQyWechatUpdateTime(Date qyWechatUpdateTime)
+    {
+        this.qyWechatUpdateTime = qyWechatUpdateTime;
+    }
+    
     public String getCanViewAllConsult()
     {
         return canViewAllConsult;
@@ -406,6 +432,8 @@
             .append("openId", getOpenId())
             .append("unionId", getUnionId())
             .append("wechatNickname", getWechatNickname())
+            .append("qyWechatUserId", getQyWechatUserId())
+            .append("qyWechatUpdateTime", getQyWechatUpdateTime())
             .append("canViewAllConsult", getCanViewAllConsult())
 
             .toString();
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MapValueUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MapValueUtils.java
new file mode 100644
index 0000000..212e79d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MapValueUtils.java
@@ -0,0 +1,142 @@
+package com.ruoyi.common.utils;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.Map;
+
+import com.ruoyi.common.utils.DateUtils;
+
+/**
+ * Map鍊艰浆鎹㈠伐鍏风被
+ * 鎻愪緵浠嶮ap涓畨鍏ㄨ幏鍙栧悇绉嶇被鍨嬪�肩殑鏂规硶
+ * 
+ * @author ruoyi
+ */
+public class MapValueUtils {
+
+    /**
+     * 浠嶮ap涓幏鍙栧瓧绗︿覆鍊�
+     * 
+     * @param map Map瀵硅薄
+     * @param key 閿�
+     * @return 瀛楃涓插�硷紝濡傛灉閿笉瀛樺湪鎴栧�间负null鍒欒繑鍥瀗ull
+     */
+    public static String getStringValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        return value != null ? value.toString() : null;
+    }
+    
+    /**
+     * 浠嶮ap涓幏鍙朆igDecimal鍊�
+     * 
+     * @param map Map瀵硅薄
+     * @param key 閿�
+     * @return BigDecimal鍊硷紝濡傛灉閿笉瀛樺湪鎴栧�间负null鍒欒繑鍥瀗ull锛岃浆鎹㈠け璐ヤ篃杩斿洖null
+     */
+    public static BigDecimal getBigDecimalValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+        try {
+            return new BigDecimal(value.toString());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+    
+    /**
+     * 浠嶮ap涓幏鍙朙ong鍊�
+     * 
+     * @param map Map瀵硅薄
+     * @param key 閿�
+     * @return Long鍊硷紝濡傛灉閿笉瀛樺湪鎴栧�间负null鍒欒繑鍥瀗ull锛岃浆鎹㈠け璐ヤ篃杩斿洖null
+     */
+    public static Long getLongValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Long) {
+            return (Long) value;
+        }
+        try {
+            return Long.valueOf(value.toString());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+    
+    /**
+     * 浠嶮ap涓幏鍙朓nteger鍊�
+     * 
+     * @param map Map瀵硅薄
+     * @param key 閿�
+     * @return Integer鍊硷紝濡傛灉閿笉瀛樺湪鎴栧�间负null鍒欒繑鍥瀗ull锛岃浆鎹㈠け璐ヤ篃杩斿洖null
+     */
+    public static Integer getIntegerValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        try {
+            return Integer.valueOf(value.toString());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+    
+    /**
+     * 浠嶮ap涓幏鍙朌ate鍊�
+     * 
+     * @param map Map瀵硅薄
+     * @param key 閿�
+     * @return Date鍊硷紝濡傛灉閿笉瀛樺湪鎴栧�间负null鍒欒繑鍥瀗ull锛屽鏋滄槸瀛楃涓蹭細灏濊瘯瑙f瀽
+     */
+    public static Date getDateValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Date) {
+            return (Date) value;
+        }
+        // 濡傛灉鏄瓧绗︿覆锛屽皾璇曡В鏋�
+        if (value instanceof String) {
+            try {
+                return DateUtils.parseDate(value.toString());
+            } catch (Exception e) {
+                return null;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * 楠岃瘉鏃ユ湡瀛楃涓叉牸寮忔槸鍚︽湁鏁�
+     * 
+     * @param dateStr 鏃ユ湡瀛楃涓�
+     * @param format 鏃ユ湡鏍煎紡
+     * @return 鏄惁鏈夋晥
+     */
+    public static boolean isValidDateFormat(String dateStr, String format) {
+        if (StringUtils.isEmpty(dateStr)) {
+            return false;
+        }
+        
+        try {
+            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(format);
+            sdf.setLenient(false);
+            sdf.parse(dateStr);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/QyWechatUserSyncTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/QyWechatUserSyncTask.java
new file mode 100644
index 0000000..253e93c
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/QyWechatUserSyncTask.java
@@ -0,0 +1,68 @@
+package com.ruoyi.quartz.task;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.UserSyncDTO;
+import com.ruoyi.system.service.IUserSyncDataService;
+import com.ruoyi.system.service.IUserSyncService;
+import java.util.List;
+
+/**
+ * 浼佷笟寰俊鐢ㄦ埛ID鍚屾浠诲姟
+ * 
+ * 瀹氭湡鍚屾OA绯荤粺涓殑浼佷笟寰俊鐢ㄦ埛ID鍒版湰鍦扮郴缁�
+ * 
+ * @author ruoyi
+ * @date 2025-12-11
+ */
+@Component("qyWechatUserSyncTask")
+public class QyWechatUserSyncTask
+{
+    private static final Logger log = LoggerFactory.getLogger(QyWechatUserSyncTask.class);
+
+    @Autowired
+    private IUserSyncDataService userSyncDataService;
+
+    @Autowired
+    private IUserSyncService userSyncService;
+
+    /**
+     * 鍚屾浼佷笟寰俊鐢ㄦ埛ID
+     * 
+     * 浠诲姟鎵ц鏂规硶锛岀敱Quartz璋冨害鍣ㄨ皟鐢�
+     * 
+     * @return 鍚屾缁撴灉
+     */
+    public AjaxResult syncQyWechatUserIds()
+    {
+        try
+        {
+            log.info("寮�濮嬪悓姝ヤ紒涓氬井淇$敤鎴稩D...");
+
+            // 1. 浠嶴QL Server鏌ヨOA鐢ㄦ埛鏁版嵁锛堝寘鍚紒涓氬井淇$敤鎴稩D锛�
+            List<UserSyncDTO> oaUsers = userSyncDataService.getOaUsers();
+
+            if (oaUsers == null || oaUsers.isEmpty())
+            {
+                log.warn("鏈煡璇㈠埌OA鐢ㄦ埛鏁版嵁锛岃烦杩囧悓姝�");
+                return AjaxResult.warn("鏈煡璇㈠埌OA鐢ㄦ埛鏁版嵁");
+            }
+
+            log.info("浠嶰A绯荤粺鏌ヨ鍒� {} 鏉$敤鎴锋暟鎹�", oaUsers.size());
+
+            // 2. 鍚屾鍒癕ySQL鏁版嵁搴�
+            AjaxResult result = userSyncService.syncOaUsers(oaUsers);
+
+            log.info("浼佷笟寰俊鐢ㄦ埛ID鍚屾瀹屾垚: {}", result.get("msg"));
+            return result;
+        }
+        catch (Exception e)
+        {
+            log.error("鍚屾浼佷笟寰俊鐢ㄦ埛ID澶辫触", e);
+            return AjaxResult.error("鍚屾澶辫触: " + e.getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifyChannelConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifyChannelConfig.java
index 862dae5..d6b8151 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifyChannelConfig.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifyChannelConfig.java
@@ -22,6 +22,8 @@
     public static final String CHANNEL_SITE_MSG = "SITE_MSG";
     /** 娓犻亾锛欰PP鎺ㄩ�� */
     public static final String CHANNEL_APP_PUSH = "APP_PUSH";
+    /** 娓犻亾锛氫紒涓氬井淇� */
+    public static final String CHANNEL_QY_WECHAT = "QY_WECHAT";
 
     // ==================== 鍚敤鐘舵�佸父閲� ====================
     /** 鍚敤 */
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifySendLog.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifySendLog.java
index e14ee2d..17fe165 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifySendLog.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/NotifySendLog.java
@@ -49,6 +49,9 @@
     @Excel(name = "鍙戦�佺姸鎬�")
     private String sendStatus;
 
+    /** 鍙戦�佺殑鍐呭 */
+    private String sendContent;
+
     /** 鍙戦�佹椂闂� */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @Excel(name = "鍙戦�佹椂闂�", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@@ -171,6 +174,14 @@
         this.sendResult = sendResult;
     }
 
+    public String getSendContent() {
+        return sendContent;
+    }
+
+    public void setSendContent(String sendContent) {
+        this.sendContent = sendContent;
+    }
+
     public String getResponseMsg() {
         return responseMsg;
     }
@@ -199,6 +210,7 @@
                 .append("sendStatus", getSendStatus())
                 .append("sendTime", getSendTime())
                 .append("sendResult", getSendResult())
+                .append("sendContent", getSendContent())
                 .append("retryCount", getRetryCount())
                 .append("createTime", getCreateTime())
                 .append("createBy", getCreateBy())
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/QyWechatArticle.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/QyWechatArticle.java
new file mode 100644
index 0000000..091027e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/QyWechatArticle.java
@@ -0,0 +1,78 @@
+package com.ruoyi.system.domain;
+
+import java.io.Serializable;
+
+/**
+ * 浼佷笟寰俊鏂囩珷瀹炰綋绫�
+ * 
+ * @author ruoyi
+ * @date 2025-12-13
+ */
+public class QyWechatArticle implements Serializable {
+    /** 鏂囩珷鏍囬 */
+    private String title;
+    
+    /** 鏂囩珷鎻忚堪 */
+    private String description;
+    
+    /** 鐐瑰嚮鍚庤烦杞殑閾炬帴 */
+    private String url;
+    
+    /** 鍥炬枃娑堟伅鐨勫浘鐗囬摼鎺� */
+    private String picurl;
+    
+    /** 灏忕▼搴廰ppid */
+    private String appid;
+    
+    /** 灏忕▼搴忛〉闈㈣矾寰� */
+    private String pagepath;
+
+    // Getters and Setters
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getPicurl() {
+        return picurl;
+    }
+
+    public void setPicurl(String picurl) {
+        this.picurl = picurl;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getPagepath() {
+        return pagepath;
+    }
+
+    public void setPagepath(String pagepath) {
+        this.pagepath = pagepath;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java
index 5e549d6..b950aaa 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java
@@ -136,6 +136,28 @@
     /** 绂忕杞︽墿灞曚俊鎭� */
     private SysTaskWelfare welfareInfo;
 
+    private String showTaskCode;
+    public void setShowTaskCode(String showTaskCode) {
+         showTaskCode=this.showTaskCode;
+    }
+    /**
+     * 鑾峰彇鏄剧ず浠诲姟缂栧彿锛屼紭鍏堣繑鍥炴�ユ晳杞繍鐨勮皟搴﹀崟缂栧彿锛屽叾娆℃槸鏈嶅姟鍗曠紪鍙凤紝鏈�鍚庢槸浠诲姟缂栧彿
+     */
+    public String getShowTaskCode(){
+
+        if(this.emergencyInfo!=null){
+            String dispatchOrdCode=this.emergencyInfo.getDispatchCode();
+            if(dispatchOrdCode!=null){
+                return dispatchOrdCode;
+            }
+            String serviceOrdCode=this.emergencyInfo.getServiceCode();
+            if(serviceOrdCode!=null){
+                return serviceOrdCode;
+            }
+        }
+        return this.taskCode;
+    }
+
     public void setTaskId(Long taskId) {
         this.taskId = taskId;
     }
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 4d960ad..42876da 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
@@ -2,6 +2,7 @@
 
 import java.math.BigDecimal;
 import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.common.utils.DateUtils;
 
 /**
  * 鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅瀵硅薄 sys_task_emergency
@@ -135,6 +136,40 @@
     /** 鏃х郴缁烻erviceOrdNo锛堣浆杩愬崟缂栧彿锛� */
     private String legacyServiceOrdNo;
 
+    /** 鏃х郴缁熻皟搴﹀崟缂栧彿 */
+    private String legacyDispatchOrdNo;
+
+    /** 鏃х郴缁熸湇鍔¢�氱煡鏃堕棿 */
+    private java.util.Date legacyServiceNsTime;
+
+    /** 鏃х郴缁熻皟搴﹂�氱煡鏃堕棿 */
+    private java.util.Date legacyDispatchNsTime;
+
+    /** 鏃х郴缁熻皟搴﹀崟鍒嗙被 */
+    private String legacyDispatchOrdClass;
+
+    /** 鏃х郴缁熸湇鍔″崟鍒嗙被 */
+    private String legacyServiceOrdClass;
+
+    public String getServiceCode(){
+        if(this.legacyServiceOrdClass!=null && this.legacyServiceNsTime!=null && this.legacyServiceOrdNo!=null) {
+            String nstime = DateUtils.parseDateToStr(DateUtils.YYYYMMDD, this.legacyServiceNsTime);
+            return this.legacyServiceOrdClass + nstime +'-'+ this.legacyServiceOrdNo;
+        }
+        return null;
+    }
+
+    public String getDispatchCode(){
+        if(this.legacyDispatchOrdClass!=null && this.legacyDispatchNsTime!=null && this.legacyDispatchOrdNo!=null) {
+            String nstime = DateUtils.parseDateToStr(DateUtils.YYYYMMDD, this.legacyDispatchNsTime);
+            //serviceOrdNo 杩欎釜鏄暟瀛楋紝鍥哄畾3浣嶆暟 锛屽皢32锛岃浆鎴�032锛涘皢1杞垚001
+            Integer intServiceNo = Integer.valueOf(this.legacyDispatchOrdNo);
+            String ordNoStr = String.format("%03d", intServiceNo);
+            return this.legacyDispatchOrdClass + nstime + "-" + ordNoStr;
+        }else{
+            return null;
+        }
+    }
 
 
     public Long getId() {
@@ -465,6 +500,46 @@
         this.legacyServiceOrdNo = legacyServiceOrdNo;
     }
 
+    public String getLegacyDispatchOrdNo() {
+        return legacyDispatchOrdNo;
+    }
+
+    public void setLegacyDispatchOrdNo(String legacyDispatchOrdNo) {
+        this.legacyDispatchOrdNo = legacyDispatchOrdNo;
+    }
+
+    public java.util.Date getLegacyServiceNsTime() {
+        return legacyServiceNsTime;
+    }
+
+    public void setLegacyServiceNsTime(java.util.Date legacyServiceNsTime) {
+        this.legacyServiceNsTime = legacyServiceNsTime;
+    }
+
+    public java.util.Date getLegacyDispatchNsTime() {
+        return legacyDispatchNsTime;
+    }
+
+    public void setLegacyDispatchNsTime(java.util.Date legacyDispatchNsTime) {
+        this.legacyDispatchNsTime = legacyDispatchNsTime;
+    }
+
+    public String getLegacyDispatchOrdClass() {
+        return legacyDispatchOrdClass;
+    }
+
+    public void setLegacyDispatchOrdClass(String legacyDispatchOrdClass) {
+        this.legacyDispatchOrdClass = legacyDispatchOrdClass;
+    }
+
+    public String getLegacyServiceOrdClass() {
+        return legacyServiceOrdClass;
+    }
+
+    public void setLegacyServiceOrdClass(String legacyServiceOrdClass) {
+        this.legacyServiceOrdClass = legacyServiceOrdClass;
+    }
+
     @Override
     public String toString() {
         return "SysTaskEmergency{" +
@@ -475,6 +550,12 @@
                 ", hospitalInName='" + hospitalInName + '\'' +
                 ", transferDistance=" + transferDistance +
                 ", transferPrice=" + transferPrice +
+                ", legacyServiceOrdNo='" + legacyServiceOrdNo + '\'' +
+                ", legacyDispatchOrdNo='" + legacyDispatchOrdNo + '\'' +
+                ", legacyServiceNsTime=" + legacyServiceNsTime +
+                ", legacyDispatchNsTime=" + legacyDispatchNsTime +
+                ", legacyDispatchOrdClass='" + legacyDispatchOrdClass + '\'' +
+                ", legacyServiceOrdClass='" + legacyServiceOrdClass + '\'' +
                 '}';
     }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java
index d0d840c..dd344e7 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UserSyncDTO.java
@@ -11,6 +11,9 @@
     /** SQL Server涓殑OA鐢ㄦ埛ID */
     private Integer oaUserId;
 
+    /** 浼佷笟寰俊鐢ㄦ埛ID */
+    private String oaWeixinUserId;
+
     /** 鐢ㄦ埛璐﹀彿 */
     private String userName;
 
@@ -43,6 +46,16 @@
     public void setOaUserId(Integer oaUserId)
     {
         this.oaUserId = oaUserId;
+    }
+
+    public String getOaWeixinUserId()
+    {
+        return oaWeixinUserId;
+    }
+
+    public void setOaWeixinUserId(String oaWeixinUserId)
+    {
+        this.oaWeixinUserId = oaWeixinUserId;
     }
 
     public String getUserName()
@@ -130,6 +143,7 @@
     {
         return "UserSyncDTO{" +
                 "oaUserId=" + oaUserId +
+                ", oaWeixinUserId='" + oaWeixinUserId + '\'' +
                 ", userName='" + userName + '\'' +
                 ", nickName='" + nickName + '\'' +
                 ", departmentId=" + departmentId +
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 d4ec91b..7958a19 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
@@ -121,6 +121,23 @@
     /** 鐥呮儏ID鍒楄〃锛圛CD-10鐤剧梾ID鍒楄〃锛岀敤浜庡悓姝ヨ皟搴﹀崟鐨凮rdICD_ID鍙傛暟锛� */
     private List<Long> diseaseIds;
 
+    /** 鏃х郴缁熻皟搴﹀崟缂栧彿 */
+    private String legacyDispatchOrdNo;
+
+    /** 鏃х郴缁熸湇鍔¢�氱煡鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date legacyServiceNsTime;
+
+    /** 鏃х郴缁熻皟搴﹂�氱煡鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date legacyDispatchNsTime;
+
+    /** 鏃х郴缁熻皟搴﹀崟鍒嗙被 */
+    private String legacyDispatchOrdClass;
+
+    /** 鏃х郴缁熸湇鍔″崟鍒嗙被 */
+    private String legacyServiceOrdClass;
+
     private Date createTime;
 
     private  String taskStatus;
@@ -567,4 +584,36 @@
     public void setDiseaseIds(List<Long> diseaseIds) {
         this.diseaseIds = diseaseIds;
     }
+
+    public String getLegacyDispatchOrdNo() {
+        return legacyDispatchOrdNo;
+    }
+
+    public void setLegacyDispatchOrdNo(String legacyDispatchOrdNo) {
+        this.legacyDispatchOrdNo = legacyDispatchOrdNo;
+    }
+
+    public Date getLegacyServiceNsTime() {
+        return legacyServiceNsTime;
+    }
+
+    public void setLegacyServiceNsTime(Date legacyServiceNsTime) {
+        this.legacyServiceNsTime = legacyServiceNsTime;
+    }
+
+    public Date getLegacyDispatchNsTime() {
+        return legacyDispatchNsTime;
+    }
+
+    public void setLegacyDispatchNsTime(Date legacyDispatchNsTime) {
+        this.legacyDispatchNsTime = legacyDispatchNsTime;
+    }
+
+    public String getLegacyDispatchOrdClass() {
+        return legacyDispatchOrdClass;
+    }
+
+    public void setLegacyDispatchOrdClass(String legacyDispatchOrdClass) {
+        this.legacyDispatchOrdClass = legacyDispatchOrdClass;
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskDispatchSyncEvent.java b/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskDispatchSyncEvent.java
new file mode 100644
index 0000000..537cee1
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskDispatchSyncEvent.java
@@ -0,0 +1,27 @@
+package com.ruoyi.system.event;
+
+/**
+ * 浠诲姟鍚屾璋冨害鍗曟垚鍔熷悗瑙﹀彂浜嬩欢
+ */
+public class TaskDispatchSyncEvent extends TaskEvent{
+
+    private Long dispatchOrderId;
+
+    public Long getDispatchOrderId(){
+        return this.dispatchOrderId;
+    }
+    private Integer oaUserId;
+    public Integer getOaUserId(){
+        return this.oaUserId;
+    }
+    private Long serviceOrderId;
+    public Long getServiceOrderId(){
+        return this.serviceOrderId;
+    }
+    public TaskDispatchSyncEvent(Object source, Long taskId, String taskCode,Long serviceOrderId, Long dispatchOrderId,Integer oaUserId) {
+        super(source, taskId, taskCode);
+        this.dispatchOrderId=dispatchOrderId;
+        this.oaUserId=oaUserId;
+        this.serviceOrderId=serviceOrderId;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskServiceOrderSyncEvent.java b/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskServiceOrderSyncEvent.java
new file mode 100644
index 0000000..16231ef
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/event/TaskServiceOrderSyncEvent.java
@@ -0,0 +1,16 @@
+package com.ruoyi.system.event;
+
+/**
+ * 鏈嶅姟鍗曞悓姝ヤ换鍔℃垚鍔熷悗瑙﹀彂浜嬩欢
+ */
+public class TaskServiceOrderSyncEvent extends TaskEvent{
+
+    private Long serviceOrderId;
+    public Long getServiceOrderId(){
+        return this.serviceOrderId;
+    }
+    public TaskServiceOrderSyncEvent(Object source, Long taskId, String taskCode,Long serviceOrderId) {
+        super(source, taskId, taskCode);
+        this.serviceOrderId=serviceOrderId;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java b/ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java
index 629bed0..a9a1141 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java
@@ -1,5 +1,8 @@
 package com.ruoyi.system.listener;
 
+import com.ruoyi.system.domain.*;
+import com.ruoyi.system.event.TaskDispatchSyncEvent;
+import com.ruoyi.system.service.ISysTaskAssigneeService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -8,10 +11,6 @@
 import org.springframework.stereotype.Component;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.domain.SysMessage;
-import com.ruoyi.system.domain.SysTask;
-import com.ruoyi.system.domain.SysTaskEmergency;
-import com.ruoyi.system.domain.NotifyTask;
 import com.ruoyi.system.event.TaskCreatedEvent;
 import com.ruoyi.system.event.TaskAssignedEvent;
 import com.ruoyi.system.event.TaskStatusChangedEvent;
@@ -23,8 +22,12 @@
 import com.ruoyi.system.service.INotifyTaskService;
 import com.ruoyi.system.service.INotifyDispatchService;
 
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 浠诲姟娑堟伅鐩戝惉鍣�
@@ -61,6 +64,28 @@
     /** 寰呭噯澶囩姸鎬� - 鍙互鍙戦�佺煭淇¢�氱煡 */
     private static final String TASK_STATUS_PREPARING = "PREPARING";
 
+    @Autowired
+    private ISysTaskAssigneeService taskAssigneeService;
+
+    @Async
+    @EventListener
+    public void handleTaskDispatchEvent(TaskDispatchSyncEvent event) {
+        try{
+            log.info("鏀跺埌浠诲姟娲惧彂鍚屾浜嬩欢锛屼换鍔D锛歿}锛屼换鍔$紪鍙凤細{}锛屾淳鍙戝崟ID锛歿}", event.getTaskId(), event.getTaskCode(), event.getDispatchOrderId());
+            SysTask task=sysTaskMapper.selectSysTaskByTaskId(event.getTaskId());
+            SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(event.getTaskId());
+            if(emergency != null){
+               List<SysTaskAssignee> assignees=taskAssigneeService.getAssigneesByTaskId(emergency.getTaskId());
+               if(assignees!=null && !assignees.isEmpty()){
+                   List<Long> assigneeIds=assignees.stream().map(SysTaskAssignee::getUserId).collect(Collectors.toList());
+                   sendDispatchNotify(assigneeIds, task.getCreatorId(), event.getTaskId(), task.getTaskCode(), buildNotifyContent(task, emergency));
+               }
+            }
+
+        }catch (Exception ex){
+            log.error("澶勭悊浠诲姟娲惧彂鍚屾浜嬩欢澶辫触", ex);
+        }
+    }
     /**
      * 鐩戝惉浠诲姟鍒涘缓浜嬩欢
      * 
@@ -145,52 +170,8 @@
 
             // 鏋勫缓閫氱煡鍐呭
             String notifyContent = buildNotifyContent(task, emergency);
-            
-            // 鏀堕泦鍒涘缓鐨勯�氱煡浠诲姟
-            List<NotifyTask> createdTasks = new ArrayList<>();
-            
-            // 涓烘瘡涓墽琛屼汉鍒涘缓閫氱煡浠诲姟
-            for (Long assigneeId : event.getAssigneeIds()) {
-                // 鎺掗櫎鍒涘缓浜�
-                if (creatorId != null && creatorId.equals(assigneeId)) {
-                    log.debug("璺宠繃鍒涘缓浜猴紝涓嶅彂閫佷换鍔″垎閰嶉�氱煡锛寀serId={}", assigneeId);
-                    continue;
-                }
-                
-                // 鑾峰彇鎵ц浜轰俊鎭�
-                SysUser assignee = sysUserMapper.selectUserById(assigneeId);
-                if (assignee == null) {
-                    log.warn("鎵句笉鍒版墽琛屼汉淇℃伅锛岀敤鎴稩D锛歿}", assigneeId);
-                    continue;
-                }
-                
-                // 鍒涘缓閫氱煡浠诲姟锛堝甫闃查噸锛�
-                NotifyTask notifyTask = new NotifyTask();
-                notifyTask.setTaskId(event.getTaskId());
-                notifyTask.setTaskCode(event.getTaskCode());
-                notifyTask.setNotifyType(NotifyTask.NOTIFY_TYPE_TASK_ASSIGN);
-                notifyTask.setUserId(assigneeId);
-                notifyTask.setUserName(assignee.getNickName());
-                notifyTask.setUserPhone(assignee.getPhonenumber());
-                notifyTask.setTitle("浠诲姟鎺ㄩ��");
-                notifyTask.setContent(notifyContent);
-                notifyTask.setCreateBy(event.getAssignerName() != null ? event.getAssignerName() : "绯荤粺");
-                
-                NotifyTask created = notifyTaskService.createNotifyTask(notifyTask);
-                if (created != null) {
-                    createdTasks.add(created);
-                    log.info("鍒涘缓閫氱煡浠诲姟鎴愬姛锛宨d={}, userId={}", created.getId(), assigneeId);
-                } else {
-                    log.info("閫氱煡浠诲姟宸插瓨鍦紝璺宠繃锛宼askId={}, userId={}", event.getTaskId(), assigneeId);
-                }
-            }
+            this.sendDispatchNotify(event.getAssigneeIds(), creatorId, event.getTaskId(), event.getTaskCode(), notifyContent);
 
-            // 鍒嗗彂閫氱煡浠诲姟
-            if (!createdTasks.isEmpty()) {
-                int successCount = notifyDispatchService.dispatchNotifies(createdTasks);
-                log.info("閫氱煡鍒嗗彂瀹屾垚锛宼askId={}锛屽垱寤烘暟閲�={}锛屾垚鍔熸暟閲�={}", 
-                        event.getTaskId(), createdTasks.size(), successCount);
-            }
             
         } catch (Exception e) {
             log.error("澶勭悊浠诲姟鍒嗛厤浜嬩欢澶辫触", e);
@@ -198,11 +179,79 @@
     }
 
     /**
+     * 鍚戞墽琛屼汉鍙戦�佷换鍔″垎閰嶉�氱煡
+     * @param assigneeIds
+     * @param creatorId
+     * @param taskId
+     * @param taskCode
+     *
+     * @param notifyContent
+     */
+
+    private void sendDispatchNotify(List<Long> assigneeIds, Long creatorId,
+                            Long taskId,String taskCode,String notifyContent) {
+        // 鏀堕泦鍒涘缓鐨勯�氱煡浠诲姟
+
+        List<NotifyTask> createdTasks = new ArrayList<>();
+
+        // 涓烘瘡涓墽琛屼汉鍒涘缓閫氱煡浠诲姟
+        for (Long assigneeId : assigneeIds) {
+            // 鎺掗櫎鍒涘缓浜�
+            if (creatorId != null && creatorId.equals(assigneeId)) {
+                log.debug("璺宠繃鍒涘缓浜猴紝涓嶅彂閫佷换鍔″垎閰嶉�氱煡锛寀serId={}", assigneeId);
+                continue;
+            }
+
+            // 鑾峰彇鎵ц浜轰俊鎭�
+            SysUser assignee = sysUserMapper.selectUserById(assigneeId);
+            if (assignee == null) {
+                log.warn("鎵句笉鍒版墽琛屼汉淇℃伅锛岀敤鎴稩D锛歿}", assigneeId);
+                continue;
+            }
+
+            // 鍒涘缓閫氱煡浠诲姟锛堝甫闃查噸锛�
+            NotifyTask notifyTask = new NotifyTask();
+            notifyTask.setTaskId(taskId);
+            notifyTask.setTaskCode(taskCode);
+            notifyTask.setNotifyType(NotifyTask.NOTIFY_TYPE_TASK_ASSIGN);
+            notifyTask.setUserId(assigneeId);
+            notifyTask.setUserName(assignee.getNickName());
+            notifyTask.setUserPhone(assignee.getPhonenumber());
+            notifyTask.setTitle("杞繍鍗曚换鍔℃淳鍗曢�氱煡");
+            notifyTask.setContent(notifyContent);
+            notifyTask.setCreateBy( "绯荤粺");
+
+            NotifyTask created = notifyTaskService.createNotifyTask(notifyTask);
+            if (created != null) {
+                createdTasks.add(created);
+                log.info("鍒涘缓閫氱煡浠诲姟鎴愬姛锛宨d={}, userId={}", created.getId(), assigneeId);
+            } else {
+                log.info("閫氱煡浠诲姟宸插瓨鍦紝璺宠繃锛宼askId={}, userId={}", taskId, assigneeId);
+            }
+        }
+
+        // 鍒嗗彂閫氱煡浠诲姟
+        if (!createdTasks.isEmpty()) {
+            int successCount = notifyDispatchService.dispatchNotifies(createdTasks);
+            log.info("閫氱煡鍒嗗彂瀹屾垚锛宼askId={}锛屽垱寤烘暟閲�={}锛屾垚鍔熸暟閲�={}",
+                    taskId, createdTasks.size(), successCount);
+        }
+    }
+    /**
      * 鏋勫缓閫氱煡鍐呭
      */
     private String buildNotifyContent(SysTask task, SysTaskEmergency emergency) {
-        StringBuilder content = new StringBuilder("鎮ㄦ湁鏂扮殑杞繍浠诲姟锛岃鍙婃椂澶勭悊锛屼换鍔″崟鍙�:"+task.getTaskCode());
-        
+        //娲惧彂鍗曞彿
+        String dispatchCode=emergency.getDispatchCode();
+        String taskCode=task.getTaskCode();
+        String orderCode=dispatchCode;
+        if(dispatchCode==null){
+            orderCode=taskCode;
+        }
+        Date dispatchTime=task.getPlanedStartTime();
+
+        StringBuilder content = new StringBuilder();
+        content.append("鎮ㄦ湁鏂扮殑杞繍浠诲姟锛屼换鍔″崟鍙�:"+orderCode);
         // 娣诲姞鍑哄彂鍦颁俊鎭�
         String departure = null;
         if (emergency != null && StringUtils.isNotEmpty(emergency.getHospitalOutName())) {
@@ -210,7 +259,9 @@
         } else if (StringUtils.isNotEmpty(task.getDepartureAddress())) {
             departure = task.getDepartureAddress();
         }
-        
+        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+        content.append("锛屽嚭鍙戞椂闂达細").append(df.format(dispatchTime));
+
         // 娣诲姞鐩殑鍦颁俊鎭�
         String destination = null;
         if (emergency != null && StringUtils.isNotEmpty(emergency.getHospitalInName())) {
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
index 5a52599..3e0d220 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
@@ -32,8 +32,21 @@
      * @param dispatchOrdID 璋冨害鍗旾D
      * @return 杞繍鍗曟暟鎹垪琛�
      */
-    List<Map<String, Object>> selectTransferOrdersByIDs(@Param("serviceOrdID") String serviceOrdID, @Param("dispatchOrdID") String dispatchOrdID);
-    
+    List<Map<String, Object>> selectTransferOrdersByIDs(@Param("serviceOrdID") Long serviceOrdID, @Param("dispatchOrdID") Long dispatchOrdID);
+
+    /**
+     * 鏍规嵁鏈嶅姟鍗旾D鏌ヨ杞繍鍗曟暟鎹�
+     *
+     * @param serviceOrdID 鏈嶅姟鍗旾D
+     * @return 杞繍鍗曟暟鎹垪琛�
+     */
+
+    List<Map<String, Object>> selectByServiceOrdId(@Param("serviceOrdID") Long serviceOrdID);
+    /**
+     *
+     * 鏍规嵁璋冨害鍗旾D鏌ヨ杞繍鍗曟暟鎹�
+     */
+    List<Map<String, Object>> selectByDispatchId(@Param("dispatchId") Long dispatchId);
     /**
      * 鏍规嵁鏈嶅姟鍗旾D鏌ヨ鐥呮儏淇℃伅
      * 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotifySendLogMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotifySendLogMapper.java
index 8e040df..b48ff9c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotifySendLogMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotifySendLogMapper.java
@@ -78,11 +78,13 @@
      * @param id 璁板綍ID
      * @param sendStatus 鍙戦�佺姸鎬�
      * @param sendResult 鍙戦�佺粨鏋�
+     * @param sendContent 鍙戦�佸唴瀹�
      * @return 缁撴灉
      */
     int updateSendStatus(@Param("id") Long id,
                          @Param("sendStatus") String sendStatus,
-                         @Param("sendResult") String sendResult);
+                         @Param("sendResult") String sendResult,
+                         @Param("sendContent") String sendContent);
 
     /**
      * 鍒犻櫎閫氱煡鍙戦�佽褰�
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/INotifyDispatchService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/INotifyDispatchService.java
index b2ca905..f1a036e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/INotifyDispatchService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/INotifyDispatchService.java
@@ -78,4 +78,12 @@
      * @return 鏄惁鍙戦�佹垚鍔�
      */
     boolean sendSmsMessage(NotifyTask notifyTask);
+
+    /**
+     * 鍙戦�佷紒涓氬井淇℃秷鎭�
+     * 
+     * @param notifyTask 閫氱煡浠诲姟
+     * @return 鏄惁鍙戦�佹垚鍔�
+     */
+    boolean sendQyWechatMessage(NotifyTask notifyTask);
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/INotifySendLogService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/INotifySendLogService.java
index a6385ad..4edc27c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/INotifySendLogService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/INotifySendLogService.java
@@ -56,11 +56,29 @@
      * 
      * @param id 璁板綍ID
      * @param result 鍙戦�佺粨鏋滀俊鎭�
+     * @param content 鍙戦�佸唴瀹�
+     */
+    void markSendSuccess(Long id, String result, String content);
+
+    /**
+     * 鏇存柊鍙戦�佺姸鎬佷负鎴愬姛锛堝悜鍚庡吋瀹癸級
+     * 
+     * @param id 璁板綍ID
+     * @param result 鍙戦�佺粨鏋滀俊鎭�
      */
     void markSendSuccess(Long id, String result);
 
     /**
      * 鏇存柊鍙戦�佺姸鎬佷负澶辫触
+     * 
+     * @param id 璁板綍ID
+     * @param errorMsg 閿欒淇℃伅
+     * @param content 鍙戦�佸唴瀹�
+     */
+    void markSendFailed(Long id, String errorMsg, String content);
+
+    /**
+     * 鏇存柊鍙戦�佺姸鎬佷负澶辫触锛堝悜鍚庡吋瀹癸級
      * 
      * @param id 璁板綍ID
      * @param errorMsg 閿欒淇℃伅
@@ -100,10 +118,19 @@
     int deleteNotifySendLogById(Long id);
 
     /**
+     * 鏍规嵁浠诲姟ID鍜岀敤鎴稩D鏌ヨ鍙戦�佽褰�
+     * 
+     * @param taskId 浠诲姟ID
+     * @param userId 鐢ㄦ埛ID
+     * @param notifyType 閫氱煡绫诲瀷
+     * @param channel 閫氱煡娓犻亾
+     * @return 閫氱煡鍙戦�佽褰�
+     */
+    NotifySendLog selectNotifySendLog(Long taskId, Long userId, String notifyType, String channel);
+    /**
      * 鏌ヨ寰呴噸璇曠殑澶辫触璁板綍
      * 
      * @param maxRetryCount 鏈�澶ч噸璇曟鏁�
      * @return 澶辫触璁板綍鍒楄〃
      */
-    List<NotifySendLog> selectFailedNotifySendLogs(Integer maxRetryCount);
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IQyWechatAccessTokenService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IQyWechatAccessTokenService.java
new file mode 100644
index 0000000..fc9465c
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IQyWechatAccessTokenService.java
@@ -0,0 +1,35 @@
+package com.ruoyi.system.service;
+
+/**
+ * 浼佷笟寰俊AccessToken鏈嶅姟鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2025-12-11
+ */
+public interface IQyWechatAccessTokenService {
+
+    /**
+     * 鑾峰彇浼佷笟寰俊搴旂敤鐨凙ccessToken
+     * 
+     * @param corpId 浼佷笟ID
+     * @param corpSecret 搴旂敤瀵嗛挜
+     * @return AccessToken
+     */
+    String getAppAccessToken(String corpId, String corpSecret);
+
+    /**
+     * 鍒锋柊浼佷笟寰俊搴旂敤鐨凙ccessToken
+     * 
+     * @param corpId 浼佷笟ID
+     * @param corpSecret 搴旂敤瀵嗛挜
+     * @return 鏂扮殑AccessToken
+     */
+    String refreshAppAccessToken(String corpId, String corpSecret);
+
+    /**
+     * 妫�鏌ヤ紒涓氬井淇℃湇鍔℃槸鍚﹀惎鐢�
+     * 
+     * @return true-鍚敤锛宖alse-绂佺敤
+     */
+    boolean isEnabled();
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IQyWechatService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IQyWechatService.java
new file mode 100644
index 0000000..ee6d3dc
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IQyWechatService.java
@@ -0,0 +1,46 @@
+package com.ruoyi.system.service;
+
+/**
+ * 浼佷笟寰俊鏈嶅姟鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2025-12-11
+ */
+public interface IQyWechatService {
+
+    /**
+     * 鍙戦�佷紒涓氬井淇℃秷鎭�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @param title 娑堟伅鏍囬
+     * @param content 娑堟伅鍐呭
+     * @return 鏄惁鍙戦�佹垚鍔�
+     */
+    boolean sendNotifyMessage(Long userId, String title, String content, String notifyUrl);
+
+    /**
+     * 鍙戦�佷紒涓氬井淇℃枃鏈秷鎭�
+     * 
+     * @param qyUserId 浼佷笟寰俊鐢ㄦ埛ID
+     * @param title 娑堟伅鏍囬
+     * @param content 娑堟伅鍐呭
+     * @param notifyUrl 閫氱煡閾炬帴
+     * @return 鏄惁鍙戦�佹垚鍔�
+     */
+    boolean sendTextMessage(String qyUserId, String title, String content, String notifyUrl);
+
+    /**
+     * 鑾峰彇鐢ㄦ埛鐨勪紒涓氬井淇D
+     * 
+     * @param userId 绯荤粺鐢ㄦ埛ID
+     * @return 浼佷笟寰俊鐢ㄦ埛ID
+     */
+    String getQyUserIdByUserId(Long userId);
+
+    /**
+     * 妫�鏌ヤ紒涓氬井淇℃湇鍔℃槸鍚﹀惎鐢�
+     * 
+     * @return true=鍚敤, false=鏈惎鐢�
+     */
+    boolean isEnabled();
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
index b307776..1740e14 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
@@ -86,4 +86,13 @@
      * @return 缁撴灉
      */
     public boolean checkConfigKeyUnique(SysConfig config);
+
+    /**
+     * 鏇存柊閰嶇疆鍊�
+     * 
+     * @param configKey 鍙傛暟閿悕
+     * @param configValue 鍙傛暟鍊�
+     * @return 缁撴灉
+     */
+    public int updateConfigValue(String configKey, String configValue);
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysEmergencyTaskService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysEmergencyTaskService.java
index 3768c4e..f58c998 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysEmergencyTaskService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysEmergencyTaskService.java
@@ -12,6 +12,7 @@
 
     void updateEmergencyInfoFromUpdateVO(SysTaskEmergency oldEmergency, TaskUpdateVO updateVO, String userName);
 
+    SysTaskEmergency selectSysTaskEmergencyByTaskId(Long taskId);
     /**
      * 浠� TaskCreateVO 鏇存柊鎬ユ晳杞繍浠诲姟鎵╁睍淇℃伅锛堢敤浜庢棫绯荤粺鍚屾锛�
      * 
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 5664186..38d32fe 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
@@ -18,7 +18,8 @@
  * @date 2024-01-15
  */
 public interface ISysTaskService {
-    
+
+    public Boolean dispatchSyncEvent(Long taskId);
     /**
      * 鏌ヨ浠诲姟绠$悊
      * 
@@ -36,6 +37,15 @@
     public List<SysTask> selectSysTaskList(TaskQueryVO queryVO);
 
     /**
+     * 鏍规嵁浠诲姟缂栧彿銆佽皟搴﹀崟缂栧彿鎴栨湇鍔″崟缂栧彿鏌ヨ浠诲姟鍒楄〃
+     * 
+     * @param queryVO 浠诲姟鏌ヨ瀵硅薄
+     * @param taskCode 浠诲姟缂栧彿
+     * @return 浠诲姟绠$悊闆嗗悎
+     */
+    public List<SysTask> selectSysTaskListByMultiCode(TaskQueryVO queryVO, String taskCode);
+
+    /**
      * 鏂板浠诲姟绠$悊
      * 
      * @param createVO 浠诲姟鍒涘缓瀵硅薄
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
index 487b710..32708d8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
@@ -16,29 +16,29 @@
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 import java.security.cert.X509Certificate;
-
+import com.ruoyi.common.utils.MapValueUtils;
 import com.ruoyi.system.domain.*;
+import com.ruoyi.system.event.TaskDispatchSyncEvent;
+import com.ruoyi.system.event.TaskServiceOrderSyncEvent;
+import com.ruoyi.system.mapper.*;
 import com.ruoyi.system.service.*;
 import com.ruoyi.system.task.ITaskAttachmentService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import com.ruoyi.common.config.LegacySystemConfig;
+import com.ruoyi.common.utils.MapValueUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.entity.SysDept;
 import com.ruoyi.system.domain.vo.TaskCreateVO;
-import com.ruoyi.system.mapper.SysTaskMapper;
-import com.ruoyi.system.mapper.SysTaskEmergencyMapper;
-import com.ruoyi.system.mapper.SysTaskVehicleMapper;
-import com.ruoyi.system.mapper.SysTaskAssigneeMapper;
-import com.ruoyi.system.mapper.VehicleInfoMapper;
-import com.ruoyi.system.mapper.SysUserMapper;
-import com.ruoyi.system.mapper.SysDeptMapper;
 import com.ruoyi.system.utils.TaskStatusConverter;
+import org.springframework.util.CollectionUtils;
 
 /**
  * 鏃х郴缁熷悓姝ervice涓氬姟灞傚鐞�
@@ -91,12 +91,35 @@
     private ITaskAttachmentService taskAttachmentService;
 
 
+    @Autowired
+    private ApplicationEventPublisher eventPublisher;
     
+    @Autowired
+    private LegacyTransferSyncMapper legacyTransferSyncMapper;
+    
+    
+    public Map<String,Object> getLegacyDispatchByDispatchId(Long dispatchId) {
+        List<Map<String, Object>> result = legacyTransferSyncMapper.selectByDispatchId(dispatchId);
+        if(!CollectionUtils.isEmpty(result)){
+            return result.get(0);
+        }else{
+            return null;
+        }
+    }
+
+
+    private Map<String,Object> getLegacyByServiceOrdId(Long serviceOrdId) {
+        List<Map<String, Object>> result = legacyTransferSyncMapper.selectByServiceOrdId(serviceOrdId);
+        if(!CollectionUtils.isEmpty(result)){
+            return result.get(0);
+        }else{
+            return null;
+        }
+    }
     /**
      * 鍚屾鎬ユ晳杞繍浠诲姟鍒版棫绯荤粺
      */
     @Override
-    @Transactional
     public Long syncEmergencyTaskToLegacy(Long taskId) {
         if (!legacyConfig.isEnabled()) {
             log.info("鏃х郴缁熷悓姝ュ凡绂佺敤锛岃烦杩囦换鍔D: {}", taskId);
@@ -149,12 +172,26 @@
                 emergency.setSyncStatus(2); // 鍚屾鎴愬姛
                 emergency.setSyncTime(new Date());
                 emergency.setSyncErrorMsg(null);
+                Map<String, Object> legacy = getLegacyByServiceOrdId(serviceOrdId);
+                String serviceOrdNo = MapValueUtils.getStringValue(legacy, "ServiceOrdNo");
+                if(serviceOrdNo!=null) {
+                    emergency.setLegacyServiceOrdNo(serviceOrdNo);
+                }
+                String serviceOrdClass = MapValueUtils.getStringValue(legacy, "ServiceOrdClass");
+                if(serviceOrdClass!=null) {
+                    emergency.setLegacyServiceOrdClass(serviceOrdClass);
+                }
+                Date serviceCCTime = MapValueUtils.getDateValue(legacy, "ServiceOrd_CC_Time");
+                if(serviceCCTime!=null) {
+                    emergency.setLegacyServiceNsTime(serviceCCTime);
+                }
                 sysTaskEmergencyService.updateSysTaskEmergency(emergency);
                 
                 // 鏇存柊浠诲姟涓昏〃鍚屾鏍囪
                 task.setLegacySynced(1);
                 sysTaskMapper.updateSysTask(task);
-                
+
+                eventPublisher.publishEvent(new TaskServiceOrderSyncEvent(this, taskId, task.getTaskCode(), serviceOrdId));
                 log.info("浠诲姟鍚屾鎴愬姛锛屼换鍔D: {}, ServiceOrdID: {}", taskId, serviceOrdId);
                 return serviceOrdId;
             } else {
@@ -187,7 +224,13 @@
             return null;
         }
     }
-    
+
+    //鍦ㄨ繖閲岀洃鍚淳鍙戠殑浜嬩欢
+    @EventListener
+    public void handleTaskServiceOrderSyncEvent(TaskServiceOrderSyncEvent event) {
+        log.info("鏀跺埌浠诲姟鏈嶅姟鍗曞悓姝ヤ簨浠讹紝浠诲姟ID锛歿}锛屼换鍔$紪鍙凤細{}锛屾湇鍔″崟ID锛歿}", event.getTaskId(), event.getTaskCode(), event.getServiceOrderId());
+        syncDispatchOrderToLegacy(event.getTaskId());
+    }
     /**
      * 鎵归噺鍚屾鏈悓姝ョ殑鎬ユ晳杞繍浠诲姟
      * 浣跨敤鍒嗛〉鏌ヨ锛岀‘淇濇墍鏈夌鍚堟潯浠剁殑浠诲姟閮借兘琚悓姝�
@@ -303,7 +346,6 @@
      * 鍚屾璋冨害鍗曞埌鏃х郴缁燂紙admin_save_24.asp锛�
      */
     @Override
-    @Transactional
     public Long syncDispatchOrderToLegacy(Long taskId) {
         if (!legacyConfig.isEnabled()) {
             log.info("鏃х郴缁熷悓姝ュ凡绂佺敤锛岃烦杩囪皟搴﹀崟鍚屾锛屼换鍔D: {}", taskId);
@@ -432,13 +474,18 @@
                 emergency.setDispatchSyncStatus(2); // 鍚屾鎴愬姛
                 emergency.setDispatchSyncTime(new Date());
                 emergency.setDispatchSyncErrorMsg(null);
+                //鏇存柊璋冨害鍗曚俊鎭紑鍒版柊绯荤粺
+                Map<String,Object> dispatchInfo = this.getLegacyDispatchByDispatchId(dispatchOrdId);
+                if (dispatchInfo != null) {
+                    emergency.setLegacyDispatchNsTime(MapValueUtils.getDateValue(dispatchInfo, "DispatchOrd_NS_Time")); // 鍚屾鎴愬姛
+                    emergency.setLegacyDispatchOrdClass(MapValueUtils.getStringValue(dispatchInfo, "DispatchOrdClass")); // 鍚屾鎴愬姛
+                    emergency.setLegacyDispatchOrdNo(MapValueUtils.getStringValue(dispatchInfo, "DispatchOrdNo")); // 鍚屾鎴愬姛
+                    emergency.setLegacyServiceNsTime(MapValueUtils.getDateValue(dispatchInfo, "ServiceOrd_CC_Time")); // 鍚屾鎴愬姛
+                    emergency.setLegacyServiceOrdClass(MapValueUtils.getStringValue(dispatchInfo, "ServiceOrdClass")); // 鍚屾鎴愬姛
+                }
                 sysTaskEmergencyService.updateSysTaskEmergency(emergency);
 
-                List<SysTaskAttachment> taskAttachments= sysTaskService.getAttachmentsByTaskId(taskId);
-                if (taskAttachments != null && !taskAttachments.isEmpty()) {
-                    //鍚屾闄勪欢
-                   this.syncAttachmentToLegacy(taskAttachments,serviceOrdId,dispatchOrdId,oaUserID);
-                }
+                eventPublisher.publishEvent(new TaskDispatchSyncEvent(this, taskId, task.getTaskCode(),serviceOrdId, dispatchOrdId, oaUserID));
 
                 log.info("璋冨害鍗曞悓姝ユ垚鍔燂紝浠诲姟ID: {}, DispatchOrdID: {}", taskId, dispatchOrdId);
                 return dispatchOrdId;
@@ -472,7 +519,19 @@
             return null;
         }
     }
-    
+
+    @EventListener
+    public void handleTaskDispatchSyncEvent(TaskDispatchSyncEvent event) {
+        Long taskId = event.getTaskId();
+        Long dispatchOrdId = event.getDispatchOrderId();
+        Long serviceOrdId = event.getServiceOrderId();
+        Integer oaUserID = event.getOaUserId();
+        List<SysTaskAttachment> taskAttachments= sysTaskService.getAttachmentsByTaskId(taskId);
+        if (taskAttachments != null && !taskAttachments.isEmpty()) {
+            //鍚屾闄勪欢
+            this.syncAttachmentToLegacy(taskAttachments,serviceOrdId,dispatchOrdId,oaUserID);
+        }
+    }
     /**
      * 鎵归噺鍚屾鏈悓姝ョ殑璋冨害鍗�
      * 浣跨敤鍒嗛〉鏌ヨ锛岀‘淇濇墍鏈夌鍚堟潯浠剁殑浠诲姟閮借兘琚悓姝�
@@ -492,17 +551,17 @@
             while (true) {
                 // 鍒嗛〉鏌ヨ宸插悓姝ユ湇鍔″崟浣嗘湭鍚屾璋冨害鍗曠殑浠诲姟
                 List<SysTaskEmergency> pendingTasks = sysTaskEmergencyService.selectPendingDispatchSyncTasks(offset, pageSize);
-                log.info("鏌ヨ鍒版湭鍚屾璋冨害鍗曠殑浠诲姟鏁伴噺: {}", pendingTasks.size());
+//                log.info("鏌ヨ鍒版湭鍚屾璋冨害鍗曠殑浠诲姟鏁伴噺: {}", pendingTasks.size());
                 if (pendingTasks == null || pendingTasks.isEmpty()) {
                     log.info("娌℃湁鏇村闇�瑕佸悓姝ヨ皟搴﹀崟鐨勪换鍔★紝offset: {}", offset);
                     break; // 娌℃湁鏇村鏁版嵁锛岄��鍑哄惊鐜�
                 }
                 
-                log.info("寮�濮嬪悓姝ヨ皟搴﹀崟绗� {} 椤碉紝浠诲姟鏁伴噺: {}", (offset / pageSize) + 1, pendingTasks.size());
+//                log.info("寮�濮嬪悓姝ヨ皟搴﹀崟绗� {} 椤碉紝浠诲姟鏁伴噺: {}", (offset / pageSize) + 1, pendingTasks.size());
                 
                 int pageSuccessCount = 0;
                 for (SysTaskEmergency emergency : pendingTasks) {
-                    log.info("寮�濮嬪悓姝ヨ皟搴﹀崟锛屼换鍔D: {}", emergency.getTaskId());
+//                    log.info("寮�濮嬪悓姝ヨ皟搴﹀崟锛屼换鍔D: {}", emergency.getTaskId());
                     Long dispatchOrdId = syncDispatchOrderToLegacy(emergency.getTaskId());
 
                     if (dispatchOrdId != null && dispatchOrdId > 0) {
@@ -1226,6 +1285,93 @@
         }
     }
     
+    // 鍒犻櫎涓嬮潰鐨勯噸澶嶆柟娉曪紝鍥犱负鎴戜滑灏嗕娇鐢∕apValueUtils宸ュ叿绫讳腑鐨勬柟娉�
+    /*
+    private String getStringValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        return value != null ? value.toString() : null;
+    }
+    
+    private BigDecimal getBigDecimalValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+        try {
+            return new BigDecimal(value.toString());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+    
+    private Long getLongValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Long) {
+            return (Long) value;
+        }
+        try {
+            return Long.valueOf(value.toString());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+    
+    private Integer getIntegerValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        try {
+            return Integer.valueOf(value.toString());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+    
+    private Date getDateValue(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Date) {
+            return (Date) value;
+        }
+        // 濡傛灉鏄瓧绗︿覆锛屽皾璇曡В鏋�
+        if (value instanceof String) {
+            try {
+                return DateUtils.parseDate(value.toString());
+            } catch (Exception e) {
+                return null;
+            }
+        }
+        return null;
+    }
+    
+    private boolean isValidDateFormat(String dateStr, String format) {
+        if (StringUtils.isEmpty(dateStr)) {
+            return false;
+        }
+        
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat(format);
+            sdf.setLenient(false);
+            sdf.parse(dateStr);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+    */
+    
     /**
      * 閲嶆柊鍚屾杞﹁締鍜屼汉鍛樺彉鏇寸殑浠诲姟鍒版棫绯荤粺
      * 褰撲换鍔$殑杞﹁締淇℃伅鎴栦汉鍛樹俊鎭彂鐢熷彉鏇存椂锛岄渶瑕佽皟鐢ㄦ棫绯荤粺鎺ュ彛閲嶆柊鍚屾
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 4bf8466..03102dd 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
@@ -3,6 +3,7 @@
 import com.ruoyi.common.core.domain.entity.SysDept;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.MapValueUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.domain.SysTaskEmergency;
 import com.ruoyi.system.domain.VehicleInfo;
@@ -107,8 +108,8 @@
             for (Map<String, Object> order : transferOrders) {
                 processedCount++;
                 try {
-                    String serviceOrdID = getStringValue(order, "ServiceOrdID");
-                    String dispatchOrdID = getStringValue(order, "DispatchOrdID");
+                    String serviceOrdID = MapValueUtils.getStringValue(order, "ServiceOrdID");
+                    String dispatchOrdID = MapValueUtils.getStringValue(order, "DispatchOrdID");
                     
                     // 妫�鏌ュ弬鏁版湁鏁堟��
                     if (StringUtils.isEmpty(serviceOrdID)) {
@@ -141,8 +142,8 @@
                     break;
                 } catch (Exception e) {
                     log.error("鍚屾鍗曚釜杞繍鍗曞け璐�: ServiceOrdID={}, DispatchOrdID={}", 
-                             getStringValue(order, "ServiceOrdID"), 
-                             getStringValue(order, "DispatchOrdID"), e);
+                             MapValueUtils.getStringValue(order, "ServiceOrdID"), 
+                             MapValueUtils.getStringValue(order, "DispatchOrdID"), e);
                 }
             }
             
@@ -173,7 +174,25 @@
                 return false;
             }
             // 鐩存帴鏌ヨ鎸囧畾鐨勮浆杩愬崟淇℃伅
-            List<Map<String, Object>> transferOrders = legacyTransferSyncMapper.selectTransferOrdersByIDs(serviceOrdID, dispatchOrdID);
+            Long serviceOrdIdLong = null;
+            Long dispatchOrdIdLong = null;
+            
+            try {
+                serviceOrdIdLong = Long.valueOf(serviceOrdID);
+            } catch (NumberFormatException e) {
+                log.error("鏈嶅姟鍗旾D涓嶆槸鏈夋晥鏁板瓧: {}", serviceOrdID);
+                return false;
+            }
+            
+            if (StringUtils.isNotEmpty(dispatchOrdID)) {
+                try {
+                    dispatchOrdIdLong = Long.valueOf(dispatchOrdID);
+                } catch (NumberFormatException e) {
+                    log.warn("璋冨害鍗旾D涓嶆槸鏈夋晥鏁板瓧: {}", dispatchOrdID);
+                }
+            }
+            
+            List<Map<String, Object>> transferOrders = legacyTransferSyncMapper.selectTransferOrdersByIDs(serviceOrdIdLong, dispatchOrdIdLong);
 
             Map<String, Object> order = transferOrders.get(0);
 
@@ -224,25 +243,25 @@
             }
             sysTaskCode = createTaskVo.getTaskCode();
             // 璁板綍鍒涘缓鐨勪换鍔′俊鎭�
-            log.debug("鍑嗗鍒涘缓浠诲姟: ServiceOrdID={}, DispatchOrdID={}, 鎮h�呭鍚�={}, 杞嚭鍖婚櫌={}, 杞叆鍖婚櫌={}",
-                    serviceOrdID, dispatchOrdID,
-                    createTaskVo.getPatient() != null ? createTaskVo.getPatient().getName() : "鏈煡",
-                    createTaskVo.getHospitalOut() != null ? createTaskVo.getHospitalOut().getName() : "鏈煡",
-                    createTaskVo.getHospitalIn() != null ? createTaskVo.getHospitalIn().getName() : "鏈煡");
+//            log.debug("鍑嗗鍒涘缓浠诲姟: ServiceOrdID={}, DispatchOrdID={}, 鎮h�呭鍚�={}, 杞嚭鍖婚櫌={}, 杞叆鍖婚櫌={}",
+//                    serviceOrdID, dispatchOrdID,
+//                    createTaskVo.getPatient() != null ? createTaskVo.getPatient().getName() : "鏈煡",
+//                    createTaskVo.getHospitalOut() != null ? createTaskVo.getHospitalOut().getName() : "鏈煡",
+//                    createTaskVo.getHospitalIn() != null ? createTaskVo.getHospitalIn().getName() : "鏈煡");
             /**
              * 寮�鍗曟椂闂�
              */
-            Date ServiceOrd_CC_Time= getDateValue(order, "ServiceOrd_CC_Time");
+            Date ServiceOrd_CC_Time= MapValueUtils.getDateValue(order, "ServiceOrd_CC_Time");
             // 璋冪敤sysTaskService鍒涘缓浠诲姟
-            String serviceOrdClass = getStringValue(order,"ServiceOrdClass");
-            String serviceOrdNo = getStringValue(order,"ServiceOrdNo");
+            String serviceOrdClass = MapValueUtils.getStringValue(order,"ServiceOrdClass");
+            String serviceOrdNo = MapValueUtils.getStringValue(order,"ServiceOrdNo");
 
-            Integer oauserId=getIntegerValue(order,"ServiceOrd_CC_ID");
+            Integer oauserId=MapValueUtils.getIntegerValue(order,"ServiceOrd_CC_ID");
             if(oauserId==null){
-                oauserId=getIntegerValue(order,"ServiceOrd_NS_ID");
+                oauserId=MapValueUtils.getIntegerValue(order,"ServiceOrd_NS_ID");
             }
-            if(oauserId==null || oauserId==0){
-                log.error("鍒涘缓浠诲姟鏃讹紝鑾峰彇鍒涘缓浜轰俊鎭け璐ワ紝serviceOrdID={}, DispatchOrdID={} ServiceOrd_NS_ID={},ServiceOrd_CC_ID={}", serviceOrdID, dispatchOrdID, getIntegerValue(order,"ServiceOrd_NS_ID"),getIntegerValue(order,"ServiceOrd_CC_ID"));
+            if(oauserId==null || oauserId==0) {
+                log.error("鍒涘缓浠诲姟鏃讹紝鑾峰彇鍒涘缓浜轰俊鎭け璐ワ紝serviceOrdID={}, DispatchOrdID={} ServiceOrd_NS_ID={},ServiceOrd_CC_ID={}", serviceOrdID, dispatchOrdID, MapValueUtils.getIntegerValue(order, "ServiceOrd_NS_ID"), MapValueUtils.getIntegerValue(order, "ServiceOrd_CC_ID"));
                 return false;
             }
             SysUser sysUser=sysUserService.selectUserByOaUserId(oauserId);
@@ -294,38 +313,39 @@
         try {
             // 鏋勯�燭askCreateVO瀵硅薄
             TaskCreateVO createTaskVo = buildCreateTaskVo(serviceOrdID, dispatchOrdID, order);
-            sysTaskCode = createTaskVo.getTaskCode();
+
             if (createTaskVo == null) {
                 log.error("鏋勯�燭askCreateVO澶辫触: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
                 return false;
             }
-            
+            sysTaskCode = createTaskVo.getTaskCode();
             // 璁板綍鍒涘缓鐨勪换鍔′俊鎭�
-            log.debug("鍑嗗鍒涘缓浠诲姟: ServiceOrdID={}, DispatchOrdID={}, 鎮h�呭鍚�={}, 杞嚭鍖婚櫌={}, 杞叆鍖婚櫌={}", 
-                     serviceOrdID, dispatchOrdID, 
-                     createTaskVo.getPatient() != null ? createTaskVo.getPatient().getName() : "鏈煡",
-                     createTaskVo.getHospitalOut() != null ? createTaskVo.getHospitalOut().getName() : "鏈煡",
-                     createTaskVo.getHospitalIn() != null ? createTaskVo.getHospitalIn().getName() : "鏈煡");
+//            log.debug("鍑嗗鍒涘缓浠诲姟: ServiceOrdID={}, DispatchOrdID={}, 鎮h�呭鍚�={}, 杞嚭鍖婚櫌={}, 杞叆鍖婚櫌={}",
+//                     serviceOrdID, dispatchOrdID,
+//                     createTaskVo.getPatient() != null ? createTaskVo.getPatient().getName() : "鏈煡",
+//                     createTaskVo.getHospitalOut() != null ? createTaskVo.getHospitalOut().getName() : "鏈煡",
+//                     createTaskVo.getHospitalIn() != null ? createTaskVo.getHospitalIn().getName() : "鏈煡");
             /**
              * 寮�鍗曟椂闂�
              */
-            Date ServiceOrd_CC_Time= getDateValue(order, "ServiceOrd_CC_Time");
+            Date ServiceOrd_CC_Time= MapValueUtils.getDateValue(order, "ServiceOrd_CC_Time");
             // 璋冪敤sysTaskService鍒涘缓浠诲姟
-            String serviceOrdClass = getStringValue(order,"ServiceOrdClass");
-            String serviceOrdNo = getStringValue(order,"ServiceOrdNo");
+            String serviceOrdClass = MapValueUtils.getStringValue(order,"ServiceOrdClass");
+            String serviceOrdNo = MapValueUtils.getStringValue(order,"ServiceOrdNo");
 
             /**
              * 鍒涘缓浜篒D
              */
-            Integer oauserId=getIntegerValue(order,"ServiceOrd_CC_ID");
+            Integer oauserId=MapValueUtils.getIntegerValue(order,"ServiceOrd_CC_ID");
             if(oauserId==null || oauserId==0) {
-                oauserId=getIntegerValue(order,"ServiceOrd_NS_ID");
+                oauserId=MapValueUtils.getIntegerValue(order,"ServiceOrd_NS_ID");
             }
             SysUser sysUser=sysUserService.selectUserByOaUserId(oauserId);
-            if(sysUser==null){
-                log.error("鍒涘缓浠诲姟鏃讹紝鑾峰彇鍒涘缓浜轰俊鎭け璐ワ紝serviceOrdID={}, DispatchOrdID={} ServiceOrd_CC_ID:{},ServiceOrd_NS_ID:{}", serviceOrdID, dispatchOrdID, getIntegerValue(order,"ServiceOrd_CC_ID"),getIntegerValue(order,"ServiceOrd_NS_ID"));
+            if(sysUser==null) {
+                log.error("鍒涘缓浠诲姟鏃讹紝鑾峰彇鍒涘缓浜轰俊鎭け璐ワ紝serviceOrdID={}, DispatchOrdID={} ServiceOrd_CC_ID:{},ServiceOrd_NS_ID:{}", serviceOrdID, dispatchOrdID, MapValueUtils.getIntegerValue(order, "ServiceOrd_CC_ID"), MapValueUtils.getIntegerValue(order, "ServiceOrd_NS_ID"));
                 return false;
             }
+            
             Long taskCreatorId= sysUser.getUserId();
             String createUserName= sysUser.getUserName();
             SysDept dept=sysDeptService.selectDeptByServiceClass(serviceOrdClass);
@@ -410,6 +430,8 @@
         String ServiceOrdNo_Str=String.format("%03d", intServiceNo);
         return serviceOrdClass+ServiceOrd_CC_Time_Str+"-"+ServiceOrdNo_Str;
     }
+
+
     /**
      * 鏋勯�燭askCreateVO瀵硅薄鐢ㄤ簬鍒涘缓浠诲姟
      * 
@@ -433,10 +455,10 @@
                 log.error("鏈嶅姟鍗旾D涓嶈兘涓虹┖");
                 return null;
             }
-            String serviceOrdClass = getStringValue(order, "ServiceOrdClass");
+            String serviceOrdClass = MapValueUtils.getStringValue(order, "ServiceOrdClass");
 
             TaskCreateVO createTaskVo = new TaskCreateVO();
-            String serviceOrdCode=this.getServiceOrdCode(getDateValue(order, "ServiceOrd_CC_Time"),serviceOrdClass,getStringValue(order, "ServiceOrdNo"));
+            String serviceOrdCode=this.getServiceOrdCode(MapValueUtils.getDateValue(order, "ServiceOrd_CC_Time"),serviceOrdClass,MapValueUtils.getStringValue(order, "ServiceOrdNo"));
             createTaskVo.setTaskCode(serviceOrdCode);
 //            log.info("鏋勯�燭askCreateVO: ServiceOrdID={}, DispatchOrdID={},taskCode:{}", serviceOrdID, dispatchOrdID,serviceOrdCode);
             // 璁剧疆鍩烘湰淇℃伅
@@ -448,26 +470,26 @@
                 createTaskVo.setDocumentTypeId(serviceOrdClass);
             }
             
-            String serviceOrdType = getStringValue(order, "ServiceOrdType");
+            String serviceOrdType = MapValueUtils.getStringValue(order, "ServiceOrdType");
             if (StringUtils.isNotEmpty(serviceOrdType)) {
                 createTaskVo.setTaskTypeId(serviceOrdType);
             }
             
             // 璁剧疆鍖哄煙绫诲瀷
-            String serviceOrdAreaType = getStringValue(order, "ServiceOrdAreaType");
+            String serviceOrdAreaType = MapValueUtils.getStringValue(order, "ServiceOrdAreaType");
 
             // 璁剧疆鐢ㄦ埛ID
-            Long serviceOrdUserID = getLongValue(order, "ServiceOrdUserID");
+            Long serviceOrdUserID = MapValueUtils.getLongValue(order, "ServiceOrdUserID");
 
             // 璁剧疆鎮h�呬俊鎭�
             TaskCreateVO.PatientInfo patientInfo = new TaskCreateVO.PatientInfo();
-            patientInfo.setName(getStringValue(order, "ServiceOrdPtName"));
-            patientInfo.setPhone(getStringValue(order, "ServiceOrdCoPhone"));
-            patientInfo.setIdCard(getStringValue(order, "ServiceOrdPtIDCard"));
-            patientInfo.setCondition(getStringValue(order, "ServiceOrdPtCondition"));
-            patientInfo.setContact(getStringValue(order, "ServiceOrdCoName"));
+            patientInfo.setName(MapValueUtils.getStringValue(order, "ServiceOrdPtName"));
+            patientInfo.setPhone(MapValueUtils.getStringValue(order, "ServiceOrdCoPhone"));
+            patientInfo.setIdCard(MapValueUtils.getStringValue(order, "ServiceOrdPtIDCard"));
+            patientInfo.setCondition(MapValueUtils.getStringValue(order, "ServiceOrdPtCondition"));
+            patientInfo.setContact(MapValueUtils.getStringValue(order, "ServiceOrdCoName"));
 
-            String serviceOrdPtSex = getStringValue(order, "ServiceOrdPtSex");
+            String serviceOrdPtSex = MapValueUtils.getStringValue(order, "ServiceOrdPtSex");
             if(serviceOrdPtSex!=null){
                 if(serviceOrdPtSex.equals("鐢�")){
                     patientInfo.setGender("male");
@@ -477,7 +499,7 @@
             }
             createTaskVo.setPatient(patientInfo);
             //1000鍏噷锛屾彁鍙栨暟瀛�
-            String ServiceOrdTraDistance=getStringValue(order, "ServiceOrdTraDistance");
+            String ServiceOrdTraDistance=MapValueUtils.getStringValue(order, "ServiceOrdTraDistance");
             if(ServiceOrdTraDistance!=null){
                 ServiceOrdTraDistance=ServiceOrdTraDistance.replaceAll("[^0-9]", "");
                 createTaskVo.setDistance(new BigDecimal(ServiceOrdTraDistance));
@@ -487,7 +509,7 @@
             // 璁剧疆杞嚭鍖婚櫌淇℃伅
 
             TaskCreateVO.HospitalInfo hospitalOutInfo = new TaskCreateVO.HospitalInfo();
-            Long hospitalOutId = getLongValue(order, "ServiceOrdPtOutHospID");
+            Long hospitalOutId = MapValueUtils.getLongValue(order, "ServiceOrdPtOutHospID");
             hospitalOutInfo.setId(hospitalOutId);
             if (hospitalOutId != null) {
                 String hospitalOutName = legacyTransferSyncMapper.selectHospitalNameByHospID(hospitalOutId.toString());
@@ -495,13 +517,13 @@
                     hospitalOutInfo.setName(hospitalOutName);
                 }
             }
-            String ServiceOrdTraVia=getStringValue(order, "ServiceOrdTraVia");
+            String ServiceOrdTraVia=MapValueUtils.getStringValue(order, "ServiceOrdTraVia");
             if(ServiceOrdTraVia!=null){
                 hospitalOutInfo.setAddress(ServiceOrdTraVia);
             }
 
 
-            String hospitalOutDeptId = getStringValue(order, "ServiceOrdPtServicesID");
+            String hospitalOutDeptId = MapValueUtils.getStringValue(order, "ServiceOrdPtServicesID");
             hospitalOutInfo.setDepartmentId(hospitalOutDeptId);
             if (StringUtils.isNotEmpty(hospitalOutDeptId)) {
                 String hospitalOutDeptName = legacyTransferSyncMapper.selectDepartmentNameByDeptID(hospitalOutDeptId);
@@ -510,7 +532,7 @@
                 }
             }
             //杞嚭搴婁綅
-            String serviceOrdPtServices=getStringValue(order, "ServiceOrdPtServices");
+            String serviceOrdPtServices=MapValueUtils.getStringValue(order, "ServiceOrdPtServices");
             if(serviceOrdPtServices!= null){
                 hospitalOutInfo.setBedNumber(serviceOrdPtServices);
             }
@@ -518,7 +540,7 @@
             
             // 璁剧疆杞叆鍖婚櫌淇℃伅
             TaskCreateVO.HospitalInfo hospitalInInfo = new TaskCreateVO.HospitalInfo();
-            Long hospitalInId = getLongValue(order, "ServiceOrdPtInHospID");
+            Long hospitalInId = MapValueUtils.getLongValue(order, "ServiceOrdPtInHospID");
             hospitalInInfo.setId(hospitalInId);
             if (hospitalInId != null) {
                 String hospitalInName = legacyTransferSyncMapper.selectHospitalNameByHospID(hospitalInId.toString());
@@ -526,18 +548,18 @@
                     hospitalInInfo.setName(hospitalInName);
                 }
             }
-            String serviceOrdTraEnd = getStringValue(order, "ServiceOrdTraEnd");
+            String serviceOrdTraEnd = MapValueUtils.getStringValue(order, "ServiceOrdTraEnd");
             if(serviceOrdTraEnd!= null){
                 hospitalInInfo.setAddress(serviceOrdTraEnd);
             }
             //杞叆搴婁綅
-            String serviceOrdPtInServices =getStringValue(order, "ServiceOrdPtInServices");
+            String serviceOrdPtInServices =MapValueUtils.getStringValue(order, "ServiceOrdPtInServices");
             if(serviceOrdPtInServices!= null){
                 hospitalInInfo.setBedNumber(serviceOrdPtInServices);
             }
 
 
-            String hospitalInDeptId = getStringValue(order, "ServiceOrdPtInServicesID");
+            String hospitalInDeptId = MapValueUtils.getStringValue(order, "ServiceOrdPtInServicesID");
             hospitalInInfo.setDepartmentId(hospitalInDeptId);
             if (StringUtils.isNotEmpty(hospitalInDeptId)) {
                 String hospitalInDeptName = legacyTransferSyncMapper.selectDepartmentNameByDeptID(hospitalInDeptId);
@@ -548,11 +570,11 @@
             createTaskVo.setHospitalIn(hospitalInInfo);
             
             // 璁剧疆鍦板潃淇℃伅
-            createTaskVo.setDepartureAddress(getStringValue(order, "ServiceOrdTraStreet"));
-            createTaskVo.setDestinationAddress(getStringValue(order, "ServiceOrdTraEnd"));
+            createTaskVo.setDepartureAddress(MapValueUtils.getStringValue(order, "ServiceOrdTraStreet"));
+            createTaskVo.setDestinationAddress(MapValueUtils.getStringValue(order, "ServiceOrdTraEnd"));
             
             // 璁剧疆浠锋牸鍜岃窛绂讳俊鎭�
-            createTaskVo.setPrice(getBigDecimalValue(order, "ServiceOrdTraTxnPrice"));
+            createTaskVo.setPrice(MapValueUtils.getBigDecimalValue(order, "ServiceOrdTraTxnPrice"));
             // 璺濈淇℃伅闇�瑕佷粠鍏朵粬瀛楁璁$畻鎴栬幏鍙�
 
             if(dispatchOrdID!=null) {
@@ -565,7 +587,7 @@
             }
             // 璁剧疆杞﹁締淇℃伅
             // 杞﹁締ID闇�瑕佹牴鎹瓺ispatchOrdCarID鏌ヨ鑾峰彇
-            String carID = getStringValue(order, "DispatchOrdCarID");
+            String carID = MapValueUtils.getStringValue(order, "DispatchOrdCarID");
             if (StringUtils.isNotEmpty(carID)) {
                 String carLicense = legacyTransferSyncMapper.selectCarLicenseByCarID(carID);
                 if (StringUtils.isNotEmpty(carLicense)) {
@@ -619,24 +641,24 @@
             
             // 璁剧疆澶囨敞淇℃伅
             String remark = "鏈嶅姟鍗旾D: " + serviceOrdID + ", 璋冨害鍗旾D: " + dispatchOrdID;
-            String serviceOrdCoTies = getStringValue(order, "ServiceOrdCoTies");
+            String serviceOrdCoTies = MapValueUtils.getStringValue(order, "ServiceOrdCoTies");
             if (StringUtils.isNotEmpty(serviceOrdCoTies)) {
                 remark += ", 鑱旂郴浜哄叧绯�: " + serviceOrdCoTies;
             }
             createTaskVo.setRemark(remark);
             
             // 璁剧疆璁″垝寮�濮嬫椂闂�
-            Date plannedStartTime = getDateValue(order, "ServiceOrdApptDate");
+            Date plannedStartTime = MapValueUtils.getDateValue(order, "ServiceOrdApptDate");
             if (plannedStartTime != null) {
                 createTaskVo.setPlannedStartTime(plannedStartTime);
             }
 
-            Date actualStartTime = getDateValue(order, "DispatchOrdActualDate");
+            Date actualStartTime = MapValueUtils.getDateValue(order, "DispatchOrdActualDate");
             if (actualStartTime != null) {
                 createTaskVo.setActualStartTime(actualStartTime);
             }
 
-            Date actualEndTime = getDateValue(order, "DispatchOrdReturnDate");
+            Date actualEndTime = MapValueUtils.getDateValue(order, "DispatchOrdReturnDate");
             if (actualEndTime != null) {
                 createTaskVo.setActualEndTime(actualEndTime);
             }
@@ -644,7 +666,7 @@
 
             
             // 璁剧疆鍒涘缓鏃堕棿 寮�鍗曟棩鏈�
-            Date createTime = getDateValue(order, "ServiceOrd_CC_Time");
+            Date createTime = MapValueUtils.getDateValue(order, "ServiceOrd_CC_Time");
             if (createTime != null) {
                 createTaskVo.setCreateTime(createTime);
             }
@@ -664,14 +686,36 @@
                 createTaskVo.setDiseaseIds(diseaseIds);
             }
 
-            Integer dispatchOrdStatus = getIntegerValue(order, "DispatchOrdStatus");
+            Integer dispatchOrdStatus = MapValueUtils.getIntegerValue(order, "DispatchOrdStatus");
            TaskStatus status= TaskStatusConverter.convertFromLegacyStatus(dispatchOrdStatus);
            if(status!=null) {
                createTaskVo.setTaskStatus(status.getCode());
            }
 
-            
-//            log.info("TaskCreateVO鏋勯�犲畬鎴�: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
+            // 璁剧疆鏃х郴缁熷悓姝ュ瓧娈�
+            String dispatchOrdNo = MapValueUtils.getStringValue(order, "DispatchOrdNo");
+           if(dispatchOrdNo!=null) {
+               createTaskVo.setLegacyDispatchOrdNo(dispatchOrdNo);
+           }
+           Date ccTime=MapValueUtils.getDateValue(order, "ServiceOrd_CC_Time");
+
+           if(ccTime!=null) {
+               createTaskVo.setLegacyServiceNsTime(ccTime);
+           }
+           Date nsTime=MapValueUtils.getDateValue(order, "DispatchOrd_NS_Time");
+           if(nsTime!=null) {
+               createTaskVo.setLegacyDispatchNsTime(MapValueUtils.getDateValue(order, "DispatchOrd_NS_Time"));
+           }
+           String dispatchOrdClass=MapValueUtils.getStringValue(order, "DispatchOrdClass");
+           if(dispatchOrdClass!=null) {
+               createTaskVo.setLegacyDispatchOrdClass(dispatchOrdClass);
+           }
+
+//           String serviceOrdClass=MapValueUtils.getStringValue(order, "ServiceOrdClass");
+           if(serviceOrdClass!=null) {
+               createTaskVo.setLegacyServiceOrdClass(serviceOrdClass);
+           }
+
             return createTaskVo;
             
         } catch (Exception e) {
@@ -718,8 +762,8 @@
             List<TaskCreateVO.AssigneeInfo> assignees = new ArrayList<>();
             if (assigneeList != null && !assigneeList.isEmpty()) {
                 for (Map<String, Object> assigneeMap : assigneeList) {
-                    String entourageOAId = getStringValue(assigneeMap, "EntourageOAId");
-                    String entourageState = getStringValue(assigneeMap, "EntourageID");
+                    String entourageOAId = MapValueUtils.getStringValue(assigneeMap, "EntourageOAId");
+                    String entourageState = MapValueUtils.getStringValue(assigneeMap, "EntourageID");
                     
                     if (StringUtils.isNotEmpty(entourageOAId)) {
                         try {
@@ -793,122 +837,7 @@
         }
     }
     
-    /**
-     * 浠嶮ap涓幏鍙栧瓧绗︿覆鍊�
-     * 
-     * @param map Map瀵硅薄
-     * @param key 閿�
-     * @return 瀛楃涓插��
-     */
-    private String getStringValue(Map<String, Object> map, String key) {
-        Object value = map.get(key);
-        return value != null ? value.toString() : null;
-    }
-    
-    /**
-     * 浠嶮ap涓幏鍙朆igDecimal鍊�
-     * 
-     * @param map Map瀵硅薄
-     * @param key 閿�
-     * @return BigDecimal鍊�
-     */
-    private BigDecimal getBigDecimalValue(Map<String, Object> map, String key) {
-        Object value = map.get(key);
-        if (value == null) {
-            return null;
-        }
-        if (value instanceof BigDecimal) {
-            return (BigDecimal) value;
-        }
-        try {
-            return new BigDecimal(value.toString());
-        } catch (NumberFormatException e) {
-            return null;
-        }
-    }
-    
-    /**
-     * 浠嶮ap涓幏鍙朙ong鍊�
-     * 
-     * @param map Map瀵硅薄
-     * @param key 閿�
-     * @return Long鍊�
-     */
-    private Long getLongValue(Map<String, Object> map, String key) {
-        Object value = map.get(key);
-        if (value == null) {
-            return null;
-        }
-        if (value instanceof Long) {
-            return (Long) value;
-        }
-        try {
-            return Long.valueOf(value.toString());
-        } catch (NumberFormatException e) {
-            return null;
-        }
-    }
-    private Integer getIntegerValue(Map<String, Object> map, String key) {
-        Object value = map.get(key);
-        if (value == null) {
-            return null;
-        }
-        if (value instanceof Integer) {
-            return (Integer) value;
-        }
-        try {
-            return Integer.valueOf(value.toString());
-        } catch (NumberFormatException e) {
-            return null;
-        }
-    }
-    /**
-     * 浠嶮ap涓幏鍙朌ate鍊�
-     * 
-     * @param map Map瀵硅薄
-     * @param key 閿�
-     * @return Date鍊�
-     */
-    private Date getDateValue(Map<String, Object> map, String key) {
-        Object value = map.get(key);
-        if (value == null) {
-            return null;
-        }
-        if (value instanceof Date) {
-            return (Date) value;
-        }
-        // 濡傛灉鏄瓧绗︿覆锛屽皾璇曡В鏋�
-        if (value instanceof String) {
-            try {
-                return DateUtils.parseDate(value.toString());
-            } catch (Exception e) {
-                return null;
-            }
-        }
-        return null;
-    }
-    
-    /**
-     * 楠岃瘉鏃ユ湡瀛楃涓叉牸寮忔槸鍚︽湁鏁�
-     * 
-     * @param dateStr 鏃ユ湡瀛楃涓�
-     * @param format 鏃ユ湡鏍煎紡
-     * @return 鏄惁鏈夋晥
-     */
-    private boolean isValidDateFormat(String dateStr, String format) {
-        if (StringUtils.isEmpty(dateStr)) {
-            return false;
-        }
-        
-        try {
-            SimpleDateFormat sdf = new SimpleDateFormat(format);
-            sdf.setLenient(false);
-            sdf.parse(dateStr);
-            return true;
-        } catch (Exception e) {
-            return false;
-        }
-    }
+
 
     private void notifyTransferOrderByWechat(Long taskId,
                                              String serviceOrdID,
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifyDispatchServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifyDispatchServiceImpl.java
index a918e86..06e3576 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifyDispatchServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifyDispatchServiceImpl.java
@@ -46,6 +46,13 @@
     @Autowired
     private ISmsService smsService;
 
+    @Autowired
+    private IQyWechatService qyWechatService;
+
+
+    @Autowired
+    private ISysEmergencyTaskService sysEmergencyTaskService;
+
     /**
      * 鑾峰彇鎸囧畾閫氱煡绫诲瀷鍚敤鐨勬笭閬撳垪琛�
      */
@@ -108,6 +115,9 @@
                         break;
                     case NotifyChannelConfig.CHANNEL_SMS:
                         success = sendSmsMessage(notifyTask);
+                        break;
+                    case NotifyChannelConfig.CHANNEL_QY_WECHAT:
+                        success = sendQyWechatMessage(notifyTask);
                         break;
                     default:
                         log.warn("涓嶆敮鎸佺殑娓犻亾绫诲瀷锛歿}", channel);
@@ -175,6 +185,7 @@
             sendLog.setChannel(channel);
             sendLog.setSendStatus(success ? NotifySendLog.SEND_STATUS_SUCCESS : NotifySendLog.SEND_STATUS_FAILED);
             sendLog.setSendTime(DateUtils.getNowDate());
+            sendLog.setSendContent(notifyTask.getContent());
             sendLog.setResponseMsg(errorMsg);
             
             notifySendLogService.insertNotifySendLog(sendLog);
@@ -318,4 +329,47 @@
             return false;
         }
     }
+
+    @Autowired
+    private ISysConfigService sysConfigService;
+    /**
+     * 鍙戦�佷紒涓氬井淇℃秷鎭�
+     */
+    @Override
+    public boolean sendQyWechatMessage(NotifyTask notifyTask) {
+        try {
+            // 妫�鏌ヤ紒涓氬井淇℃湇鍔℃槸鍚﹀惎鐢�
+            if (!qyWechatService.isEnabled()) {
+                log.info("浼佷笟寰俊鏈嶅姟宸插叧闂紝璺宠繃鍙戦��");
+                return false;
+            }
+            Long taskId= notifyTask.getTaskId();
+           SysTaskEmergency emergency = this.sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
+           if(emergency==null){
+               return false;
+           }
+           Long dispatchOrderId = emergency.getLegacyDispatchOrdId();
+          String oldsiteUrl= sysConfigService.selectConfigByKey("oldsite.url");
+          if(oldsiteUrl==null){
+              oldsiteUrl="https://sys.966120.com.cn/m_DispatchOrder.gds?DispatchOrdID=";
+          }
+           String url=oldsiteUrl+dispatchOrderId;
+            // 鍙戦�佷紒涓氬井淇℃秷鎭�
+            boolean success = qyWechatService.sendNotifyMessage(
+                    notifyTask.getUserId(), 
+                    notifyTask.getTitle(), 
+                    notifyTask.getContent(),url
+            );
+            
+            if (success) {
+                log.info("浼佷笟寰俊娑堟伅鍙戦�佹垚鍔燂紝userId={}", notifyTask.getUserId());
+            } else {
+                log.warn("浼佷笟寰俊娑堟伅鍙戦�佸け璐ワ紝userId={}", notifyTask.getUserId());
+            }
+            return success;
+        } catch (Exception e) {
+            log.error("浼佷笟寰俊娑堟伅鍙戦�佸紓甯革紝taskId={}, userId={}", notifyTask.getTaskId(), notifyTask.getUserId(), e);
+            return false;
+        }
+    }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifySendLogServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifySendLogServiceImpl.java
index f671855..3d37ef3 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifySendLogServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotifySendLogServiceImpl.java
@@ -49,6 +49,14 @@
     }
 
     /**
+     * 鏍规嵁浠诲姟ID鍜岀敤鎴稩D鏌ヨ鍙戦�佽褰�
+     */
+    @Override
+    public NotifySendLog selectNotifySendLog(Long taskId, Long userId, String notifyType, String channel) {
+        return notifySendLogMapper.selectNotifySendLog(taskId, userId, notifyType, channel);
+    }
+
+    /**
      * 妫�鏌ユ槸鍚﹀凡鍙戦�佽繃閫氱煡锛堥槻閲嶆鏌ワ級
      * 
      * @param taskId 浠诲姟ID
@@ -114,18 +122,29 @@
     }
 
     /**
-     * 鏇存柊鍙戦�佺姸鎬佷负鎴愬姛
+     * 鏇存柊鍙戦�佺姸鎬佷负鎴愬姛锛堝悜鍚庡吋瀹癸級
      * 
      * @param id 璁板綍ID
      * @param result 鍙戦�佺粨鏋滀俊鎭�
      */
-    @Override
     public void markSendSuccess(Long id, String result) {
+        markSendSuccess(id, result, null);
+    }
+
+    /**
+     * 鏇存柊鍙戦�佺姸鎬佷负鎴愬姛
+     * 
+     * @param id 璁板綍ID
+     * @param result 鍙戦�佺粨鏋滀俊鎭�
+     * @param content 鍙戦�佸唴瀹�
+     */
+    @Override
+    public void markSendSuccess(Long id, String result, String content) {
         if (id == null) {
             return;
         }
         try {
-            notifySendLogMapper.updateSendStatus(id, NotifySendLog.SEND_STATUS_SUCCESS, result);
+            notifySendLogMapper.updateSendStatus(id, NotifySendLog.SEND_STATUS_SUCCESS, result, content);
             log.debug("鏇存柊閫氱煡鍙戦�佺姸鎬佷负鎴愬姛锛宨d={}", id);
         } catch (Exception e) {
             log.error("鏇存柊閫氱煡鍙戦�佺姸鎬佸け璐ワ紝id={}", id, e);
@@ -133,13 +152,24 @@
     }
 
     /**
-     * 鏇存柊鍙戦�佺姸鎬佷负澶辫触
+     * 鏇存柊鍙戦�佺姸鎬佷负澶辫触锛堝悜鍚庡吋瀹癸級
      * 
      * @param id 璁板綍ID
      * @param errorMsg 閿欒淇℃伅
      */
-    @Override
     public void markSendFailed(Long id, String errorMsg) {
+        markSendFailed(id, errorMsg, null);
+    }
+
+    /**
+     * 鏇存柊鍙戦�佺姸鎬佷负澶辫触
+     * 
+     * @param id 璁板綍ID
+     * @param errorMsg 閿欒淇℃伅
+     * @param content 鍙戦�佸唴瀹�
+     */
+    @Override
+    public void markSendFailed(Long id, String errorMsg, String content) {
         if (id == null) {
             return;
         }
@@ -148,7 +178,7 @@
             if (errorMsg != null && errorMsg.length() > 500) {
                 errorMsg = errorMsg.substring(0, 500);
             }
-            notifySendLogMapper.updateSendStatus(id, NotifySendLog.SEND_STATUS_FAILED, errorMsg);
+            notifySendLogMapper.updateSendStatus(id, NotifySendLog.SEND_STATUS_FAILED, errorMsg, content);
             log.debug("鏇存柊閫氱煡鍙戦�佺姸鎬佷负澶辫触锛宨d={}, error={}", id, errorMsg);
         } catch (Exception e) {
             log.error("鏇存柊閫氱煡鍙戦�佺姸鎬佸け璐ワ紝id={}", id, e);
@@ -207,7 +237,7 @@
      * @param maxRetryCount 鏈�澶ч噸璇曟鏁�
      * @return 澶辫触璁板綍鍒楄〃
      */
-    @Override
+
     public List<NotifySendLog> selectFailedNotifySendLogs(Integer maxRetryCount) {
         return notifySendLogMapper.selectFailedNotifySendLogs(maxRetryCount);
     }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QyWechatAccessTokenServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QyWechatAccessTokenServiceImpl.java
new file mode 100644
index 0000000..534a865
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QyWechatAccessTokenServiceImpl.java
@@ -0,0 +1,285 @@
+package com.ruoyi.system.service.impl;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.IQyWechatAccessTokenService;
+import com.ruoyi.system.service.ISysConfigService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 浼佷笟寰俊AccessToken鏈嶅姟瀹炵幇绫�
+ * 
+ * @author ruoyi
+ * @date 2025-12-11
+ */
+@Service
+public class QyWechatAccessTokenServiceImpl implements IQyWechatAccessTokenService {
+
+    private static final Logger log = LoggerFactory.getLogger(QyWechatAccessTokenServiceImpl.class);
+
+    @Autowired
+    private ISysConfigService configService;
+
+    /**
+     * 浼佷笟寰俊鑾峰彇access_token鐨刄RL
+     */
+    private static final String GET_ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
+
+    /**
+     * 鑾峰彇浼佷笟寰俊搴旂敤鐨凙ccessToken
+     *
+     * @param corpId 浼佷笟ID
+     * @param corpSecret 搴旂敤瀵嗛挜
+     * @return AccessToken
+     */
+    @Override
+    public String getAppAccessToken(String corpId, String corpSecret) {
+        try {
+            // 鍙傛暟鏍¢獙
+            if (StringUtils.isEmpty(corpId) || StringUtils.isEmpty(corpSecret)) {
+                log.warn("浼佷笟寰俊閰嶇疆鍙傛暟涓嶅畬鏁达紝corpId鎴朿orpSecret涓虹┖");
+                return null;
+            }
+
+            // 妫�鏌ユ湇鍔℃槸鍚﹀惎鐢�
+            if (!isEnabled()) {
+                log.info("浼佷笟寰俊鏈嶅姟宸茬鐢紝鏃犳硶鑾峰彇AccessToken");
+                return null;
+            }
+
+            // 鏋勫缓閰嶇疆閿悕
+            String tokenKey = "qy_wechat.access_token." + corpId;
+            String expiresKey = "qy_wechat.access_token_expires." + corpId;
+
+            // 浠庨厤缃腑鑾峰彇Token鍜岃繃鏈熸椂闂�
+            String accessToken = configService.selectConfigByKey(tokenKey);
+            String expiresStr = configService.selectConfigByKey(expiresKey);
+
+            // 妫�鏌oken鏄惁瀛樺湪涓旀湭杩囨湡
+            if (StringUtils.isNotEmpty(accessToken) && StringUtils.isNotEmpty(expiresStr)) {
+                try {
+                    long expiresTime = Long.parseLong(expiresStr);
+                    long currentTime = System.currentTimeMillis();
+
+                    // 棰勭暀60绉掑畨鍏ㄨ竟鐣岋紝閬垮厤涓寸晫鐐硅繃鏈�
+                    if (currentTime < expiresTime - 60000) {
+                        log.debug("浣跨敤缂撳瓨鐨勪紒涓氬井淇ccessToken锛屽墿浣欐湁鏁堟椂闂�: {}绉�", 
+                            (expiresTime - currentTime) / 1000);
+                        return accessToken;
+                    } else {
+                        log.info("浼佷笟寰俊AccessToken宸茶繃鏈熸垨鍗冲皢杩囨湡锛岄渶瑕佸埛鏂�");
+                    }
+                } catch (NumberFormatException e) {
+                    log.warn("瑙f瀽浼佷笟寰俊AccessToken杩囨湡鏃堕棿澶辫触: {}", expiresStr);
+                }
+            }
+
+            // Token涓嶅瓨鍦ㄦ垨宸茶繃鏈燂紝鍒锋柊Token
+            return refreshAppAccessToken(corpId, corpSecret);
+        } catch (Exception e) {
+            log.error("鑾峰彇浼佷笟寰俊AccessToken澶辫触", e);
+            return null;
+        }
+    }
+
+    /**
+     * 鍒锋柊浼佷笟寰俊搴旂敤鐨凙ccessToken
+     *
+     * @param corpId 浼佷笟ID
+     * @param corpSecret 搴旂敤瀵嗛挜
+     * @return 鏂扮殑AccessToken
+     */
+    @Override
+    public String refreshAppAccessToken(String corpId, String corpSecret) {
+        try {
+            log.info("寮�濮嬪埛鏂颁紒涓氬井淇ccessToken");
+
+            // 鏋勫缓璇锋眰URL
+            String url = GET_ACCESS_TOKEN_URL + "?corpid=" + corpId + "&corpsecret=" + corpSecret;
+
+            // 鍙戦�丠TTP璇锋眰鑾峰彇Token
+            String response = sendHttpGetRequest(url);
+            
+            if (StringUtils.isEmpty(response)) {
+                log.error("鑾峰彇浼佷笟寰俊AccessToken澶辫触锛屽搷搴斾负绌�");
+                return null;
+            }
+
+            // 瑙f瀽鍝嶅簲
+            QyWechatTokenResponse tokenResponse = parseTokenResponse(response);
+            
+            if (tokenResponse == null || StringUtils.isEmpty(tokenResponse.getAccessToken())) {
+                log.error("瑙f瀽浼佷笟寰俊AccessToken鍝嶅簲澶辫触: {}", response);
+                return null;
+            }
+
+            // 璁$畻杩囨湡鏃堕棿锛堝綋鍓嶆椂闂� + 鏈夋晥鏈� - 60绉掑畨鍏ㄨ竟鐣岋級
+            long expiresTime = System.currentTimeMillis() + (tokenResponse.getExpiresIn() * 1000L) - 60000L;
+
+            // 鏋勫缓閰嶇疆閿悕
+            String tokenKey = "qy_wechat.access_token." + corpId;
+            String expiresKey = "qy_wechat.access_token_expires." + corpId;
+
+            // 淇濆瓨鍒扮郴缁熼厤缃〃
+            configService.updateConfigValue(tokenKey, tokenResponse.getAccessToken());
+            configService.updateConfigValue(expiresKey, String.valueOf(expiresTime));
+
+            log.info("浼佷笟寰俊AccessToken鍒锋柊鎴愬姛锛屾湁鏁堟湡: {}绉�", tokenResponse.getExpiresIn());
+            return tokenResponse.getAccessToken();
+        } catch (Exception e) {
+            log.error("鍒锋柊浼佷笟寰俊AccessToken澶辫触", e);
+            return null;
+        }
+    }
+
+    /**
+     * 妫�鏌ヤ紒涓氬井淇℃湇鍔℃槸鍚﹀惎鐢�
+     *
+     * @return true-鍚敤锛宖alse-绂佺敤
+     */
+    @Override
+    public boolean isEnabled() {
+        try {
+            String enabled = configService.selectConfigByKey("qy_wechat.enable");
+            return !"false".equals(enabled); // 榛樿鍚敤
+        } catch (Exception e) {
+            log.warn("鑾峰彇浼佷笟寰俊鏈嶅姟鍚敤鐘舵�佸け璐ワ紝浣跨敤榛樿鍊�(true)", e);
+            return true;
+        }
+    }
+
+    /**
+     * 鍙戦�丠TTP GET璇锋眰
+     * 
+     * @param url 璇锋眰URL
+     * @return 鍝嶅簲鍐呭
+     */
+    private String sendHttpGetRequest(String url) {
+        try {
+            java.net.HttpURLConnection conn = (java.net.HttpURLConnection) new java.net.URL(url).openConnection();
+            conn.setRequestMethod("GET");
+            conn.setConnectTimeout(5000);
+            conn.setReadTimeout(5000);
+
+            int responseCode = conn.getResponseCode();
+            if (responseCode == 200) {
+                java.io.BufferedReader reader = new java.io.BufferedReader(
+                    new java.io.InputStreamReader(conn.getInputStream(), "UTF-8"));
+                StringBuilder response = new StringBuilder();
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    response.append(line);
+                }
+                reader.close();
+                return response.toString();
+            } else {
+                log.error("HTTP璇锋眰澶辫触锛屽搷搴旂爜: {}", responseCode);
+                return null;
+            }
+        } catch (Exception e) {
+            log.error("鍙戦�丠TTP璇锋眰澶辫触", e);
+            return null;
+        }
+    }
+
+    /**
+     * 瑙f瀽浼佷笟寰俊Token鍝嶅簲
+     * 
+     * @param response 鍝嶅簲JSON
+     * @return Token鍝嶅簲瀵硅薄
+     */
+    private QyWechatTokenResponse parseTokenResponse(String response) {
+        try {
+            // 绠�鍗旿SON瑙f瀽锛堝疄闄呴」鐩腑寤鸿浣跨敤Jackson鎴朑son锛�
+            // 绀轰緥鍝嶅簲: {"errcode":0,"errmsg":"ok","access_token":"xxxxxx","expires_in":7200}
+            
+            // 绉婚櫎鑺辨嫭鍙�
+            String content = response.substring(1, response.length() - 1);
+            
+            // 鎸夐�楀彿鍒嗗壊
+            String[] pairs = content.split(",");
+            
+            QyWechatTokenResponse tokenResponse = new QyWechatTokenResponse();
+            
+            for (String pair : pairs) {
+                String[] keyValue = pair.split(":");
+                if (keyValue.length == 2) {
+                    String key = keyValue[0].trim().replaceAll("\"", "");
+                    String value = keyValue[1].trim().replaceAll("\"", "");
+                    
+                    switch (key) {
+                        case "errcode":
+                            tokenResponse.setErrcode(Integer.parseInt(value));
+                            break;
+                        case "errmsg":
+                            tokenResponse.setErrmsg(value);
+                            break;
+                        case "access_token":
+                            tokenResponse.setAccessToken(value);
+                            break;
+                        case "expires_in":
+                            tokenResponse.setExpiresIn(Integer.parseInt(value));
+                            break;
+                    }
+                }
+            }
+            
+            // 妫�鏌ユ槸鍚︽湁閿欒
+            if (tokenResponse.getErrcode() != 0) {
+                log.error("鑾峰彇浼佷笟寰俊AccessToken澶辫触锛岄敊璇爜: {}, 閿欒淇℃伅: {}", 
+                    tokenResponse.getErrcode(), tokenResponse.getErrmsg());
+                return null;
+            }
+            
+            return tokenResponse;
+        } catch (Exception e) {
+            log.error("瑙f瀽浼佷笟寰俊Token鍝嶅簲澶辫触: {}", response, e);
+            return null;
+        }
+    }
+
+    /**
+     * 浼佷笟寰俊Token鍝嶅簲鍐呴儴绫�
+     */
+    private static class QyWechatTokenResponse {
+        private int errcode;
+        private String errmsg;
+        private String accessToken;
+        private int expiresIn;
+
+        // Getters and Setters
+        public int getErrcode() {
+            return errcode;
+        }
+
+        public void setErrcode(int errcode) {
+            this.errcode = errcode;
+        }
+
+        public String getErrmsg() {
+            return errmsg;
+        }
+
+        public void setErrmsg(String errmsg) {
+            this.errmsg = errmsg;
+        }
+
+        public String getAccessToken() {
+            return accessToken;
+        }
+
+        public void setAccessToken(String accessToken) {
+            this.accessToken = accessToken;
+        }
+
+        public int getExpiresIn() {
+            return expiresIn;
+        }
+
+        public void setExpiresIn(int expiresIn) {
+            this.expiresIn = expiresIn;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QyWechatServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QyWechatServiceImpl.java
new file mode 100644
index 0000000..8615f04
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/QyWechatServiceImpl.java
@@ -0,0 +1,431 @@
+package com.ruoyi.system.service.impl;
+
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.domain.QyWechatArticle;
+import com.ruoyi.system.mapper.SysUserMapper;
+import com.ruoyi.system.service.IQyWechatAccessTokenService;
+import com.ruoyi.system.service.IQyWechatService;
+import com.ruoyi.system.service.ISysConfigService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 浼佷笟寰俊鏈嶅姟瀹炵幇绫�
+ * 
+ * @author ruoyi
+ * @date 2025-12-11
+ */
+@Service
+public class QyWechatServiceImpl implements IQyWechatService {
+
+    private static final Logger log = LoggerFactory.getLogger(QyWechatServiceImpl.class);
+
+    @Autowired
+    private IQyWechatAccessTokenService qyWechatAccessTokenService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private SysUserMapper userMapper;
+
+    /**
+     * 鍙戦�佷紒涓氬井淇℃秷鎭�
+     */
+    @Override
+    public boolean sendNotifyMessage(Long userId, String title, String content,String notifyUrl) {
+        try {
+            // 妫�鏌ユ湇鍔℃槸鍚﹀惎鐢�
+            if (!isEnabled()) {
+                log.info("浼佷笟寰俊鏈嶅姟鏈惎鐢紝璺宠繃娑堟伅鍙戦��");
+                return false;
+            }
+
+            // 鑾峰彇鐢ㄦ埛鐨勪紒涓氬井淇D
+            String qyUserId = getQyUserIdByUserId(userId);
+            if (StringUtils.isEmpty(qyUserId)) {
+                log.warn("鐢ㄦ埛{}鏈粦瀹氫紒涓氬井淇D锛屾棤娉曞彂閫佹秷鎭�", userId);
+                return false;
+            }
+
+            // 鍙戦�佹枃鏈秷鎭�
+            return sendTextMessage(qyUserId, title, content, notifyUrl);
+        } catch (Exception e) {
+            log.error("浼佷笟寰俊娑堟伅鍙戦�佸紓甯革紝userId={}", userId, e);
+            return false;
+        }
+    }
+
+    /**
+     * 鍙戦�佷紒涓氬井淇℃枃鏈秷鎭�
+     */
+    @Override
+    public boolean sendTextMessage(String qyUserId, String title, String content, String notifyUrl) {
+        try {
+            // 妫�鏌ユ湇鍔℃槸鍚﹀惎鐢�
+            if (!isEnabled()) {
+                log.info("浼佷笟寰俊鏈嶅姟鏈惎鐢紝璺宠繃娑堟伅鍙戦��");
+                return false;
+            }
+
+            // 鑾峰彇浼佷笟寰俊閰嶇疆
+            String corpId = configService.selectConfigByKey("qy_wechat.corp_id");
+            String corpSecret = configService.selectConfigByKey("qy_wechat.corp_secret");
+
+            if (StringUtils.isEmpty(corpId) || StringUtils.isEmpty(corpSecret)) {
+                log.error("浼佷笟寰俊閰嶇疆涓嶅畬鏁达紝缂哄皯corpId鎴朿orpSecret");
+                return false;
+            }
+
+            // 鑾峰彇AccessToken
+            String accessToken = qyWechatAccessTokenService.getAppAccessToken(corpId, corpSecret);
+            if (StringUtils.isEmpty(accessToken)) {
+                log.error("鑾峰彇浼佷笟寰俊AccessToken澶辫触");
+                return false;
+            }
+
+            // 鏋勯�犺姹俇RL
+            String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken;
+
+            // 鏋勯�犳枃绔犲璞�
+            QyWechatArticle article = new QyWechatArticle();
+            article.setTitle(title);
+            article.setDescription(content);
+            article.setUrl(notifyUrl);
+            // 璁剧疆榛樿鍥剧墖URL锛屾偍鍙互鏍规嵁闇�瑕佷慨鏀�
+            
+
+            // 鏋勯�犺姹傚弬鏁�
+            Map<String, Object> params = new HashMap<>();
+            params.put("touser", qyUserId);
+            params.put("msgtype", "news");
+            params.put("agentid", Integer.parseInt(configService.selectConfigByKey("qy_wechat.agent_id")));
+            
+            // 鏋勯�犳枃绔犲垪琛�
+            List<QyWechatArticle> articles = new ArrayList<>();
+            articles.add(article);
+            params.put("news", Collections.singletonMap("articles", articles));
+
+            // 鍙戦�丠TTP POST璇锋眰
+            String response = sendHttpPostRequest(url, params);
+
+            if (StringUtils.isEmpty(response)) {
+                log.error("鍙戦�佷紒涓氬井淇℃秷鎭け璐ワ紝鍝嶅簲涓虹┖");
+                return false;
+            }
+
+            // 瑙f瀽鍝嶅簲缁撴灉
+            QyWechatResponse result = parseResponse(response);
+
+            if (result != null && result.getErrcode() == 0) {
+                log.info("浼佷笟寰俊娑堟伅鍙戦�佹垚鍔燂紝鐢ㄦ埛ID: {}", qyUserId);
+                return true;
+            } else {
+                log.error("浼佷笟寰俊娑堟伅鍙戦�佸け璐ワ紝閿欒鐮�: {}, 閿欒淇℃伅: {}",
+                        result != null ? result.getErrcode() : "unknown",
+                        result != null ? result.getErrmsg() : response);
+                return false;
+            }
+        } catch (Exception e) {
+            log.error("浼佷笟寰俊鏂囨湰娑堟伅鍙戦�佸紓甯革紝qyUserId={}", qyUserId, e);
+            return false;
+        }
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛鐨勪紒涓氬井淇D
+     */
+    @Override
+    public String getQyUserIdByUserId(Long userId) {
+        try {
+            if (userId == null) {
+                log.warn("鐢ㄦ埛ID涓嶈兘涓虹┖");
+                return null;
+            }
+
+            // 鏌ヨ鐢ㄦ埛淇℃伅
+            SysUser user = userMapper.selectUserById(userId);
+            if (user == null) {
+                log.warn("鏈壘鍒扮敤鎴凤紝userId={}", userId);
+                return null;
+            }
+
+            // 杩斿洖浼佷笟寰俊鐢ㄦ埛ID
+            return user.getQyWechatUserId();
+        } catch (Exception e) {
+            log.error("鑾峰彇鐢ㄦ埛浼佷笟寰俊ID寮傚父锛寀serId={}", userId, e);
+            return null;
+        }
+    }
+
+    /**
+     * 妫�鏌ヤ紒涓氬井淇℃湇鍔℃槸鍚﹀惎鐢�
+     */
+    @Override
+    public boolean isEnabled() {
+        try {
+            String enabled = configService.selectConfigByKey("qy_wechat.enable");
+            return "true".equals(enabled);
+        } catch (Exception e) {
+            log.warn("鑾峰彇浼佷笟寰俊鏈嶅姟鍚敤鐘舵�佸け璐ワ紝浣跨敤榛樿鍊�(false)", e);
+            return false;
+        }
+    }
+
+    /**
+     * 鍙戦�丠TTP POST璇锋眰
+     *
+     * @param url    璇锋眰URL
+     * @param params 璇锋眰鍙傛暟
+     * @return 鍝嶅簲鍐呭
+     */
+    private String sendHttpPostRequest(String url, Map<String, Object> params) {
+        try {
+            // 灏嗗弬鏁拌浆鎹负JSON瀛楃涓�
+            String jsonParams = toJsonString(params);
+
+            java.net.HttpURLConnection conn = (java.net.HttpURLConnection) new java.net.URL(url).openConnection();
+            conn.setRequestMethod("POST");
+            conn.setConnectTimeout(5000);
+            conn.setReadTimeout(5000);
+            conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+            conn.setDoOutput(true);
+
+            // 鍙戦�佽姹傛暟鎹�
+            java.io.OutputStream os = conn.getOutputStream();
+            os.write(jsonParams.getBytes("UTF-8"));
+            os.flush();
+            os.close();
+
+            int responseCode = conn.getResponseCode();
+            if (responseCode == 200) {
+                java.io.BufferedReader reader = new java.io.BufferedReader(
+                        new java.io.InputStreamReader(conn.getInputStream(), "UTF-8"));
+                StringBuilder response = new StringBuilder();
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    response.append(line);
+                }
+                reader.close();
+                return response.toString();
+            } else {
+                log.error("HTTP璇锋眰澶辫触锛屽搷搴旂爜: {}", responseCode);
+                return null;
+            }
+        } catch (Exception e) {
+            log.error("鍙戦�丠TTP POST璇锋眰澶辫触", e);
+            return null;
+        }
+    }
+
+    /**
+     * 绠�鍗曠殑JSON搴忓垪鍖栨柟娉�
+     *
+     * @param map 瑕佸簭鍒楀寲鐨凪ap
+     * @return JSON瀛楃涓�
+     */
+    private String toJsonString(Map<String, Object> map) {
+        StringBuilder json = new StringBuilder("{");
+        boolean first = true;
+
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            if (!first) {
+                json.append(",");
+            }
+
+            json.append("\"").append(entry.getKey()).append("\":");
+
+            Object value = entry.getValue();
+            if (value instanceof String) {
+                json.append("\"").append(value).append("\"");
+            } else if (value instanceof Map) {
+                // 澶勭悊宓屽Map
+                json.append(toJsonString((Map<String, Object>) value));
+            } else if (value instanceof List) {
+                // 澶勭悊鍒楄〃
+                json.append(toJsonList((List<Object>) value));
+            } else {
+                json.append(value);
+            }
+
+            first = false;
+        }
+
+        json.append("}");
+        return json.toString();
+    }
+
+    /**
+     * 搴忓垪鍖栧垪琛ㄤ负JSON
+     *
+     * @param list 鍒楄〃
+     * @return JSON瀛楃涓�
+     */
+    private String toJsonList(List<Object> list) {
+        StringBuilder json = new StringBuilder("[");
+        boolean first = true;
+
+        for (Object item : list) {
+            if (!first) {
+                json.append(",");
+            }
+
+            if (item instanceof String) {
+                json.append("\"").append(item).append("\"");
+            } else if (item instanceof Map) {
+                json.append(toJsonString((Map<String, Object>) item));
+            } else if (item instanceof QyWechatArticle) {
+                json.append(toJsonArticle((QyWechatArticle) item));
+            } else {
+                json.append(item);
+            }
+
+            first = false;
+        }
+
+        json.append("]");
+        return json.toString();
+    }
+
+    /**
+     * 搴忓垪鍖栨枃绔犲璞′负JSON
+     *
+     * @param article 鏂囩珷瀵硅薄
+     * @return JSON瀛楃涓�
+     */
+    private String toJsonArticle(QyWechatArticle article) {
+        StringBuilder json = new StringBuilder("{");
+        boolean first = true;
+
+        // 娣诲姞闈炵┖瀛楁
+        if (article.getTitle() != null) {
+            if (!first) json.append(",");
+            json.append("\"title\":\"").append(escapeJsonString(article.getTitle())).append("\"");
+            first = false;
+        }
+        if (article.getDescription() != null) {
+            if (!first) json.append(",");
+            json.append("\"description\":\"").append(escapeJsonString(article.getDescription())).append("\"");
+            first = false;
+        }
+        if (article.getUrl() != null) {
+            if (!first) json.append(",");
+            json.append("\"url\":\"").append(escapeJsonString(article.getUrl())).append("\"");
+            first = false;
+        }
+        if (article.getPicurl() != null) {
+            if (!first) json.append(",");
+            json.append("\"picurl\":\"").append(escapeJsonString(article.getPicurl())).append("\"");
+            first = false;
+        }
+        if (article.getAppid() != null) {
+            if (!first) json.append(",");
+            json.append("\"appid\":\"").append(escapeJsonString(article.getAppid())).append("\"");
+            first = false;
+        }
+        if (article.getPagepath() != null) {
+            if (!first) json.append(",");
+            json.append("\"pagepath\":\"").append(escapeJsonString(article.getPagepath())).append("\"");
+            first = false;
+        }
+
+        json.append("}");
+        return json.toString();
+    }
+
+    /**
+     * 杞箟JSON瀛楃涓蹭腑鐨勭壒娈婂瓧绗�
+     *
+     * @param str 鍘熷瀛楃涓�
+     * @return 杞箟鍚庣殑瀛楃涓�
+     */
+    private String escapeJsonString(String str) {
+        if (str == null) return "";
+        return str.replace("\\", "\\\\")
+                 .replace("\"", "\\\"")
+                 .replace("\n", "\\n")
+                 .replace("\r", "\\r")
+                 .replace("\t", "\\t");
+    }
+
+    /**
+     * 瑙f瀽浼佷笟寰俊鍝嶅簲
+     *
+     * @param response 鍝嶅簲JSON
+     * @return 鍝嶅簲瀵硅薄
+     */
+    private QyWechatResponse parseResponse(String response) {
+        try {
+            // 浣跨敤绠�鍗旿SON瑙f瀽
+            QyWechatResponse result = new QyWechatResponse();
+            
+            // 绉婚櫎棣栧熬鑺辨嫭鍙�
+            String content = response.trim();
+            if (content.startsWith("{")) {
+                content = content.substring(1);
+            }
+            if (content.endsWith("}")) {
+                content = content.substring(0, content.length() - 1);
+            }
+            
+            // 鎸夐�楀彿鍒嗗壊閿�煎
+            String[] pairs = content.split(",");
+            
+            for (String pair : pairs) {
+                String[] keyValue = pair.split(":", 2); // 鍙垎鍓茬涓�涓啋鍙�
+                if (keyValue.length == 2) {
+                    String key = keyValue[0].trim().replaceAll("\"", "");
+                    String value = keyValue[1].trim().replaceAll("\"", "");
+                    
+                    switch (key) {
+                        case "errcode":
+                            result.setErrcode(Integer.parseInt(value));
+                            break;
+                        case "errmsg":
+                            result.setErrmsg(value);
+                            break;
+                    }
+                }
+            }
+            
+            return result;
+        } catch (Exception e) {
+            log.error("瑙f瀽浼佷笟寰俊鍝嶅簲澶辫触: {}", response, e);
+            return null;
+        }
+    }
+
+    /**
+     * 浼佷笟寰俊鍝嶅簲鍐呴儴绫�
+     */
+    private static class QyWechatResponse {
+        private int errcode;
+        private String errmsg;
+
+        // Getters and Setters
+        public int getErrcode() {
+            return errcode;
+        }
+
+        public void setErrcode(int errcode) {
+            this.errcode = errcode;
+        }
+
+        public String getErrmsg() {
+            return errmsg;
+        }
+
+        public void setErrmsg(String errmsg) {
+            this.errmsg = errmsg;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
index 4d29b22..0f41ee0 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
@@ -220,6 +220,47 @@
     }
 
     /**
+     * 鏇存柊閰嶇疆鍊�
+     * 
+     * @param configKey 鍙傛暟閿悕
+     * @param configValue 鍙傛暟鍊�
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateConfigValue(String configKey, String configValue) {
+        // 鍏堟煡璇㈡槸鍚﹀瓨鍦ㄨ閰嶇疆椤�
+        SysConfig config = new SysConfig();
+        config.setConfigKey(configKey);
+        SysConfig existingConfig = configMapper.selectConfig(config);
+        
+        if (existingConfig != null) {
+            // 濡傛灉瀛樺湪锛屾洿鏂伴厤缃��
+            existingConfig.setConfigValue(configValue);
+            existingConfig.setUpdateTime(new java.util.Date());
+            int result = configMapper.updateConfig(existingConfig);
+            // 鏇存柊缂撳瓨
+            if (result > 0) {
+                redisCache.setCacheObject(getCacheKey(configKey), configValue);
+            }
+            return result;
+        } else {
+            // 濡傛灉涓嶅瓨鍦紝鍒涘缓鏂扮殑閰嶇疆椤�
+            SysConfig newConfig = new SysConfig();
+            newConfig.setConfigKey(configKey);
+            newConfig.setConfigValue(configValue);
+            newConfig.setConfigName("浼佷笟寰俊閰嶇疆");
+            newConfig.setConfigType("N"); // 闈炵郴缁熷唴缃�
+            newConfig.setCreateBy("system");
+            int result = configMapper.insertConfig(newConfig);
+            // 鏇存柊缂撳瓨
+            if (result > 0) {
+                redisCache.setCacheObject(getCacheKey(configKey), configValue);
+            }
+            return result;
+        }
+    }
+
+    /**
      * 璁剧疆cache key
      * 
      * @param configKey 鍙傛暟閿�
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 20fcac3..f85f37b 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
@@ -143,6 +143,21 @@
         emergencyInfo.setCreateBy(createUserName);
         emergencyInfo.setUpdateBy(createUserName);
 
+        if(createVO.getLegacyDispatchNsTime() != null){
+            emergencyInfo.setLegacyDispatchNsTime(createVO.getLegacyDispatchNsTime());
+        }
+        if(createVO.getLegacyDispatchOrdClass() != null){
+            emergencyInfo.setLegacyDispatchOrdClass(createVO.getLegacyDispatchOrdClass());
+        }
+        if(createVO.getLegacyDispatchOrdNo() != null){
+            emergencyInfo.setLegacyDispatchOrdNo(createVO.getLegacyDispatchOrdNo());
+        }
+        if(createVO.getLegacyServiceNsTime() != null){
+            emergencyInfo.setLegacyServiceNsTime(createVO.getLegacyServiceNsTime());
+        }
+        if(createVO.getLegacyServiceOrdClass() != null){
+            emergencyInfo.setLegacyServiceOrdClass(createVO.getLegacyServiceOrdClass());
+        }
         sysTaskEmergencyMapper.insertSysTaskEmergency(emergencyInfo);
     }
 
@@ -276,7 +291,28 @@
         oldEmergency.setUpdateTime(DateUtils.getNowDate());
         oldEmergency.setUpdateBy(userName);
 
+        if( updateVO.getLegacyDispatchNsTime() != null) {
+            oldEmergency.setLegacyDispatchNsTime(updateVO.getLegacyDispatchNsTime());
+        }
+        if( updateVO.getLegacyServiceNsTime() != null){
+            oldEmergency.setLegacyServiceNsTime(updateVO.getLegacyServiceNsTime());
+        }
+        if( updateVO.getLegacyDispatchOrdClass() != null){
+            oldEmergency.setLegacyDispatchOrdClass(updateVO.getLegacyDispatchOrdClass());
+        }
+        if( updateVO.getLegacyDispatchOrdNo() != null){
+            oldEmergency.setLegacyDispatchOrdNo(updateVO.getLegacyDispatchOrdNo());
+        }
+        if( updateVO.getLegacyServiceOrdClass() != null){
+            oldEmergency.setLegacyServiceOrdClass(updateVO.getLegacyServiceOrdClass());
+        }
+
         sysTaskEmergencyMapper.updateSysTaskEmergency(oldEmergency);
+    }
+
+    @Override
+    public SysTaskEmergency selectSysTaskEmergencyByTaskId(Long taskId) {
+        return sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
     }
 
     @Override
@@ -420,6 +456,22 @@
         // 绯荤粺瀛楁
         existingInfo.setUpdateTime(DateUtils.getNowDate());
         existingInfo.setUpdateBy(userName);
+
+        if(createVO.getLegacyDispatchNsTime() != null){
+            existingInfo.setLegacyDispatchNsTime(createVO.getLegacyDispatchNsTime());
+        }
+        if(createVO.getLegacyDispatchOrdNo() != null){
+            existingInfo.setLegacyDispatchOrdNo(createVO.getLegacyDispatchOrdNo());
+        }
+        if(createVO.getLegacyServiceNsTime() != null){
+            existingInfo.setLegacyServiceNsTime(createVO.getLegacyServiceNsTime());
+        }
+        if(createVO.getLegacyDispatchOrdClass() != null){
+            existingInfo.setLegacyDispatchOrdClass(createVO.getLegacyDispatchOrdClass());
+        }
+        if(createVO.getLegacyServiceOrdClass() != null){
+            existingInfo.setLegacyServiceOrdClass(createVO.getLegacyServiceOrdClass());
+        }
         
         // 鎵ц鏇存柊
         sysTaskEmergencyMapper.updateSysTaskEmergency(existingInfo);
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 d9c04d5..0644f40 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
@@ -10,6 +10,7 @@
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.system.domain.vo.*;
+import com.ruoyi.system.event.TaskDispatchSyncEvent;
 import com.ruoyi.system.mapper.*;
 import com.ruoyi.system.service.*;
 import com.ruoyi.system.utils.TaskCodeGenerator;
@@ -100,6 +101,16 @@
     @Autowired
     private ISysTaskVehicleService sysTaskVehicleService;
 
+    @Override
+    public Boolean dispatchSyncEvent(Long taskId) {
+        SysTask task= sysTaskMapper.selectSysTaskByTaskId(taskId);
+        SysUser user= sysUserMapper.selectUserById(task.getCreatorId());
+        Integer oaUser=user.getOaUserId();
+        SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
+        eventPublisher.publishEvent(new TaskDispatchSyncEvent(this, taskId, task.getTaskCode(),emergency.getLegacyServiceOrdId(), emergency.getLegacyDispatchOrdId(),oaUser));
+        return true;
+    }
+
     /**
      * 鏌ヨ浠诲姟绠$悊
      * 
@@ -132,7 +143,68 @@
      */
     @Override
     public List<SysTask> selectSysTaskList(TaskQueryVO queryVO) {
-        return sysTaskMapper.selectSysTaskList(queryVO);
+        List<SysTask> tasks= sysTaskMapper.selectSysTaskList(queryVO);
+        tasks.forEach(task -> {
+            if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+                SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(task.getTaskId());
+                task.setEmergencyInfo(emergencyInfo);
+            }
+        });
+        return tasks;
+    }
+
+    /**
+     * 鏍规嵁浠诲姟缂栧彿銆佽皟搴﹀崟缂栧彿鎴栨湇鍔″崟缂栧彿鏌ヨ浠诲姟鍒楄〃
+     * 
+     * @param queryVO 浠诲姟鏌ヨ瀵硅薄
+     * @param taskCode 浠诲姟缂栧彿
+     * @return 浠诲姟绠$悊闆嗗悎
+     */
+    @Override
+    public List<SysTask> selectSysTaskListByMultiCode(TaskQueryVO queryVO, String taskCode) {
+        // Create a new query object without the taskCode filter
+        TaskQueryVO newQuery = new TaskQueryVO();
+        // Copy all properties except taskCode
+        try {
+            org.springframework.beans.BeanUtils.copyProperties(queryVO, newQuery, "taskCode");
+        } catch (Exception e) {
+            // If copy fails, manually copy the important fields
+            newQuery.setTaskType(queryVO.getTaskType());
+            newQuery.setTaskStatus(queryVO.getTaskStatus());
+            newQuery.setVehicleNo(queryVO.getVehicleNo());
+            newQuery.setCreatorId(queryVO.getCreatorId());
+            newQuery.setAssigneeId(queryVO.getAssigneeId());
+            newQuery.setDeptId(queryVO.getDeptId());
+            newQuery.setDeptIds(queryVO.getDeptIds());
+            newQuery.setPlannedStartTimeBegin(queryVO.getPlannedStartTimeBegin());
+            newQuery.setPlannedStartTimeEnd(queryVO.getPlannedStartTimeEnd());
+            newQuery.setPlannedEndTimeBegin(queryVO.getPlannedEndTimeBegin());
+            newQuery.setPlannedEndTimeEnd(queryVO.getPlannedEndTimeEnd());
+            newQuery.setOverdue(queryVO.getOverdue());
+        }
+
+        // Get all tasks matching the other criteria
+        List<SysTask> allTasks = sysTaskMapper.selectSysTaskList(newQuery);
+        allTasks.stream().forEach(task -> {
+            if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
+                SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(task.getTaskId());
+                task.setEmergencyInfo(emergencyInfo);
+            }
+        });
+        return allTasks.stream().filter(task -> {
+            if (task.getTaskCode() != null && task.getTaskCode().contains(taskCode)) {
+                return true;
+            }
+            if ("EMERGENCY_TRANSFER".equals(task.getTaskType()) && task.getEmergencyInfo() != null) {
+                String dispatchCode = task.getEmergencyInfo().getDispatchCode();
+                String serviceCode = task.getEmergencyInfo().getServiceCode();
+                return (dispatchCode != null && dispatchCode.contains(taskCode)) ||
+                        (serviceCode != null && serviceCode.contains(taskCode));
+            }
+            return false;
+
+        }).collect(Collectors.toList());
+
     }
 
     /**
@@ -215,10 +287,7 @@
             ));
         }
         
-        // 鍙戝竷浠诲姟鍒嗛厤浜嬩欢
-        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
-            this.sendTaskAssigneeEvent(createVO,task,SecurityUtils.getUserId(),SecurityUtils.getUsername());
-        }
+
         
         // 寮傛鍚屾鎬ユ晳杞繍浠诲姟鍒版棫绯荤粺
         if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType()) && legacySystemSyncService != null) {
@@ -341,10 +410,7 @@
             ));
         }
         
-        // 鍙戝竷浠诲姟鍒嗛厤浜嬩欢
-        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
-            this.sendTaskAssigneeEvent(createVO,task,userId,userName);
-        }
+
         
 
         
@@ -491,11 +557,12 @@
                 needResync = true;
             }
         }
-        
+        Long dispatchOrderId=0L;
         // 鏇存柊鎬ユ晳杞繍鎵╁睍淇℃伅锛堟娴嬪湴鍧�鍜屾垚浜や环鍙樻洿锛�
         if (result > 0 && "EMERGENCY_TRANSFER".equals(oldTask.getTaskType())) {
             SysTaskEmergency oldEmergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(updateVO.getTaskId());
             sysEmergencyTaskService.updateEmergencyInfoFromUpdateVO(oldEmergency, updateVO, userName);
+          dispatchOrderId=  oldEmergency.getLegacyDispatchOrdId();
             sysEmergencyTaskService.markNeedResyncIfNecessary(updateVO.getTaskId(), oldTask, updateVO, updateFromLegacy);
         }
         
@@ -518,7 +585,7 @@
                 userId, userName);
         }
 
-        if(result > 0 && oldTask.getTaskStatus().equals(TaskStatus.PENDING.getCode()) && updateVO.getAssignees() != null && !updateVO.getAssignees().isEmpty()){
+        if(result > 0 && oldTask.getTaskStatus().equals(TaskStatus.PENDING.getCode()) && updateVO.getAssignees() != null && !updateVO.getAssignees().isEmpty() && dispatchOrderId>0L){
 
             this.sendTaskAssigneeEvent(updateVO,oldTask,userId,userName);
         }
@@ -646,16 +713,14 @@
 //            log.info("鏇存柊鎵ц浜哄憳 ServiceOrdID:{},dispatchOrderId:{}",serviceOrderId,dispatchOrderId);
             sysTaskAssigneeService.updateTaskAssignees(taskId, updateVO.getAssignees(), userName);
         }
-        
+        Long dispatchOrderIdLong = 0L;
         // 鏇存柊鎬ユ晳杞繍鎵╁睍淇℃伅
         if (result > 0) {
             // 鏇存柊鏃х郴缁烮D
-            if (serviceOrderId != null) {
-                taskEmergency.setLegacyServiceOrdId(Long.parseLong(serviceOrderId));
-            }
+            taskEmergency.setLegacyServiceOrdId(Long.parseLong(serviceOrderId));
             if (dispatchOrderId != null) {
-                taskEmergency.setLegacyDispatchOrdId(Long.parseLong(dispatchOrderId));
-                taskEmergency.setLegacyDispatchOrdId(Long.parseLong(dispatchOrderId));
+                dispatchOrderIdLong = Long.parseLong(dispatchOrderId);
+                taskEmergency.setLegacyDispatchOrdId(dispatchOrderIdLong);
                 taskEmergency.setDispatchSyncStatus(2);
                 taskEmergency.setDispatchSyncTime(new Date());
                 taskEmergency.setDispatchSyncErrorMsg("鏃х郴缁熷悓姝ヨ繃鏉�");
@@ -666,16 +731,17 @@
             taskEmergency.setUpdateTime(DateUtils.getNowDate());
 
             Boolean hasEmergencyInfo = updateVO.getHospitalOut() != null || updateVO.getHospitalIn() != null || updateVO.getPatient() != null;
-//            log.info("鏇存柊杞繍浠诲姟淇℃伅 serviceOrdID:{},dispatchOrderId:{} hasEmergencyInfo:{}",serviceOrderId,
-//                    dispatchOrderId,hasEmergencyInfo);
+
 
             // 浣跨敤TaskCreateVO鐨勫瓧娈垫潵鏇存柊鎬ユ晳杞繍淇℃伅
             if (hasEmergencyInfo) {
                 sysEmergencyTaskService.updateEmergencyInfoFromCreateVO(taskEmergency, updateVO, userName);
             }
+           SysTaskEmergency emergency= sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
+            dispatchOrderIdLong = emergency.getLegacyDispatchOrdId();
         }
 
-        if(updateVO.getTaskStatus()!=null && updateVO.getTaskStatus().equals(TaskStatus.PENDING.getCode()) && updateVO.getAssignees()!=null && !updateVO.getAssignees().isEmpty()){
+        if(updateVO.getTaskStatus()!=null && updateVO.getTaskStatus().equals(TaskStatus.PENDING.getCode()) && updateVO.getAssignees()!=null && !updateVO.getAssignees().isEmpty() && dispatchOrderIdLong>0L){
             this.sendTaskAssigneeEvent(updateVO,task,userId,userName);
         }
         
@@ -1026,7 +1092,13 @@
      */
     @Override
     public List<SysTask> selectMyTasks(Long userId) {
-        return sysTaskMapper.selectMyTasks(userId);
+        List<SysTask> list = sysTaskMapper.selectMyTasks(userId);
+        list.stream().forEach(task -> {
+            if(task.getTaskType().equals("EMERGENCY_TRANSFER")){
+                task.setEmergencyInfo(sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(task.getTaskId()));
+            }
+        });
+        return list;
     }
 
     /**
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java
index 97e49ae..58689a0 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserSyncServiceImpl.java
@@ -227,6 +227,12 @@
         {
             existingUser.setCanViewAllConsult(dto.getCanViewAllConsult());
         }
+        // 鍚屾浼佷笟寰俊鐢ㄦ埛ID
+        if (StringUtils.isNotEmpty(dto.getOaWeixinUserId()))
+        {
+            existingUser.setQyWechatUserId(dto.getOaWeixinUserId());
+            existingUser.setQyWechatUpdateTime(new Date());
+        }
         sysUserMapper.updateUser(existingUser);
     }
 
@@ -248,6 +254,13 @@
             newUser.setCanViewAllConsult(dto.getCanViewAllConsult());
         }
         
+        // 璁剧疆浼佷笟寰俊鐢ㄦ埛ID
+        if (StringUtils.isNotEmpty(dto.getOaWeixinUserId()))
+        {
+            newUser.setQyWechatUserId(dto.getOaWeixinUserId());
+            newUser.setQyWechatUpdateTime(new Date());
+        }
+        
         if (deptId != null)
         {
             newUser.setDeptId(deptId);
diff --git a/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml b/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
index 906b028..4b29293 100644
--- a/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
@@ -44,6 +44,10 @@
         <result property="ServiceOrdTraDistance" column="ServiceOrdTraDistance" />
         <result property="ServiceOrdApptDate" column="ServiceOrdApptDate" />
         <result property="DispatchOrdState" column="DispatchOrdState" />
+        <result property="DispatchOrdNo" column="DispatchOrdNo" />
+        <result property="DispatchOrdClass" column="DispatchOrdClass" />
+        <result property="DispatchOrd_NS_Time" column="DispatchOrd_NS_Time" />
+
     </resultMap>
     
     <!-- 鎵ц浜虹粨鏋滄槧灏� -->
@@ -93,7 +97,11 @@
             b.DispatchOrdCarID,
             a.ServiceOrdPtServices,
             a.ServiceOrdPtInServices,
-            a.ServiceOrdPtName
+            a.ServiceOrdPtName,
+            b.DispatchOrdState,            
+            b.DispatchOrdNo,
+            b.DispatchOrdClass,
+            a.ServiceOrdClass  
         FROM ServiceOrder as a 
         left JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
         WHERE a.ServiceOrdState &lt;= 3
@@ -111,6 +119,7 @@
             a.ServiceOrdApptDate,
             a.ServiceOrdUserID,
             a.ServiceOrd_NS_ID,
+            a.ServiceOrd_NS_Time,
             a.ServiceOrd_CC_ID,
             a.ServiceOrd_CC_Time,
             a.ServiceOrdAreaType,
@@ -140,13 +149,115 @@
             a.ServiceOrdPtServices,
             a.ServiceOrdPtInServices,
             a.ServiceOrdPtName,
-            b.DispatchOrdState
+            b.DispatchOrdState,            
+            b.DispatchOrdNo,
+            b.DispatchOrdClass,
+            a.ServiceOrdClass           
+
         FROM ServiceOrder as a 
         left JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
-        WHERE a.ServiceOrdID = #{serviceOrdID}
+        WHERE a.ServiceOrdID = #{serviceOrdID} 
+            AND (b.DispatchOrdID = #{dispatchOrdID} OR #{dispatchOrdID} IS NULL)
             AND a.ServiceOrdState &lt;=3
 
     </select>
+    <select id="selectByServiceOrdId" resultMap="TransferOrderResult">
+        SELECT
+        a.ServiceOrdID,
+        a.Old_ServiceOrdID_TXT,
+        a.ServiceOrdTraVia,
+        a.ServiceOrdNo,
+        a.ServiceOrdApptDate,
+        a.ServiceOrdUserID,
+        a.ServiceOrd_NS_ID,
+        a.ServiceOrd_NS_Time,
+        a.ServiceOrd_CC_ID,
+        a.ServiceOrd_CC_Time,
+        a.ServiceOrdAreaType,
+        a.ServiceOrdType,
+        a.ServiceOrdPtSex,
+        a.ServiceOrdTraTxnPrice,
+        a.ServiceOrdPtOutHospID,
+        a.ServiceOrdPtServicesID,
+        a.ServiceOrdPtInHospID,
+        a.ServiceOrdPtInServicesID,
+        a.ServiceOrdCoTies,
+        a.ServiceOrdCoName,
+        a.ServiceOrdTraDistance,
+        a.ServiceOrdCoPhone,
+        a.ServiceOrdClass,
+        a.ServiceOrdTraStreet,
+        a.ServiceOrdTraEnd,
+        a.ServiceOrdPtCondition,
+        b.DispatchOrd_NS_Time,
+        a.ServiceOrdState,
+        a.ServiceOrdPtIDCard,
+        b.DispatchOrdTraStreet,
+        b.DispatchOrdStartDate,
+        b.DispatchOrdTraEnd,
+        b.DispatchOrdID,
+        b.DispatchOrdCarID,
+        a.ServiceOrdPtServices,
+        a.ServiceOrdPtInServices,
+        a.ServiceOrdPtName,
+        b.DispatchOrdState,
+        b.DispatchOrdNo,
+        b.DispatchOrdClass,
+        a.ServiceOrdClass
+
+        FROM ServiceOrder as a
+        left JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
+        WHERE a.ServiceOrdID = #{serviceOrdID}
+    </select>
+    <select id="selectByDispatchId" resultMap="TransferOrderResult">
+     SELECT 
+            a.ServiceOrdID,
+            a.Old_ServiceOrdID_TXT,
+            a.ServiceOrdTraVia,
+            a.ServiceOrdNo,
+            a.ServiceOrdApptDate,
+            a.ServiceOrdUserID,
+            a.ServiceOrd_NS_ID,
+            a.ServiceOrd_NS_Time,
+            a.ServiceOrd_CC_ID,
+            a.ServiceOrd_CC_Time,
+            a.ServiceOrdAreaType,
+            a.ServiceOrdType,
+            a.ServiceOrdPtSex,
+            a.ServiceOrdTraTxnPrice,
+            a.ServiceOrdPtOutHospID,
+            a.ServiceOrdPtServicesID,
+            a.ServiceOrdPtInHospID,
+            a.ServiceOrdPtInServicesID,
+            a.ServiceOrdCoTies,
+            a.ServiceOrdCoName,
+            a.ServiceOrdTraDistance,
+            a.ServiceOrdCoPhone,
+            a.ServiceOrdClass,
+            a.ServiceOrdTraStreet,
+            a.ServiceOrdTraEnd,
+            a.ServiceOrdPtCondition,
+            b.DispatchOrd_NS_Time,
+            a.ServiceOrdState,
+            a.ServiceOrdPtIDCard,
+            b.DispatchOrdTraStreet,
+            b.DispatchOrdStartDate,
+            b.DispatchOrdTraEnd,
+            b.DispatchOrdID,
+            b.DispatchOrdCarID,
+            a.ServiceOrdPtServices,
+            a.ServiceOrdPtInServices,
+            a.ServiceOrdPtName,
+            b.DispatchOrdState,            
+            b.DispatchOrdNo,
+            b.DispatchOrdClass,
+            a.ServiceOrdClass           
+
+        FROM ServiceOrder as a 
+        left JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
+        WHERE b.DispatchOrdID = #{dispatchId}
+     </select>
+
     
     <!-- 鏍规嵁鏈嶅姟鍗旾D鏌ヨ鐥呮儏淇℃伅 -->
     <select id="selectDiseaseIdsByServiceOrdID" resultType="String">
diff --git a/ruoyi-system/src/main/resources/mapper/system/NotifySendLogMapper.xml b/ruoyi-system/src/main/resources/mapper/system/NotifySendLogMapper.xml
index 636a623..baf4fa9 100644
--- a/ruoyi-system/src/main/resources/mapper/system/NotifySendLogMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/NotifySendLogMapper.xml
@@ -13,6 +13,7 @@
         <result property="notifyType"   column="notify_type"  />
         <result property="channel"      column="channel"      />
         <result property="sendStatus"   column="send_status"  />
+        <result property="sendContent"  column="send_content" />
         <result property="sendTime"     column="send_time"    />
         <result property="sendResult"   column="send_result"  />
         <result property="responseMsg"  column="response_msg" />
@@ -26,7 +27,7 @@
 
     <sql id="selectNotifySendLogVo">
         select id, notify_task_id, task_id, user_id, user_name, notify_type, channel, send_status, 
-               send_time, send_result, response_msg, retry_count, create_time, create_by, 
+               send_content, send_time, send_result, response_msg, retry_count, create_time, create_by, 
                update_time, update_by, remark
         from sys_notify_send_log
     </sql>
@@ -102,6 +103,7 @@
             <if test="notifyType != null and notifyType != ''">notify_type,</if>
             <if test="channel != null and channel != ''">channel,</if>
             <if test="sendStatus != null">send_status,</if>
+            <if test="sendContent != null">send_content,</if>
             <if test="sendTime != null">send_time,</if>
             <if test="sendResult != null">send_result,</if>
             <if test="responseMsg != null">response_msg,</if>
@@ -120,6 +122,7 @@
             <if test="notifyType != null and notifyType != ''">#{notifyType},</if>
             <if test="channel != null and channel != ''">#{channel},</if>
             <if test="sendStatus != null">#{sendStatus},</if>
+            <if test="sendContent != null">#{sendContent},</if>
             <if test="sendTime != null">#{sendTime},</if>
             <if test="sendResult != null">#{sendResult},</if>
             <if test="responseMsg != null">#{responseMsg},</if>
@@ -141,6 +144,7 @@
             <if test="notifyType != null and notifyType != ''">notify_type = #{notifyType},</if>
             <if test="channel != null and channel != ''">channel = #{channel},</if>
             <if test="sendStatus != null">send_status = #{sendStatus},</if>
+            <if test="sendContent != null">send_content = #{sendContent},</if>
             <if test="sendTime != null">send_time = #{sendTime},</if>
             <if test="sendResult != null">send_result = #{sendResult},</if>
             <if test="retryCount != null">retry_count = #{retryCount},</if>
@@ -155,6 +159,7 @@
         update sys_notify_send_log
         set send_status = #{sendStatus},
             send_result = #{sendResult},
+            send_content = #{sendContent},
             send_time = now(),
             update_time = now(),
             retry_count = retry_count + 1
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
index a7f2760..d5f526f 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml
@@ -46,6 +46,11 @@
         <result property="dispatchSyncErrorMsg"    column="dispatch_sync_error_msg" />
         <result property="needResync"              column="need_resync"             />
         <result property="legacyServiceOrdNo"      column="legacy_service_ord_no"   />
+        <result property="legacyDispatchOrdNo"     column="legacy_dispatch_ord_no"  />
+        <result property="legacyServiceNsTime"     column="legacy_service_ns_time"  />
+        <result property="legacyDispatchNsTime"    column="legacy_dispatch_ns_time" />
+        <result property="legacyDispatchOrdClass"  column="legacy_dispatch_ord_class" />
+        <result property="legacyServiceOrdClass"   column="legacy_service_ord_class" />
         <result property="createTime"              column="create_time"             />
         <result property="updateTime"              column="update_time"             />
         <result property="createBy"                column="create_by"               />
@@ -60,7 +65,7 @@
                hospital_in_department_id, hospital_in_bed_number, hospital_in_address, hospital_in_longitude, 
                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,
+               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,
                create_time, update_time, create_by, update_by
         from sys_task_emergency
     </sql>
@@ -118,6 +123,11 @@
             <if test="dispatchSyncErrorMsg != null">dispatch_sync_error_msg,</if>
             <if test="needResync != null">need_resync,</if>
             <if test="legacyServiceOrdNo != null">legacy_service_ord_no,</if>
+            <if test="legacyDispatchOrdNo != null">legacy_dispatch_ord_no,</if>
+            <if test="legacyServiceNsTime != null">legacy_service_ns_time,</if>
+            <if test="legacyDispatchNsTime != null">legacy_dispatch_ns_time,</if>
+            <if test="legacyDispatchOrdClass != null">legacy_dispatch_ord_class,</if>
+            <if test="legacyServiceOrdClass != null">legacy_service_ord_class,</if>
             <if test="createTime != null">create_time,</if>
             <if test="updateTime != null">update_time,</if>
             <if test="createBy != null">create_by,</if>
@@ -164,6 +174,11 @@
             <if test="dispatchSyncErrorMsg != null">#{dispatchSyncErrorMsg},</if>
             <if test="needResync != null">#{needResync},</if>
             <if test="legacyServiceOrdNo != null">#{legacyServiceOrdNo},</if>
+            <if test="legacyDispatchOrdNo != null">#{legacyDispatchOrdNo},</if>
+            <if test="legacyServiceNsTime != null">#{legacyServiceNsTime},</if>
+            <if test="legacyDispatchNsTime != null">#{legacyDispatchNsTime},</if>
+            <if test="legacyDispatchOrdClass != null">#{legacyDispatchOrdClass},</if>
+            <if test="legacyServiceOrdClass != null">#{legacyServiceOrdClass},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="updateTime != null">#{updateTime},</if>
             <if test="createBy != null">#{createBy},</if>
@@ -213,6 +228,11 @@
             <if test="dispatchSyncErrorMsg != null">dispatch_sync_error_msg = #{dispatchSyncErrorMsg},</if>
             <if test="needResync != null">need_resync = #{needResync},</if>
             <if test="legacyServiceOrdNo != null">legacy_service_ord_no = #{legacyServiceOrdNo},</if>
+            <if test="legacyDispatchOrdNo != null">legacy_dispatch_ord_no = #{legacyDispatchOrdNo},</if>
+            <if test="legacyServiceNsTime != null">legacy_service_ns_time = #{legacyServiceNsTime},</if>
+            <if test="legacyDispatchNsTime != null">legacy_dispatch_ns_time = #{legacyDispatchNsTime},</if>
+            <if test="legacyDispatchOrdClass != null">legacy_dispatch_ord_class = #{legacyDispatchOrdClass},</if>
+            <if test="legacyServiceOrdClass != null">legacy_service_ord_class = #{legacyServiceOrdClass},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="updateBy != null">update_by = #{updateBy},</if>
         </trim>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
index f5fab34..6389b38 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -28,6 +28,8 @@
         <result property="openId"       column="open_id"       />
         <result property="unionId"     column="union_id"     />
         <result property="wechatNickname" column="wechat_nickname" />
+        <result property="qyWechatUserId" column="qy_wechat_user_id" />
+        <result property="qyWechatUpdateTime" column="qy_wechat_update_time" />
         <result property="canViewAllConsult" column="can_view_all_consult" />
         <association property="dept"    javaType="SysDept"         resultMap="deptResult" />
         <collection  property="roles"   javaType="java.util.List"  resultMap="RoleResult" />
@@ -53,7 +55,7 @@
     </resultMap>
 	
 	<sql id="selectUserVo">
-        select u.user_id, u.dept_id, u.user_name,u.oa_user_id, u.oa_order_class, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.oa_user_id, u.create_by, u.create_time, u.remark,u.open_id,u.union_id,u.wechat_nickname,u.can_view_all_consult,
+        select u.user_id, u.dept_id, u.user_name,u.oa_user_id, u.oa_order_class, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.oa_user_id, u.create_by, u.create_time, u.remark,u.open_id,u.union_id,u.wechat_nickname,u.qy_wechat_user_id,u.qy_wechat_update_time,u.can_view_all_consult,
         d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
         r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
         from sys_user u
@@ -170,7 +172,8 @@
  			<if test="status != null and status != ''">status,</if>
  			<if test="oaUserId != null">oa_user_id,</if>
  			<if test="oaOrderClass != null and oaOrderClass != ''">oa_order_class,</if>
- 			<if test="canViewAllConsult != null and canViewAllConsult != ''">can_view_all_consult,</if>
+ 			<if test="qyWechatUserId != null and qyWechatUserId != ''">qy_wechat_user_id,</if>
+ 			<if test="qyWechatUpdateTime != null">qy_wechat_update_time,</if>
  			<if test="createBy != null and createBy != ''">create_by,</if>
  			<if test="remark != null and remark != ''">remark,</if>
  			create_time
@@ -188,6 +191,8 @@
  			<if test="oaUserId != null">#{oaUserId},</if>
  			<if test="oaOrderClass != null and oaOrderClass != ''">#{oaOrderClass},</if>
  			<if test="canViewAllConsult != null and canViewAllConsult != ''">#{canViewAllConsult},</if>
+ 			<if test="qyWechatUserId != null and qyWechatUserId != ''">#{qyWechatUserId},</if>
+ 			<if test="qyWechatUpdateTime != null">#{qyWechatUpdateTime},</if>
  			<if test="createBy != null and createBy != ''">#{createBy},</if>
  			<if test="remark != null and remark != ''">#{remark},</if>
  			sysdate()
@@ -208,6 +213,8 @@
  			<if test="oaUserId != null">oa_user_id = #{oaUserId},</if>
  			<if test="oaOrderClass != null">oa_order_class = #{oaOrderClass},</if>
  			<if test="canViewAllConsult != null and canViewAllConsult != ''">can_view_all_consult = #{canViewAllConsult},</if>
+ 			<if test="qyWechatUserId != null and qyWechatUserId != ''">qy_wechat_user_id = #{qyWechatUserId},</if>
+ 			<if test="qyWechatUpdateTime != null">qy_wechat_update_time = #{qyWechatUpdateTime},</if>
  			<if test="openId != null and openId != ''">open_id = #{openId},</if>
  			<if test="unionId != null and unionId != ''">union_id = #{unionId},</if>
  			<if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if>
diff --git a/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml b/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml
index 420e03e..a1dbfcd 100644
--- a/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/UserSyncMapper.xml
@@ -6,6 +6,7 @@
 
     <resultMap type="UserSyncDTO" id="UserSyncResult">
         <result property="oaUserId" column="OA_UserID" />
+        <result property="oaWeixinUserId" column="OA_weixinUserID" />
         <result property="userName" column="user_name" />
         <result property="nickName" column="nick_name" />
         <result property="departmentId" column="department_id" />
@@ -21,6 +22,7 @@
         <![CDATA[
         SELECT
             OA_User_ID AS OA_UserID,
+            OA_weixinUserID AS OA_weixinUserID,
             OA_User AS user_name,
             OA_Name AS nick_name,
             OA_departmentID AS department_id,
diff --git a/ruoyi-ui/src/api/system/qywechat/index.js b/ruoyi-ui/src/api/system/qywechat/index.js
new file mode 100644
index 0000000..0fed4fc
--- /dev/null
+++ b/ruoyi-ui/src/api/system/qywechat/index.js
@@ -0,0 +1,43 @@
+import request from '@/utils/request'
+
+// 鑾峰彇浼佷笟寰俊AccessToken
+export function getToken() {
+  return request({
+    url: '/system/qywechat/test/token',
+    method: 'get'
+  })
+}
+
+// 鍒锋柊浼佷笟寰俊AccessToken
+export function refreshToken() {
+  return request({
+    url: '/system/qywechat/test/refreshToken',
+    method: 'post'
+  })
+}
+
+// 鍙戦�佷紒涓氬井淇¢�氱煡娑堟伅
+export function sendMessage(data) {
+  return request({
+    url: '/system/qywechat/test/sendMessage',
+    method: 'post',
+    params: data
+  })
+}
+
+// 鍙戦�佷紒涓氬井淇℃枃鏈秷鎭�
+export function sendTextMessage(data) {
+  return request({
+    url: '/system/qywechat/test/sendTextMessage',
+    method: 'post',
+    params: data
+  })
+}
+
+// 妫�鏌ヤ紒涓氬井淇℃湇鍔$姸鎬�
+export function checkServiceStatus() {
+  return request({
+    url: '/system/qywechat/test/enabled',
+    method: 'get'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/qywechat/test.js b/ruoyi-ui/src/api/system/qywechat/test.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ruoyi-ui/src/api/system/qywechat/test.js
diff --git a/ruoyi-ui/src/views/system/notify/channelConfig.vue b/ruoyi-ui/src/views/system/notify/channelConfig.vue
index f96689c..5e13fa6 100644
--- a/ruoyi-ui/src/views/system/notify/channelConfig.vue
+++ b/ruoyi-ui/src/views/system/notify/channelConfig.vue
@@ -132,6 +132,7 @@
             <el-option label="鐭俊" value="SMS" />
             <el-option label="绔欏唴娑堟伅" value="SITE_MSG" />
             <el-option label="APP鎺ㄩ��" value="APP_PUSH" />
+            <el-option label="浼佷笟寰俊" value="QY_WECHAT" />
           </el-select>
         </el-form-item>
         <el-form-item label="鏄惁鍚敤" prop="enabled">
diff --git a/ruoyi-ui/src/views/system/notify/log/index.vue b/ruoyi-ui/src/views/system/notify/log/index.vue
index fbb1b60..e7079b9 100644
--- a/ruoyi-ui/src/views/system/notify/log/index.vue
+++ b/ruoyi-ui/src/views/system/notify/log/index.vue
@@ -113,6 +113,7 @@
           <span>{{ parseTime(scope.row.sendTime) }}</span>
         </template>
       </el-table-column>
+      <el-table-column label="鍙戦�佸唴瀹�" align="center" prop="sendContent" show-overflow-tooltip />
       <el-table-column label="鍙戦�佺粨鏋�" align="center" prop="sendResult" show-overflow-tooltip />
       <el-table-column label="閲嶈瘯娆℃暟" align="center" prop="retryCount" />
       <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
@@ -194,6 +195,19 @@
         </el-row>
         <el-row>
           <el-col :span="24">
+            <el-form-item label="鍙戦�佸唴瀹癸細">
+              <el-input
+                type="textarea"
+                :rows="4"
+                placeholder="鍙戦�佸唴瀹�"
+                v-model="form.sendContent"
+                readonly>
+              </el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
             <el-form-item label="鍝嶅簲娑堟伅锛�">{{ form.responseMsg }}</el-form-item>
           </el-col>
         </el-row>
diff --git a/ruoyi-ui/src/views/system/qywechat/index.vue b/ruoyi-ui/src/views/system/qywechat/index.vue
new file mode 100644
index 0000000..f2d7856
--- /dev/null
+++ b/ruoyi-ui/src/views/system/qywechat/index.vue
@@ -0,0 +1,18 @@
+<template>
+  <div class="app-container">
+    <h1>浼佷笟寰俊娴嬭瘯椤甸潰</h1>
+    <p>杩欐槸涓�涓祴璇曢〉闈紝鐢ㄤ簬楠岃瘉浼佷笟寰俊鍔熻兘銆�</p>
+  </div>
+</template>
+
+<script>
+// 绠�鍗曟祴璇曞鍏�
+import * as qywechatApi from '@/api/system/qywechat/index'
+
+export default {
+  name: 'QyWechatIndex',
+  mounted() {
+    console.log('浼佷笟寰俊API瀵煎叆娴嬭瘯:', qywechatApi)
+  }
+}
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/qywechat/test.vue b/ruoyi-ui/src/views/system/qywechat/test.vue
new file mode 100644
index 0000000..d2444a5
--- /dev/null
+++ b/ruoyi-ui/src/views/system/qywechat/test.vue
@@ -0,0 +1,226 @@
+<template>
+  <div class="app-container">
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <span>浼佷笟寰俊鍔熻兘娴嬭瘯</span>
+      </div>
+      
+      <el-tabs v-model="activeTab">
+        <!-- AccessToken娴嬭瘯 -->
+        <el-tab-pane label="AccessToken娴嬭瘯" name="token">
+          <el-form ref="tokenForm" :model="tokenForm" label-width="120px">
+            <el-form-item label="CorpID">
+              <el-input v-model="tokenForm.corpId" placeholder="璇疯緭鍏ヤ紒涓氬井淇orpID" />
+            </el-form-item>
+            <el-form-item label="CorpSecret">
+              <el-input v-model="tokenForm.corpSecret" placeholder="璇疯緭鍏ヤ紒涓氬井淇orpSecret" show-password />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="getToken">鑾峰彇AccessToken</el-button>
+              <el-button type="success" @click="refreshToken">鍒锋柊AccessToken</el-button>
+            </el-form-item>
+          </el-form>
+          
+          <el-divider />
+          
+          <div v-if="tokenResult">
+            <h4>娴嬭瘯缁撴灉锛�</h4>
+            <pre>{{ tokenResult }}</pre>
+          </div>
+        </el-tab-pane>
+        
+        <!-- 娑堟伅鍙戦�佹祴璇� -->
+        <el-tab-pane label="娑堟伅鍙戦�佹祴璇�" name="message">
+          <el-form ref="messageForm" :model="messageForm" label-width="120px">
+            <el-form-item label="鐢ㄦ埛ID">
+              <el-input v-model="messageForm.userId" placeholder="璇疯緭鍏ョ郴缁熺敤鎴稩D" />
+            </el-form-item>
+            <el-form-item label="浼佷笟寰俊鐢ㄦ埛ID">
+              <el-input v-model="messageForm.qyUserId" placeholder="璇疯緭鍏ヤ紒涓氬井淇$敤鎴稩D" />
+            </el-form-item>
+            <el-form-item label="娑堟伅鏍囬">
+              <el-input v-model="messageForm.title" placeholder="璇疯緭鍏ユ秷鎭爣棰�" />
+            </el-form-item>
+            <el-form-item label="娑堟伅鍐呭">
+              <el-input v-model="messageForm.content" type="textarea" :rows="4" placeholder="璇疯緭鍏ユ秷鎭唴瀹�" />
+            </el-form-item>
+            <el-form-item label="閫氱煡閾炬帴">
+              <el-input v-model="messageForm.notifyUrl" placeholder="璇疯緭鍏ラ�氱煡閾炬帴" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="sendMessage">鍙戦�侀�氱煡娑堟伅</el-button>
+              <el-button type="success" @click="sendTextMessage">鍙戦�佹枃鏈秷鎭�</el-button>
+            </el-form-item>
+          </el-form>
+          
+          <el-divider />
+          
+          <div v-if="messageResult">
+            <h4>娴嬭瘯缁撴灉锛�</h4>
+            <pre>{{ messageResult }}</pre>
+          </div>
+        </el-tab-pane>
+        
+        <!-- 鏈嶅姟鐘舵�佹鏌� -->
+        <el-tab-pane label="鏈嶅姟鐘舵�佹鏌�" name="status">
+          <el-button type="primary" @click="checkServiceStatus">妫�鏌ユ湇鍔$姸鎬�</el-button>
+          
+          <el-divider />
+          
+          <div v-if="statusResult">
+            <h4>鏈嶅姟鐘舵�侊細</h4>
+            <el-tag :type="statusResult.enabled ? 'success' : 'danger'">
+              {{ statusResult.enabled ? '宸插惎鐢�' : '宸茬鐢�' }}
+            </el-tag>
+            <p v-if="statusResult.message">{{ statusResult.message }}</p>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import { getToken, refreshToken, sendMessage, sendTextMessage, checkServiceStatus } from '@/api/system/qywechat/index'
+
+export default {
+  name: 'QyWechatTest',
+  data() {
+    return {
+      activeTab: 'token',
+      tokenForm: {
+        corpId: 'wx248505bfbab6d0c1',
+        corpSecret: '2MCilqWYC0FWjOQ894sbb-s7Lb5sVH4HHuJgOsd9l1k'
+      },
+      messageForm: {
+        userId: '',
+        qyUserId: '',
+        title: '娴嬭瘯娑堟伅鏍囬',
+        content: '杩欐槸涓�鏉℃祴璇曟秷鎭唴瀹�',
+        notifyUrl: 'https://www.example.com'
+      },
+      tokenResult: null,
+      messageResult: null,
+      statusResult: null
+    }
+  },
+  methods: {
+    // 鑾峰彇AccessToken
+    async getToken() {
+      try {
+        const response = await getToken()
+        this.tokenResult = JSON.stringify(response, null, 2)
+        this.$message.success('鑾峰彇AccessToken鎴愬姛')
+      } catch (error) {
+        this.tokenResult = error.message || '鑾峰彇AccessToken澶辫触'
+        this.$message.error('鑾峰彇AccessToken澶辫触: ' + (error.message || '鏈煡閿欒'))
+      }
+    },
+    
+    // 鍒锋柊AccessToken
+    async refreshToken() {
+      try {
+        const response = await refreshToken()
+        this.tokenResult = JSON.stringify(response, null, 2)
+        this.$message.success('鍒锋柊AccessToken鎴愬姛')
+      } catch (error) {
+        this.tokenResult = error.message || '鍒锋柊AccessToken澶辫触'
+        this.$message.error('鍒锋柊AccessToken澶辫触: ' + (error.message || '鏈煡閿欒'))
+      }
+    },
+    
+    // 鍙戦�侀�氱煡娑堟伅
+    async sendMessage() {
+      if (!this.messageForm.userId) {
+        this.$message.warning('璇疯緭鍏ョ敤鎴稩D')
+        return
+      }
+      if (!this.messageForm.title) {
+        this.$message.warning('璇疯緭鍏ユ秷鎭爣棰�')
+        return
+      }
+      if (!this.messageForm.content) {
+        this.$message.warning('璇疯緭鍏ユ秷鎭唴瀹�')
+        return
+      }
+      
+      try {
+        const params = {
+          userId: this.messageForm.userId,
+          title: this.messageForm.title,
+          content: this.messageForm.content
+        }
+        const response = await sendMessage(params)
+        this.messageResult = JSON.stringify(response, null, 2)
+        this.$message.success('鍙戦�侀�氱煡娑堟伅鎴愬姛')
+      } catch (error) {
+        this.messageResult = error.message || '鍙戦�侀�氱煡娑堟伅澶辫触'
+        this.$message.error('鍙戦�侀�氱煡娑堟伅澶辫触: ' + (error.message || '鏈煡閿欒'))
+      }
+    },
+    
+    // 鍙戦�佹枃鏈秷鎭�
+    async sendTextMessage() {
+      if (!this.messageForm.qyUserId) {
+        this.$message.warning('璇疯緭鍏ヤ紒涓氬井淇$敤鎴稩D')
+        return
+      }
+      if (!this.messageForm.content) {
+        this.$message.warning('璇疯緭鍏ユ秷鎭唴瀹�')
+        return
+      }
+      
+      try {
+        const params = {
+          qyUserId: this.messageForm.qyUserId,
+          title: this.messageForm.title || '娴嬭瘯娑堟伅',
+          content: this.messageForm.content,
+          notifyUrl: this.messageForm.notifyUrl
+        }
+        const response = await sendTextMessage(params)
+        this.messageResult = JSON.stringify(response, null, 2)
+        this.$message.success('鍙戦�佹枃鏈秷鎭垚鍔�')
+      } catch (error) {
+        this.messageResult = error.message || '鍙戦�佹枃鏈秷鎭け璐�'
+        this.$message.error('鍙戦�佹枃鏈秷鎭け璐�: ' + (error.message || '鏈煡閿欒'))
+      }
+    },
+    
+    // 妫�鏌ユ湇鍔$姸鎬�
+    async checkServiceStatus() {
+      try {
+        const response = await checkServiceStatus()
+        this.statusResult = {
+          enabled: response.data,
+          message: response.msg
+        }
+        this.$message.success('妫�鏌ユ湇鍔$姸鎬佹垚鍔�')
+      } catch (error) {
+        this.statusResult = {
+          enabled: false,
+          message: error.message || '妫�鏌ユ湇鍔$姸鎬佸け璐�'
+        }
+        this.$message.error('妫�鏌ユ湇鍔$姸鎬佸け璐�: ' + (error.message || '鏈煡閿欒'))
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.box-card {
+  margin-bottom: 20px;
+}
+
+.el-divider {
+  margin: 20px 0;
+}
+
+pre {
+  background-color: #f5f5f5;
+  padding: 10px;
+  border-radius: 4px;
+  white-space: pre-wrap;
+  word-wrap: break-word;
+}
+</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/task/general/detail.vue b/ruoyi-ui/src/views/task/general/detail.vue
index e65a2a7..036d380 100644
--- a/ruoyi-ui/src/views/task/general/detail.vue
+++ b/ruoyi-ui/src/views/task/general/detail.vue
@@ -8,7 +8,7 @@
       
       <!-- 鍩烘湰淇℃伅 -->
       <el-descriptions title="鍩烘湰淇℃伅" :column="2" border>
-        <el-descriptions-item label="浠诲姟缂栧彿">{{ taskDetail.taskCode }}</el-descriptions-item>
+        <el-descriptions-item label="浠诲姟缂栧彿">{{ taskDetail.showTaskCode }}</el-descriptions-item>
         <el-descriptions-item label="浠诲姟绫诲瀷">
           <dict-tag :options="dict.type.sys_task_type" :value="taskDetail.taskType"/>
         </el-descriptions-item>
@@ -81,6 +81,12 @@
           </span>
           <span v-else style="color: #C0C4CC;">--</span>
         </el-descriptions-item>
+        <el-descriptions-item label="鏈嶅姟鍗曠紪鐮�">
+          <span v-if="taskDetail.emergencyInfo.serviceCode">
+            <el-tag type="success" size="small">{{ taskDetail.emergencyInfo.serviceCode }}</el-tag>
+          </span>
+          <span v-else style="color: #C0C4CC;">--</span>
+        </el-descriptions-item>
         <el-descriptions-item label="鏈嶅姟鍗曞悓姝ユ椂闂�">
           <span v-if="taskDetail.emergencyInfo.syncTime">{{ parseTime(taskDetail.emergencyInfo.syncTime) }}</span>
           <span v-else style="color: #C0C4CC;">--</span>
@@ -107,6 +113,12 @@
         <el-descriptions-item label="璋冨害鍗曞彿">
           <span v-if="taskDetail.emergencyInfo.legacyDispatchOrdId">
             <el-tag type="primary" size="small">{{ taskDetail.emergencyInfo.legacyDispatchOrdId }}</el-tag>
+          </span>
+          <span v-else style="color: #C0C4CC;">--</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="璋冨害鍗曠紪鐮�">
+          <span v-if="taskDetail.emergencyInfo.dispatchCode">
+            <el-tag type="success" size="small">{{ taskDetail.emergencyInfo.dispatchCode }}</el-tag>
           </span>
           <span v-else style="color: #C0C4CC;">--</span>
         </el-descriptions-item>
@@ -306,12 +318,12 @@
       </el-descriptions>
 
       <!-- 鎿嶄綔鎸夐挳 -->
-      <div style="margin-top: 20px; text-align: center;">
+      <!-- <div style="margin-top: 20px; text-align: center;">
         <el-button type="primary" @click="handleEdit" v-hasPermi="['task:general:edit']">缂栬緫浠诲姟</el-button>
         <el-button type="success" @click="handleAssign" v-hasPermi="['task:general:assign']">鍒嗛厤浠诲姟</el-button>
         <el-button type="warning" @click="handleStatusChange" v-hasPermi="['task:general:status']">鐘舵�佸彉鏇�</el-button>
         <el-button type="info" @click="handleVehicleAssign" v-hasPermi="['task:general:assign']">鍒嗛厤杞﹁締</el-button>
-      </div>
+      </div> -->
     </el-card>
     
     <!-- 鎵ц浜哄憳鍒楄〃 -->
diff --git a/ruoyi-ui/src/views/task/general/index.vue b/ruoyi-ui/src/views/task/general/index.vue
index 63da244..382cc4a 100644
--- a/ruoyi-ui/src/views/task/general/index.vue
+++ b/ruoyi-ui/src/views/task/general/index.vue
@@ -102,22 +102,20 @@
 
     <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="浠诲姟缂栧彿" align="center" prop="taskCode" min-width="180">
+      <el-table-column label="浠诲姟缂栧彿" align="center" prop="showTaskCode" min-width="120">
         <template slot-scope="scope">
           <el-button
             type="text"
             @click="handleView(scope.row)"
             v-hasPermi="['task:general:query']"
             style="font-family: 'Courier New', monospace; font-size: 13px;"
-          >{{ scope.row.taskCode }}</el-button>
+          >{{ scope.row.showTaskCode }}</el-button>
         </template>
       </el-table-column>
       <el-table-column label="浠诲姟绫诲瀷" align="center" prop="taskType" width="120">
         <template slot-scope="scope">
           <dict-tag :options="dict.type.sys_task_type" :value="scope.row.taskType"/>
-          <el-tag v-if="scope.row.taskType === 'EMERGENCY_TRANSFER'" type="danger" size="mini" style="margin-left: 5px;">
-            <i class="el-icon-warning"></i>
-          </el-tag>
+          
         </template>
       </el-table-column>
    
@@ -132,8 +130,8 @@
           <span v-else style="color: #C0C4CC;">--</span>
         </template>
       </el-table-column>
-      <el-table-column label="鍑哄彂鍦板潃" align="center" prop="departureAddress" show-overflow-tooltip />
-      <el-table-column label="鐩殑鍦板潃" align="center" prop="destinationAddress" show-overflow-tooltip />
+      
+      <!-- <el-table-column label="鐩殑鍦板潃" align="center" prop="destinationAddress" show-overflow-tooltip /> -->
       <el-table-column label="棰勮鍏噷鏁�" align="center" prop="estimatedDistance" width="120">
         <template slot-scope="scope">
           <span v-if="scope.row.estimatedDistance">{{ scope.row.estimatedDistance }} km</span>
@@ -143,7 +141,7 @@
  
      
       <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" />
-      <el-table-column label="鎵ц浜�" align="center" prop="assigneeName" />
+      
       <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
@@ -158,27 +156,27 @@
             @click="handleView(scope.row)"
             v-hasPermi="['task:general:query']"
           >鏌ョ湅</el-button>
-          <el-button
+          <!-- <el-button
             size="mini"
             type="text"
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['task:general:edit']"
-          >淇敼</el-button>
-          <el-button
+          >淇敼</el-button> -->
+          <!-- <el-button
             size="mini"
             type="text"
             icon="el-icon-user"
             @click="handleAssign(scope.row)"
             v-hasPermi="['task:general:assign']"
-          >鍒嗛厤</el-button>
-          <el-button
+          >鍒嗛厤</el-button> -->
+          <!-- <el-button
             size="mini"
             type="text"
             icon="el-icon-refresh"
             @click="handleStatusChange(scope.row)"
             v-hasPermi="['task:general:status']"
-          >鐘舵��</el-button>
+          >鐘舵��</el-button> -->
           <el-button
             size="mini"
             type="text"
diff --git a/sql/add_qy_wechat_user_id_to_sys_user.sql b/sql/add_qy_wechat_user_id_to_sys_user.sql
new file mode 100644
index 0000000..37605f2
--- /dev/null
+++ b/sql/add_qy_wechat_user_id_to_sys_user.sql
@@ -0,0 +1,11 @@
+-- 鍦╯ys_user琛ㄤ腑娣诲姞qy_wechat_user_id瀛楁锛岀敤浜庤褰曚紒涓氬井淇$敤鎴稩D
+-- 璇ュ瓧娈电敤浜庝紒涓氬井淇℃秷鎭帹閫佸姛鑳�
+
+-- 娣诲姞qy_wechat_user_id瀛楁
+ALTER TABLE sys_user ADD COLUMN qy_wechat_user_id VARCHAR(100) NULL COMMENT '浼佷笟寰俊鐢ㄦ埛ID';
+
+-- 涓簈y_wechat_user_id瀛楁鍒涘缓绱㈠紩锛屾彁楂樻煡璇㈡晥鐜�
+CREATE INDEX idx_qy_wechat_user_id ON sys_user(qy_wechat_user_id);
+
+-- 娣诲姞鏇存柊鏃堕棿瀛楁锛岃褰曚紒涓氬井淇$敤鎴稩D鐨勬渶鍚庢洿鏂版椂闂�
+ALTER TABLE sys_user ADD COLUMN qy_wechat_update_time datetime NULL COMMENT '浼佷笟寰俊鐢ㄦ埛ID鏇存柊鏃堕棿';
\ No newline at end of file
diff --git a/sql/notify_dict.sql b/sql/notify_dict.sql
index be76d42..ae5c695 100644
--- a/sql/notify_dict.sql
+++ b/sql/notify_dict.sql
@@ -36,7 +36,8 @@
 (1, '寰俊璁㈤槄娑堟伅', 'WECHAT', 'sys_notify_channel', '', 'primary', 'Y', '0', 'admin', SYSDATE(), '寰俊璁㈤槄娑堟伅'),
 (2, '鐭俊', 'SMS', 'sys_notify_channel', '', 'success', 'N', '0', 'admin', SYSDATE(), '鐭俊'),
 (3, '绔欏唴娑堟伅', 'SITE_MSG', 'sys_notify_channel', '', 'info', 'N', '0', 'admin', SYSDATE(), '绔欏唴娑堟伅'),
-(4, 'APP鎺ㄩ��', 'APP_PUSH', 'sys_notify_channel', '', 'warning', 'N', '0', 'admin', SYSDATE(), 'APP鎺ㄩ��');
+(4, 'APP鎺ㄩ��', 'APP_PUSH', 'sys_notify_channel', '', 'warning', 'N', '0', 'admin', SYSDATE(), 'APP鎺ㄩ��'),
+(5, '浼佷笟寰俊', 'QY_WECHAT', 'sys_notify_channel', '', 'primary', 'N', '0', 'admin', SYSDATE(), '浼佷笟寰俊');
 
 -- 4. 閫氱煡鍙戦�佺姸鎬佸瓧鍏�
 INSERT INTO sys_dict_type(dict_name, dict_type, status, create_by, create_time, remark) 
diff --git a/sql/notify_menu.sql b/sql/notify_menu.sql
index 1b83cdf..f389c97 100644
--- a/sql/notify_menu.sql
+++ b/sql/notify_menu.sql
@@ -50,4 +50,20 @@
 ('娓犻亾閰嶇疆鏌ヨ', @channelConfigParentId, 1,  '#', '', 1, 0, 'F', '0', '0', 'system:notify:channel:config:query',        '#', 'admin', SYSDATE(), '', NULL, ''),
 ('娓犻亾閰嶇疆鏂板', @channelConfigParentId, 2,  '#', '', 1, 0, 'F', '0', '0', 'system:notify:channel:config:add',       '#', 'admin', SYSDATE(), '', NULL, ''),
 ('娓犻亾閰嶇疆淇敼', @channelConfigParentId, 3,  '#', '', 1, 0, 'F', '0', '0', 'system:notify:channel:config:edit',       '#', 'admin', SYSDATE(), '', NULL, ''),
-('娓犻亾閰嶇疆鍒犻櫎', @channelConfigParentId, 4,  '#', '', 1, 0, 'F', '0', '0', 'system:notify:channel:config:remove',       '#', 'admin', SYSDATE(), '', NULL, '');
\ No newline at end of file
+('娓犻亾閰嶇疆鍒犻櫎', @channelConfigParentId, 4,  '#', '', 1, 0, 'F', '0', '0', 'system:notify:channel:config:remove',       '#', 'admin', SYSDATE(), '', NULL, '');
+
+-- 浼佷笟寰俊娴嬭瘯鑿滃崟
+INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+VALUES
+('浼佷笟寰俊娴嬭瘯', @parentId, 4, 'qywechat/test', 'system/qywechat/test', 1, 0, 'C', '0', '0', 'system:qywechat:test:list', 'wechat', 'admin', SYSDATE(), '', NULL, '浼佷笟寰俊娴嬭瘯鑿滃崟');
+
+-- 鑾峰彇鍒氭彃鍏ョ殑浼佷笟寰俊娴嬭瘯鑿滃崟ID
+SET @qywechatTestParentId = (SELECT menu_id FROM sys_menu WHERE menu_name = '浼佷笟寰俊娴嬭瘯' AND menu_type = 'C');
+
+-- 浼佷笟寰俊娴嬭瘯鎸夐挳 SQL
+INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+VALUES
+('浼佷笟寰俊娴嬭瘯鏌ヨ', @qywechatTestParentId, 1,  '#', '', 1, 0, 'F', '0', '0', 'system:qywechat:test:query',        '#', 'admin', SYSDATE(), '', NULL, ''),
+('浼佷笟寰俊娴嬭瘯鏂板', @qywechatTestParentId, 2,  '#', '', 1, 0, 'F', '0', '0', 'system:qywechat:test:add',       '#', 'admin', SYSDATE(), '', NULL, ''),
+('浼佷笟寰俊娴嬭瘯淇敼', @qywechatTestParentId, 3,  '#', '', 1, 0, 'F', '0', '0', 'system:qywechat:test:edit',       '#', 'admin', SYSDATE(), '', NULL, ''),
+('浼佷笟寰俊娴嬭瘯鍒犻櫎', @qywechatTestParentId, 4,  '#', '', 1, 0, 'F', '0', '0', 'system:qywechat:test:remove',       '#', 'admin', SYSDATE(), '', NULL, '');
\ No newline at end of file
diff --git a/sql/qy_wechat_config.sql b/sql/qy_wechat_config.sql
new file mode 100644
index 0000000..03bbb5b
--- /dev/null
+++ b/sql/qy_wechat_config.sql
@@ -0,0 +1,19 @@
+-- 浼佷笟寰俊閰嶇疆鍒濆鍖栬剼鏈�
+-- 璇ヨ剼鏈敤浜庡垵濮嬪寲浼佷笟寰俊鐩稿叧鐨勭郴缁熼厤缃」
+
+-- 鍒犻櫎宸插瓨鍦ㄧ殑閰嶇疆椤�
+DELETE FROM sys_config WHERE config_key IN (
+    'qy_wechat.enable',
+    'qy_wechat.corp_id',
+    'qy_wechat.corp_secret',
+    'qy_wechat.agent_id'
+);
+
+-- 鎻掑叆浼佷笟寰俊閰嶇疆椤�
+INSERT INTO sys_config (config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark) VALUES
+('浼佷笟寰俊鏈嶅姟鍚敤鐘舵��', 'qy_wechat.enable', 'false', 'Y', 'admin', SYSDATE(), '', NULL, '浼佷笟寰俊鏈嶅姟鏄惁鍚敤锛宼rue-鍚敤锛宖alse-绂佺敤'),
+('浼佷笟寰俊CorpID', 'qy_wechat.corp_id', 'wx248505bfbab6d0c1', 'N', 'admin', SYSDATE(), '', NULL, '浼佷笟寰俊浼佷笟ID'),
+('浼佷笟寰俊CorpSecret', 'qy_wechat.corp_secret', '2MCilqWYC0FWjOQ894sbb-s7Lb5sVH4HHuJgOsd9l1k', 'N', 'admin', SYSDATE(), '', NULL, '浼佷笟寰俊搴旂敤瀵嗛挜'),
+('浼佷笟寰俊AgentId', 'qy_wechat.agent_id', '1000002', 'N', 'admin', SYSDATE(), '', NULL, '浼佷笟寰俊搴旂敤AgentId');
+
+COMMIT;
\ No newline at end of file
diff --git a/sql/qy_wechat_sync_job.sql b/sql/qy_wechat_sync_job.sql
new file mode 100644
index 0000000..02d5c48
--- /dev/null
+++ b/sql/qy_wechat_sync_job.sql
@@ -0,0 +1,86 @@
+-- 浼佷笟寰俊鐢ㄦ埛ID鍚屾瀹氭椂浠诲姟
+-- 璇ヤ换鍔℃瘡澶╁噷鏅�2鐐规墽琛屼竴娆★紝鍚屾OA绯荤粺涓殑浼佷笟寰俊鐢ㄦ埛ID鍒版湰鍦扮郴缁�
+
+-- 鍒犻櫎宸插瓨鍦ㄧ殑鍚屽悕浠诲姟
+DELETE FROM QRTZ_JOB_DETAILS WHERE sched_name = 'RuoyiScheduler' AND job_name = 'qyWechatUserSyncTask' AND job_group = 'DEFAULT';
+DELETE FROM QRTZ_TRIGGERS WHERE sched_name = 'RuoyiScheduler' AND trigger_name = 'qyWechatUserSyncTask' AND trigger_group = 'DEFAULT';
+DELETE FROM QRTZ_CRON_TRIGGERS WHERE sched_name = 'RuoyiScheduler' AND trigger_name = 'qyWechatUserSyncTask' AND trigger_group = 'DEFAULT';
+
+-- 鎻掑叆浠诲姟璇︾粏淇℃伅
+INSERT INTO QRTZ_JOB_DETAILS (
+    sched_name,
+    job_name,
+    job_group,
+    description,
+    job_class_name,
+    is_durable,
+    is_nonconcurrent,
+    is_update_data,
+    requests_recovery,
+    job_data
+) VALUES (
+    'RuoyiScheduler',
+    'qyWechatUserSyncTask',
+    'DEFAULT',
+    '浼佷笟寰俊鐢ㄦ埛ID鍚屾浠诲姟',
+    'com.ruoyi.quartz.task.QyWechatUserSyncTask',
+    '1',
+    '0',
+    '0',
+    '0',
+    ''
+);
+
+-- 鎻掑叆瑙﹀彂鍣ㄤ俊鎭�
+INSERT INTO QRTZ_TRIGGERS (
+    sched_name,
+    trigger_name,
+    trigger_group,
+    job_name,
+    job_group,
+    description,
+    next_fire_time,
+    prev_fire_time,
+    priority,
+    trigger_state,
+    trigger_type,
+    start_time,
+    end_time,
+    calendar_name,
+    misfire_instr,
+    job_data
+) VALUES (
+    'RuoyiScheduler',
+    'qyWechatUserSyncTask',
+    'DEFAULT',
+    'qyWechatUserSyncTask',
+    'DEFAULT',
+    '浼佷笟寰俊鐢ㄦ埛ID鍚屾浠诲姟瑙﹀彂鍣�',
+    0,
+    0,
+    5,
+    'WAITING',
+    'CRON',
+    1702281600000,
+    0,
+    '',
+    0,
+    ''
+);
+
+-- 鎻掑叆Cron瑙﹀彂鍣ㄤ俊鎭紙姣忓ぉ鍑屾櫒2鐐规墽琛岋級
+INSERT INTO QRTZ_CRON_TRIGGERS (
+    sched_name,
+    trigger_name,
+    trigger_group,
+    cron_expression,
+    time_zone_id
+) VALUES (
+    'RuoyiScheduler',
+    'qyWechatUserSyncTask',
+    'DEFAULT',
+    '0 0 2 * * ?',
+    'Asia/Shanghai'
+);
+
+COMMIT;
\ No newline at end of file
diff --git a/sql/ry_20250417.sql b/sql/ry_20250417.sql
index 20e843f..f40e3bf 100644
--- a/sql/ry_20250417.sql
+++ b/sql/ry_20250417.sql
@@ -59,14 +59,22 @@
   update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
   update_time       datetime                                   comment '鏇存柊鏃堕棿',
   remark            varchar(500)    default null               comment '澶囨敞',
+  oa_user_id        int(11)         default null               comment 'SQL Server涓殑OA鐢ㄦ埛ID',
+  oa_order_class    varchar(255)    default null               comment 'OA绯荤粺鐨勮鍗曠紪鐮佸垪琛紙濡傦細BF,AB,SA锛�',
+  open_id           varchar(100)    default null               comment '寰俊OpenID',
+  union_id          varchar(100)    default null               comment '寰俊UnionID',
+  wechat_nickname   varchar(100)    default null               comment '寰俊鏄电О',
+  qy_wechat_user_id varchar(100)    default null               comment '浼佷笟寰俊鐢ㄦ埛ID',
+  qy_wechat_update_time datetime    default null               comment '浼佷笟寰俊鐢ㄦ埛ID鏇存柊鏃堕棿',
+  can_view_all_consult char(1)      default '0'                comment '鏄惁鍙煡鐪嬫墍鏈夊挩璇㈠崟锛�0鍚� 1鏄級',
   primary key (user_id)
 ) engine=innodb auto_increment=100 comment = '鐢ㄦ埛淇℃伅琛�';
 
 -- ----------------------------
 -- 鍒濆鍖�-鐢ㄦ埛淇℃伅琛ㄦ暟鎹�
 -- ----------------------------
-insert into sys_user values(1,  103, 'admin', '鑻ヤ緷', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '绠$悊鍛�');
-insert into sys_user values(2,  105, 'ry',    '鑻ヤ緷', '00', 'ry@qq.com',  '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '娴嬭瘯鍛�');
+insert into sys_user values(1,  103, 'admin', '鑻ヤ緷', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '绠$悊鍛�', null, null, null, null, null, null, null, '0');
+insert into sys_user values(2,  105, 'ry',    '鑻ヤ緷', '00', 'ry@qq.com',  '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '娴嬭瘯鍛�', null, null, null, null, null, null, null, '0');
 
 
 -- ----------------------------
diff --git a/sql/sys_notify_send_log.sql b/sql/sys_notify_send_log.sql
index fa0f91b..c415448 100644
--- a/sql/sys_notify_send_log.sql
+++ b/sql/sys_notify_send_log.sql
@@ -14,8 +14,9 @@
   `notify_type` varchar(32) NOT NULL COMMENT '閫氱煡绫诲瀷锛歍ASK_ASSIGN-浠诲姟鍒嗛厤, STATUS_CHANGE-鐘舵�佸彉鏇�, TASK_CREATE-浠诲姟鍒涘缓',
   `channel` varchar(32) NOT NULL COMMENT '閫氱煡娓犻亾锛歐ECHAT-寰俊璁㈤槄娑堟伅, SMS-鐭俊, APP_PUSH-APP鎺ㄩ��, SITE_MSG-绔欏唴娑堟伅',
   `send_status` char(1) DEFAULT '0' COMMENT '鍙戦�佺姸鎬侊細0-寰呭彂閫�, 1-鍙戦�佹垚鍔�, 2-鍙戦�佸け璐�',
+  `send_content` text COMMENT '鍙戦�佺殑鍐呭',
   `send_time` datetime DEFAULT NULL COMMENT '鍙戦�佹椂闂�',
-  `send_result` varchar(500) DEFAULT NULL COMMENT '鍙戦�佺粨鏋�/閿欒淇℃伅',
+  `send_result` text DEFAULT NULL COMMENT '鍙戦�佺粨鏋�/閿欒淇℃伅',
   `retry_count` int(11) DEFAULT 0 COMMENT '閲嶈瘯娆℃暟',
   `create_time` datetime NOT NULL COMMENT '鍒涘缓鏃堕棿',
   `create_by` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
diff --git a/sql/sys_notify_task.sql b/sql/sys_notify_task.sql
index 8a06596..87a9cfa 100644
--- a/sql/sys_notify_task.sql
+++ b/sql/sys_notify_task.sql
@@ -62,7 +62,8 @@
 INSERT INTO `sys_notify_channel_config` (`notify_type`, `channel`, `enabled`, `priority`, `config_json`, `create_by`, `create_time`, `remark`) VALUES
 ('TASK_ASSIGN', 'SITE_MSG', '1', 100, NULL, 'admin', NOW(), '浠诲姟鍒嗛厤-绔欏唴娑堟伅'),
 ('TASK_ASSIGN', 'WECHAT', '1', 90, NULL, 'admin', NOW(), '浠诲姟鍒嗛厤-寰俊璁㈤槄娑堟伅'),
-('TASK_ASSIGN', 'SMS', '0', 80, NULL, 'admin', NOW(), '浠诲姟鍒嗛厤-鐭俊锛堥粯璁ゅ叧闂級');
+('TASK_ASSIGN', 'SMS', '0', 80, NULL, 'admin', NOW(), '浠诲姟鍒嗛厤-鐭俊锛堥粯璁ゅ叧闂級'),
+('TASK_ASSIGN', 'QY_WECHAT', '0', 85, NULL, 'admin', NOW(), '浠诲姟鍒嗛厤-浼佷笟寰俊锛堥粯璁ゅ叧闂級');
 
 -- 鐘舵�佸彉鏇撮�氱煡 - 浠呭惎鐢ㄧ珯鍐呮秷鎭�
 INSERT INTO `sys_notify_channel_config` (`notify_type`, `channel`, `enabled`, `priority`, `config_json`, `create_by`, `create_time`, `remark`) VALUES
diff --git a/sql/sys_task_emergency.sql b/sql/sys_task_emergency.sql
index 8db1baf..8288b3d 100644
--- a/sql/sys_task_emergency.sql
+++ b/sql/sys_task_emergency.sql
@@ -43,6 +43,12 @@
     -- 鐥呮儏璇婃柇淇℃伅
     disease_ids VARCHAR(500) COMMENT '鐥呮儏ID鍒楄〃锛圛CD-10鐤剧梾ID鍒楄〃锛岄�楀彿鍒嗛殧锛岀敤浜庡悓姝ヨ皟搴﹀崟鐨凮rdICD_ID鍙傛暟锛�',
     
+    -- 鏃х郴缁熷悓姝ュ瓧娈�
+    legacy_dispatch_ord_no VARCHAR(50) COMMENT '鏃х郴缁熻皟搴﹀崟缂栧彿',
+    legacy_service_ns_time DATETIME COMMENT '鏃х郴缁熸湇鍔¢�氱煡鏃堕棿',
+    legacy_dispatch_ns_time DATETIME COMMENT '鏃х郴缁熻皟搴﹂�氱煡鏃堕棿',
+    legacy_dispatch_ord_class VARCHAR(50) COMMENT '鏃х郴缁熻皟搴﹀崟鍒嗙被',
+    
     -- 绯荤粺瀛楁
     create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
     update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
diff --git a/sql/update_sys_task_emergency.sql b/sql/update_sys_task_emergency.sql
new file mode 100644
index 0000000..bf160ec
--- /dev/null
+++ b/sql/update_sys_task_emergency.sql
@@ -0,0 +1,19 @@
+-- ----------------------------
+-- 鏇存柊鎬ユ晳杞繍浠诲姟鎵╁睍琛紝娣诲姞鏃х郴缁熷悓姝ュ瓧娈�
+-- ----------------------------
+
+-- 娣诲姞鏃х郴缁熻皟搴﹀崟缂栧彿瀛楁
+ALTER TABLE sys_task_emergency 
+ADD COLUMN legacy_dispatch_ord_no VARCHAR(50) COMMENT '鏃х郴缁熻皟搴﹀崟缂栧彿';
+
+-- 娣诲姞鏃х郴缁熸湇鍔¢�氱煡鏃堕棿瀛楁
+ALTER TABLE sys_task_emergency 
+ADD COLUMN legacy_service_ns_time DATETIME COMMENT '鏃х郴缁熸湇鍔¢�氱煡鏃堕棿';
+
+-- 娣诲姞鏃х郴缁熻皟搴﹂�氱煡鏃堕棿瀛楁
+ALTER TABLE sys_task_emergency 
+ADD COLUMN legacy_dispatch_ns_time DATETIME COMMENT '鏃х郴缁熻皟搴﹂�氱煡鏃堕棿';
+
+-- 娣诲姞鏃х郴缁熻皟搴﹀崟鍒嗙被瀛楁
+ALTER TABLE sys_task_emergency 
+ADD COLUMN legacy_dispatch_ord_class VARCHAR(50) COMMENT '鏃х郴缁熻皟搴﹀崟鍒嗙被';
\ No newline at end of file
diff --git a/sql/update_sys_task_emergency_add_service_ord_class.sql b/sql/update_sys_task_emergency_add_service_ord_class.sql
new file mode 100644
index 0000000..f83556c
--- /dev/null
+++ b/sql/update_sys_task_emergency_add_service_ord_class.sql
@@ -0,0 +1,8 @@
+-- ----------------------------
+-- 涓簊ys_task_emergency琛ㄦ坊鍔爈egacy_service_ord_class瀛楁
+-- 鐢ㄤ簬瀛樺偍鏃х郴缁熸湇鍔″崟鍒嗙被淇℃伅
+-- ----------------------------
+
+-- 娣诲姞鏃х郴缁熸湇鍔″崟鍒嗙被瀛楁
+ALTER TABLE sys_task_emergency 
+ADD COLUMN legacy_service_ord_class VARCHAR(50) COMMENT '鏃х郴缁熸湇鍔″崟鍒嗙被';
\ No newline at end of file

--
Gitblit v1.9.1