From 0b80903f3d48b3c39570c097a4334cb7eb71d08f Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期日, 21 九月 2025 14:11:42 +0800
Subject: [PATCH] feat:通用任务初始化

---
 ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml                       |  104 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java                  |  103 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskType.java                   |   43 
 ruoyi-ui/src/api/task.js                                                                 |  159 +
 prd/任务车辆关联.md                                                                            |  301 ++
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskAttachmentMapper.java          |   77 
 sql/task_menu.sql                                                                        |   27 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java |   84 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java                 |  174 +
 ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskCodeGenerator.java                 |   38 
 ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml                |   95 
 ruoyi-ui/src/router/index.js                                                             |   14 
 ruoyi-system/src/main/resources/mapper/system/SysTaskVehicleMapper.xml                   |  114 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java                          |  369 +++
 sql/task_tables.sql                                                                      |  113 +
 ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java               |   66 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/VehicleType.java                |   43 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java                |  126 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java                 |   46 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java           |  205 +
 ruoyi-ui/src/views/task/general/detail.vue                                               |  564 +++++
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskLogMapper.java                 |   77 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskStatisticsVO.java              |   98 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java         |  567 +++++
 prd/通用任务管理功能说明.md                                                                        | 1156 ++++++++++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java                   |  140 +
 ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml                          |  198 +
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskMapper.java                    |  109 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskVehicleMapper.java             |  103 
 README_TASK.md                                                                           |  183 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskUpdateVO.java                  |  103 
 ruoyi-ui/src/views/task/general/index.vue                                                |  535 ++++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskVehicle.java                   |  152 +
 sql/task_dict_data.sql                                                                   |   39 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java                       |  152 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskVehicleStatus.java          |   46 
 sql/vehicle_info.sql                                                                     |    5 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskVehicleController.java    |  158 +
 38 files changed, 6,686 insertions(+), 0 deletions(-)

diff --git a/README_TASK.md b/README_TASK.md
new file mode 100644
index 0000000..a6c0dca
--- /dev/null
+++ b/README_TASK.md
@@ -0,0 +1,183 @@
+# 閫氱敤浠诲姟绠$悊鍔熻兘浣跨敤璇存槑
+
+## 鍔熻兘姒傝堪
+
+閫氱敤浠诲姟绠$悊鍔熻兘鏄熀浜庤嫢渚濇鏋跺紑鍙戠殑瀹屾暣浠诲姟绠$悊绯荤粺锛屾敮鎸佺淮淇繚鍏汇�佸姞娌逛换鍔°�佸叾浠栦换鍔$被鍨嬬殑鍏ㄧ敓鍛藉懆鏈熺鐞嗐��
+
+## 涓昏鍔熻兘
+
+### 1. 浠诲姟绠$悊
+- **浠诲姟鍒涘缓**锛氭敮鎸佸垱寤虹淮淇繚鍏汇�佸姞娌逛换鍔°�佸叾浠栫被鍨嬩换鍔�
+- **浠诲姟鏌ヨ**锛氭敮鎸佹寜浠诲姟缂栧彿銆佺被鍨嬨�佺姸鎬併�佹椂闂磋寖鍥寸瓑鏉′欢鏌ヨ
+- **浠诲姟缂栬緫**锛氭敮鎸佷慨鏀逛换鍔℃弿杩般�佸湴鍧�銆佹椂闂淬�佹墽琛屼汉绛変俊鎭�
+- **浠诲姟鍒犻櫎**锛氭敮鎸佸崟涓垨鎵归噺鍒犻櫎浠诲姟
+- **浠诲姟鍒嗛厤**锛氭敮鎸佸皢浠诲姟鍒嗛厤缁欐寚瀹氭墽琛屼汉
+- **鐘舵�佺鐞�**锛氭敮鎸佷换鍔$姸鎬佹祦杞紙寰呭紑濮嬧啋浠诲姟涓啋宸插畬鎴愶紝浠讳綍鐘舵�佸彲鍙栨秷锛�
+
+### 2. 杞﹁締绠$悊
+- **杞﹁締鍒嗛厤**锛氭敮鎸佸皢杞﹁締鍒嗛厤缁欎换鍔�
+- **鎵归噺鍒嗛厤**锛氭敮鎸佷竴娆℃�у垎閰嶅杈嗚溅缁欎换鍔�
+- **鍙栨秷鍒嗛厤**锛氭敮鎸佸彇娑堣溅杈嗕笌浠诲姟鐨勫叧鑱�
+- **杞﹁締鏌ヨ**锛氭敮鎸佹煡璇㈠彲鐢ㄨ溅杈嗗垪琛�
+
+### 3. 闄勪欢绠$悊
+- **鏂囦欢涓婁紶**锛氭敮鎸佷笂浼犱换鍔$浉鍏抽檮浠讹紙PDF銆丏OC銆佸浘鐗囩瓑锛�
+- **鏂囦欢涓嬭浇**锛氭敮鎸佷笅杞藉凡涓婁紶鐨勯檮浠�
+- **鏂囦欢鍒犻櫎**锛氭敮鎸佸垹闄や笉闇�瑕佺殑闄勪欢
+
+### 4. 鎿嶄綔鏃ュ織
+- **鏃ュ織璁板綍**锛氳嚜鍔ㄨ褰曟墍鏈変换鍔℃搷浣滄棩蹇�
+- **鏃ュ織鏌ヨ**锛氭敮鎸佹煡鐪嬩换鍔$殑鎿嶄綔鍘嗗彶
+- **鎿嶄綔杩借釜**锛氳褰曟搷浣滀汉銆佹搷浣滄椂闂淬�佹搷浣滃唴瀹圭瓑璇︾粏淇℃伅
+
+### 5. 缁熻鍔熻兘
+- **浠诲姟缁熻**锛氭彁渚涗换鍔℃�绘暟銆佸悇鐘舵�佷换鍔℃暟閲忋�佽秴鏃朵换鍔$瓑缁熻淇℃伅
+- **鎴戠殑浠诲姟**锛氭敮鎸佹煡鐪嬪綋鍓嶇敤鎴峰垱寤烘垨鍒嗛厤鐨勪换鍔�
+- **瓒呮椂鎻愰啋**锛氳嚜鍔ㄨ瘑鍒拰鎻愰啋瓒呮椂浠诲姟
+
+## 鏁版嵁搴撹〃缁撴瀯
+
+### 鏍稿績琛�
+1. **sys_task** - 浠诲姟涓昏〃
+2. **sys_task_vehicle** - 浠诲姟杞﹁締鍏宠仈琛�
+3. **sys_task_attachment** - 浠诲姟闄勪欢琛�
+4. **sys_task_log** - 浠诲姟鎿嶄綔鏃ュ織琛�
+
+### 鏁版嵁瀛楀吀
+- **sys_task_type** - 浠诲姟绫诲瀷瀛楀吀
+- **sys_task_status** - 浠诲姟鐘舵�佸瓧鍏�
+- **sys_vehicle_type** - 杞﹁締绫诲瀷瀛楀吀
+- **sys_vehicle_status** - 杞﹁締鐘舵�佸瓧鍏�
+- **sys_task_vehicle_status** - 浠诲姟杞﹁締鍏宠仈鐘舵�佸瓧鍏�
+
+## 閮ㄧ讲姝ラ
+
+### 1. 鏁版嵁搴撳垵濮嬪寲
+```sql
+-- 鎵ц琛ㄧ粨鏋勫垱寤鸿剼鏈�
+source sql/task_tables.sql;
+
+-- 鎵ц鏁版嵁瀛楀吀鍒濆鍖栬剼鏈�
+source sql/task_dict_data.sql;
+
+-- 鎵ц鑿滃崟鏉冮檺鍒濆鍖栬剼鏈�
+source sql/task_menu.sql;
+```
+
+### 2. 鍚庣閮ㄧ讲
+1. 纭繚鎵�鏈塉ava鏂囦欢宸叉纭斁缃埌瀵瑰簲鐩綍
+2. 閲嶆柊缂栬瘧椤圭洰锛歚mvn clean compile`
+3. 閲嶅惎搴旂敤鏈嶅姟
+
+### 3. 鍓嶇閮ㄧ讲
+1. 纭繚鎵�鏈塚ue鏂囦欢宸叉纭斁缃埌瀵瑰簲鐩綍
+2. 閲嶆柊鏋勫缓鍓嶇锛歚npm run build:prod`
+3. 閮ㄧ讲鍒癢eb鏈嶅姟鍣�
+
+### 4. 鏉冮檺閰嶇疆
+1. 鐧诲綍绯荤粺绠$悊鍚庡彴
+2. 杩涘叆"绯荤粺绠$悊" 鈫� "鑿滃崟绠$悊"
+3. 纭浠诲姟绠$悊鐩稿叧鑿滃崟宸叉纭垱寤�
+4. 涓虹浉搴旇鑹插垎閰嶄换鍔$鐞嗘潈闄�
+
+## API鎺ュ彛璇存槑
+
+### 浠诲姟绠$悊鎺ュ彛
+- `GET /task/list` - 鏌ヨ浠诲姟鍒楄〃
+- `GET /task/{taskId}` - 鑾峰彇浠诲姟璇︽儏
+- `POST /task` - 鍒涘缓浠诲姟
+- `PUT /task` - 鏇存柊浠诲姟
+- `DELETE /task/{taskIds}` - 鍒犻櫎浠诲姟
+- `PUT /task/{taskId}/assign` - 鍒嗛厤浠诲姟
+- `PUT /task/{taskId}/status` - 鏇存柊浠诲姟鐘舵��
+
+### 杞﹁締绠$悊鎺ュ彛
+- `GET /task/vehicle/list/{taskId}` - 鏌ヨ浠诲姟鍏宠仈杞﹁締
+- `GET /task/vehicle/available` - 鏌ヨ鍙敤杞﹁締
+- `POST /task/vehicle/assign/{taskId}` - 鍒嗛厤杞﹁締
+- `POST /task/vehicle/assign-batch/{taskId}` - 鎵归噺鍒嗛厤杞﹁締
+- `DELETE /task/vehicle/{taskId}/{vehicleId}` - 鍙栨秷杞﹁締鍒嗛厤
+
+### 闄勪欢绠$悊鎺ュ彛
+- `GET /task/attachment/list/{taskId}` - 鏌ヨ浠诲姟闄勪欢
+- `POST /task/attachment/upload/{taskId}` - 涓婁紶闄勪欢
+- `DELETE /task/attachment/{attachmentId}` - 鍒犻櫎闄勪欢
+
+### 缁熻鎺ュ彛
+- `GET /task/statistics` - 鑾峰彇浠诲姟缁熻淇℃伅
+- `GET /task/overdue` - 鑾峰彇瓒呮椂浠诲姟鍒楄〃
+- `GET /task/my` - 鑾峰彇鎴戠殑浠诲姟鍒楄〃
+
+## 浣跨敤璇存槑
+
+### 1. 鍒涘缓浠诲姟
+1. 杩涘叆"浠诲姟绠$悊" 鈫� "閫氱敤浠诲姟"
+2. 鐐瑰嚮"鏂板"鎸夐挳
+3. 濉啓浠诲姟淇℃伅锛�
+   - 浠诲姟绫诲瀷锛氶�夋嫨缁翠慨淇濆吇銆佸姞娌逛换鍔℃垨鍏朵粬
+   - 浠诲姟鎻忚堪锛氳缁嗘弿杩颁换鍔″唴瀹�
+   - 鍑哄彂鍦板潃锛氫换鍔¤捣濮嬪湴鐐�
+   - 鐩殑鍦板潃锛氫换鍔$洰鏍囧湴鐐�
+   - 璁″垝鏃堕棿锛氳缃鍒掑紑濮嬪拰缁撴潫鏃堕棿
+   - 鎵ц浜猴細閫夋嫨浠诲姟鎵ц浜�
+   - 澶囨敞锛氬叾浠栬鏄庝俊鎭�
+4. 鐐瑰嚮"纭畾"淇濆瓨
+
+### 2. 鍒嗛厤杞﹁締
+1. 鍦ㄤ换鍔″垪琛ㄤ腑鐐瑰嚮"鏌ョ湅"杩涘叆浠诲姟璇︽儏
+2. 鍦�"鍏宠仈杞﹁締"鍖哄煙鐐瑰嚮"鍒嗛厤杞﹁締"
+3. 閫夋嫨瑕佸垎閰嶇殑杞﹁締锛堝彲澶氶�夛級
+4. 濉啓鍒嗛厤澶囨敞
+5. 鐐瑰嚮"纭畾"瀹屾垚鍒嗛厤
+
+### 3. 涓婁紶闄勪欢
+1. 鍦ㄤ换鍔¤鎯呴〉闈㈢偣鍑�"涓婁紶闄勪欢"
+2. 閫夋嫨瑕佷笂浼犵殑鏂囦欢锛堟敮鎸丳DF銆丏OC銆佸浘鐗囩瓑鏍煎紡锛�
+3. 鏂囦欢澶у皬涓嶈秴杩�10MB
+4. 涓婁紶瀹屾垚鍚庡彲鍦ㄩ檮浠跺垪琛ㄤ腑鏌ョ湅鍜屼笅杞�
+
+### 4. 鐘舵�佺鐞�
+1. 鍦ㄤ换鍔″垪琛ㄦ垨璇︽儏椤甸潰鐐瑰嚮"鐘舵�佸彉鏇�"
+2. 閫夋嫨鏂扮殑浠诲姟鐘舵��
+3. 濉啓鐘舵�佸彉鏇村娉�
+4. 绯荤粺浼氳嚜鍔ㄨ褰曠姸鎬佸彉鏇存棩蹇�
+
+## 鏉冮檺璇存槑
+
+### 鑿滃崟鏉冮檺
+- `task:general:view` - 浠诲姟鏌ョ湅鏉冮檺
+- `task:general:query` - 浠诲姟鏌ヨ鏉冮檺
+- `task:general:add` - 浠诲姟鏂板鏉冮檺
+- `task:general:edit` - 浠诲姟淇敼鏉冮檺
+- `task:general:remove` - 浠诲姟鍒犻櫎鏉冮檺
+- `task:general:assign` - 浠诲姟鍒嗛厤鏉冮檺
+- `task:general:status` - 鐘舵�佸彉鏇存潈闄�
+- `task:general:export` - 浠诲姟瀵煎嚭鏉冮檺
+
+### 鏁版嵁鏉冮檺
+绯荤粺鍩轰簬閮ㄩ棬杩涜鏁版嵁闅旂锛岀敤鎴峰彧鑳芥煡鐪嬪拰鎿嶄綔鏈儴闂ㄥ強涓嬬骇閮ㄩ棬鐨勬暟鎹��
+
+## 娉ㄦ剰浜嬮」
+
+1. **浠诲姟缂栧彿**锛氱郴缁熻嚜鍔ㄧ敓鎴愶紝鏍煎紡涓篢ASK+鏃ユ湡+搴忓彿
+2. **鐘舵�佹祦杞�**锛氬繀椤绘寜鐓т笟鍔¤鍒欒繘琛岀姸鎬佹祦杞紝涓嶅厑璁歌烦璺冨紡鍙樻洿
+3. **鏂囦欢涓婁紶**锛氭敮鎸佺殑鏂囦欢绫诲瀷鍜屽ぇ灏忔湁闄愬埗锛岃鎸夎姹備笂浼�
+4. **鏁版嵁澶囦唤**锛氬缓璁畾鏈熷浠戒换鍔$浉鍏虫暟鎹�
+5. **鎬ц兘浼樺寲**锛氬ぇ閲忔暟鎹椂寤鸿浣跨敤鍒嗛〉鏌ヨ
+
+## 鏁呴殰鎺掗櫎
+
+### 甯歌闂
+1. **鑿滃崟涓嶆樉绀�**锛氭鏌ヨ彍鍗曟潈闄愰厤缃拰瑙掕壊鍒嗛厤
+2. **鎺ュ彛璋冪敤澶辫触**锛氭鏌ュ悗绔湇鍔℃槸鍚︽甯稿惎鍔�
+3. **鏂囦欢涓婁紶澶辫触**锛氭鏌ユ枃浠跺ぇ灏忓拰鏍煎紡鏄惁绗﹀悎瑕佹眰
+4. **鐘舵�佸彉鏇村け璐�**锛氭鏌ョ姸鎬佹祦杞鍒欐槸鍚﹀厑璁�
+
+### 鏃ュ織鏌ョ湅
+- 鍚庣鏃ュ織锛氭煡鐪嬪簲鐢ㄦ棩蹇楁枃浠�
+- 鍓嶇鏃ュ織锛氭墦寮�娴忚鍣ㄥ紑鍙戣�呭伐鍏锋煡鐪嬫帶鍒跺彴
+- 鏁版嵁搴撴棩蹇楋細鏌ョ湅鏁版嵁搴撴搷浣滄棩蹇�
+
+## 鎶�鏈敮鎸�
+
+濡傛湁闂璇疯仈绯荤郴缁熺鐞嗗憳鎴栧紑鍙戝洟闃熴��
diff --git "a/prd/\344\273\273\345\212\241\350\275\246\350\276\206\345\205\263\350\201\224.md" "b/prd/\344\273\273\345\212\241\350\275\246\350\276\206\345\205\263\350\201\224.md"
new file mode 100644
index 0000000..9c02089
--- /dev/null
+++ "b/prd/\344\273\273\345\212\241\350\275\246\350\276\206\345\205\263\350\201\224.md"
@@ -0,0 +1,301 @@
+# 浠诲姟杞﹁締鍏宠仈鍏崇郴璁捐
+
+## 鍏崇郴姒傝堪
+
+鏍规嵁涓氬姟闇�姹傦紝浠诲姟绠$悊绯荤粺闇�瑕佸缓绔嬩互涓嬪叧鑱斿叧绯伙細
+
+1. **浠诲姟 鈫� 杞﹁締**锛氫竴涓换鍔″彲浠ュ叧鑱斿杈嗚溅锛屼竴杈嗚溅鍙互鎵ц澶氫釜浠诲姟
+2. **杞﹁締 鈫� 鏈烘瀯**锛氭瘡杈嗚溅褰掑睘浜庝竴涓満鏋�
+3. **浠诲姟 鈫� 鎵ц浜�**锛氭瘡涓换鍔″垎閰嶇粰涓�涓墽琛屼汉
+4. **鎵ц浜� 鈫� 鏈烘瀯**锛氭瘡涓墽琛屼汉褰掑睘浜庝竴涓満鏋�
+
+## 鏁版嵁搴撳叧绯昏璁�
+
+### 1. 鏍稿績鍏宠仈鍏崇郴
+
+```mermaid
+erDiagram
+    sys_task ||--o{ sys_task_vehicle : "涓�瀵瑰"
+    tb_vehicle_info ||--o{ sys_task_vehicle : "涓�瀵瑰"
+    sys_dept ||--o{ tb_vehicle_info : "涓�瀵瑰"
+    sys_dept ||--o{ sys_task : "涓�瀵瑰"
+    sys_user ||--o{ sys_task : "涓�瀵瑰"
+    sys_dept ||--o{ sys_user : "涓�瀵瑰"
+    
+    sys_task {
+        bigint task_id PK
+        varchar task_code UK
+        varchar task_type
+        varchar task_status
+        bigint creator_id FK
+        bigint assignee_id FK
+        bigint dept_id FK
+        bigint vehicle_id FK
+    }
+    
+    tb_vehicle_info {
+        bigint vehicle_id PK
+        varchar platform_code
+        varchar vehicle_no UK
+        varchar vehicle_type
+        varchar vehicle_brand
+        varchar vehicle_model
+        varchar vehicle_color
+        char vehicle_status
+        varchar device_id
+        bigint dept_id FK
+    }
+    
+    sys_task_vehicle {
+        bigint id PK
+        bigint task_id FK
+        bigint vehicle_id FK
+        datetime assign_time
+        varchar assign_by
+        varchar status
+        varchar remark
+    }
+    
+    sys_dept {
+        bigint dept_id PK
+        varchar dept_name
+        bigint parent_id
+    }
+    
+    sys_user {
+        bigint user_id PK
+        varchar user_name
+        bigint dept_id FK
+    }
+```
+
+### 2. 鍏宠仈鍏崇郴璇存槑
+
+#### 2.1 浠诲姟涓庤溅杈嗗叧鑱�
+- **鍏崇郴绫诲瀷**锛氬瀵瑰锛堥�氳繃涓棿琛� `sys_task_vehicle`锛�
+- **涓氬姟瑙勫垯**锛�
+  - **涓�涓换鍔″彲浠ュ垎閰嶅杈嗚溅**锛堝锛氫富杞�+澶囩敤杞︺�佸杞﹀崗鍚屼綔涓氾級
+  - **涓�杈嗚溅鍙互鎵ц澶氫釜浠诲姟**锛堟寜鏃堕棿椤哄簭锛岄伩鍏嶅啿绐侊級
+  - **浠诲姟杞﹁締鍏宠仈鏈夌嫭绔嬬姸鎬佺鐞�**锛堝凡鍒嗛厤銆佹墽琛屼腑銆佸凡瀹屾垚銆佸凡鍙栨秷锛�
+  - **鏀寔鎵归噺鍒嗛厤鍜屽彇娑堝垎閰�**
+  - **杞﹁締鍒嗛厤鏃堕獙璇佽溅杈嗙姸鎬佸拰鍙敤鎬�**
+
+#### 2.2 杞﹁締涓庢満鏋勫叧鑱�
+- **鍏崇郴绫诲瀷**锛氬瀵逛竴
+- **涓氬姟瑙勫垯**锛�
+  - 姣忚締杞﹀繀椤诲綊灞炰簬涓�涓満鏋�
+  - 鏈烘瀯鍒犻櫎鏃讹紝杞﹁締褰掑睘璁剧疆涓篘ULL锛堣蒋鍒犻櫎锛�
+  - 鏀寔鎸夋満鏋勬煡璇㈣溅杈�
+
+#### 2.3 浠诲姟涓庢墽琛屼汉鍏宠仈
+- **鍏崇郴绫诲瀷**锛氬瀵逛竴
+- **涓氬姟瑙勫垯**锛�
+  - 姣忎釜浠诲姟鍒嗛厤缁欎竴涓墽琛屼汉
+  - 鎵ц浜哄繀椤讳笌浠诲姟鍦ㄥ悓涓�鏈烘瀯鎴栦笂绾ф満鏋�
+  - 鏀寔浠诲姟閲嶆柊鍒嗛厤
+
+#### 2.4 鎵ц浜轰笌鏈烘瀯鍏宠仈
+- **鍏崇郴绫诲瀷**锛氬瀵逛竴
+- **涓氬姟瑙勫垯**锛�
+  - 姣忎釜鎵ц浜哄綊灞炰簬涓�涓満鏋�
+  - 鏀寔鏈烘瀯灞傜骇鏉冮檺鎺у埗
+
+## 鏁版嵁鏉冮檺鎺у埗
+
+### 1. 鏈烘瀯鏁版嵁闅旂
+```sql
+-- 鏌ヨ浠诲姟鏃舵寜鏈烘瀯杩囨护
+SELECT t.* FROM sys_task t 
+WHERE t.dept_id IN (
+    SELECT dept_id FROM sys_dept 
+    WHERE FIND_IN_SET(dept_id, @user_dept_ids)
+);
+
+-- 鏌ヨ杞﹁締鏃舵寜鏈烘瀯杩囨护
+SELECT v.* FROM tb_vehicle_info v 
+WHERE v.dept_id IN (
+    SELECT dept_id FROM sys_dept 
+    WHERE FIND_IN_SET(dept_id, @user_dept_ids)
+);
+```
+
+### 2. 鏉冮檺楠岃瘉瑙勫垯
+- **浠诲姟鍒涘缓**锛氬彧鑳藉垱寤烘湰鏈烘瀯鍙婁笅绾ф満鏋勭殑浠诲姟
+- **杞﹁締鍒嗛厤**锛氬彧鑳藉垎閰嶆湰鏈烘瀯鍙婁笅绾ф満鏋勭殑杞﹁締
+- **鎵ц浜哄垎閰�**锛氬彧鑳藉垎閰嶇粰鏈満鏋勫強涓嬬骇鏈烘瀯鐨勭敤鎴�
+- **鏁版嵁鏌ヨ**锛氬彧鑳芥煡鐪嬫湰鏈烘瀯鍙婁笅绾ф満鏋勭殑鏁版嵁
+
+## 涓氬姟鍦烘櫙绀轰緥
+
+### 1. 鍒涘缓缁翠慨浠诲姟骞跺垎閰嶅杈嗚溅
+```sql
+-- 1. 鍒涘缓浠诲姟
+INSERT INTO sys_task (task_code, task_type, task_status, creator_id, dept_id, ...)
+VALUES ('TASK202401150001', 'MAINTENANCE', 'PENDING', 100, 200, ...);
+
+-- 2. 鍒嗛厤澶氳締杞︼紙涓昏溅+澶囩敤杞︼級
+INSERT INTO sys_task_vehicle (task_id, vehicle_id, assign_by, status, remark)
+VALUES 
+(1, 10, 'admin', 'ASSIGNED', '鍒嗛厤涓荤淮淇溅'),
+(1, 11, 'admin', 'ASSIGNED', '鍒嗛厤澶囩敤缁翠慨杞�'),
+(1, 12, 'admin', 'ASSIGNED', '鍒嗛厤宸ュ叿杞�');
+
+-- 3. 鍒嗛厤鎵ц浜�
+UPDATE sys_task SET assignee_id = 150 WHERE task_id = 1;
+```
+
+### 2. 鏌ヨ鏈烘瀯涓嬬殑鎵�鏈変换鍔″拰杞﹁締
+```sql
+-- 鏌ヨ鏈烘瀯浠诲姟
+SELECT t.task_code, t.task_type, t.task_status, 
+       u.user_name as assignee_name,
+       d.dept_name
+FROM sys_task t
+LEFT JOIN sys_user u ON t.assignee_id = u.user_id
+LEFT JOIN sys_dept d ON t.dept_id = d.dept_id
+WHERE t.dept_id = 200;
+
+-- 鏌ヨ鏈烘瀯杞﹁締
+SELECT v.vehicle_no, v.vehicle_type, v.vehicle_status,
+       d.dept_name
+FROM tb_vehicle_info v
+LEFT JOIN sys_dept d ON v.dept_id = d.dept_id
+WHERE v.dept_id = 200;
+```
+
+### 3. 鏌ヨ浠诲姟鐨勮溅杈嗗垎閰嶆儏鍐�
+```sql
+SELECT t.task_code, t.task_type,
+       v.vehicle_no, v.vehicle_type,
+       tv.assign_time, tv.status, tv.remark
+FROM sys_task t
+LEFT JOIN sys_task_vehicle tv ON t.task_id = tv.task_id
+LEFT JOIN tb_vehicle_info v ON tv.vehicle_id = v.vehicle_id
+WHERE t.task_id = 1;
+```
+
+## 鎺ュ彛璁捐鎵╁睍
+
+### 1. 杞﹁締绠$悊鎺ュ彛
+```javascript
+// 鏌ヨ鏈烘瀯杞﹁締鍒楄〃
+export function listVehicleByDept(deptId, query) {
+  return request({
+    url: '/api/vehicle/list-by-dept/' + deptId,
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ鍙敤杞﹁締锛堟湭鍒嗛厤浠诲姟鐨勮溅杈嗭級
+export function listAvailableVehicles(deptId, taskType) {
+  return request({
+    url: '/api/vehicle/available',
+    method: 'get',
+    params: { deptId, taskType }
+  })
+}
+```
+
+### 2. 浠诲姟杞﹁締鍒嗛厤鎺ュ彛
+```javascript
+// 鎵归噺鍒嗛厤杞﹁締
+export function assignVehiclesToTask(taskId, vehicleIds, remark) {
+  return request({
+    url: '/api/task/' + taskId + '/assign-vehicles',
+    method: 'post',
+    data: { vehicleIds, remark }
+  })
+}
+
+// 鏌ヨ浠诲姟杞﹁締浣跨敤鎯呭喌
+export function getTaskVehicleUsage(taskId) {
+  return request({
+    url: '/api/task/' + taskId + '/vehicle-usage',
+    method: 'get'
+  })
+}
+```
+
+## 鏁版嵁涓�鑷存�т繚璇�
+
+### 1. 澶栭敭绾︽潫
+- 浠诲姟琛ㄥ紩鐢ㄨ溅杈嗚〃锛歚ON DELETE SET NULL`
+- 浠诲姟杞﹁締鍏宠仈琛細`ON DELETE CASCADE`
+- 杞﹁締琛ㄥ紩鐢ㄦ満鏋勮〃锛歚ON DELETE SET NULL`
+
+### 2. 涓氬姟瑙勫垯楠岃瘉
+- 杞﹁締鍒嗛厤鏃堕獙璇佽溅杈嗙姸鎬侊紙蹇呴』涓烘甯哥姸鎬侊級
+- 浠诲姟鍒嗛厤鏃堕獙璇佹墽琛屼汉鏉冮檺锛堝悓鏈烘瀯鎴栦笂绾ф満鏋勶級
+- 鏈烘瀯鍒犻櫎鏃跺鐞嗗叧鑱旀暟鎹紙杞垹闄ゆ垨杞Щ锛�
+
+### 3. 浜嬪姟鎺у埗
+```java
+@Transactional
+public void assignMultipleVehiclesToTask(Long taskId, List<Long> vehicleIds, String remark) {
+    // 1. 楠岃瘉浠诲姟鐘舵��
+    Task task = taskMapper.selectById(taskId);
+    if (task.getStatus() == TaskStatus.COMPLETED) {
+        throw new BusinessException("宸插畬鎴愮殑浠诲姟涓嶈兘鍒嗛厤杞﹁締");
+    }
+    
+    List<TaskVehicle> assignedVehicles = new ArrayList<>();
+    
+    for (Long vehicleId : vehicleIds) {
+        // 2. 楠岃瘉杞﹁締鐘舵�佸拰鍙敤鎬�
+        Vehicle vehicle = vehicleMapper.selectById(vehicleId);
+        if (vehicle.getStatus() != VehicleStatus.ACTIVE) {
+            throw new BusinessException("杞﹁締ID " + vehicleId + " 鐘舵�佸紓甯革紝涓嶈兘鍒嗛厤");
+        }
+        
+        // 3. 妫�鏌ヨ溅杈嗘槸鍚﹀凡琚叾浠栦换鍔″崰鐢�
+        if (isVehicleAssignedToOtherTask(vehicleId, taskId)) {
+            throw new BusinessException("杞﹁締ID " + vehicleId + " 宸茶鍏朵粬浠诲姟鍗犵敤");
+        }
+        
+        // 4. 鍒涘缓鍏宠仈璁板綍
+        TaskVehicle taskVehicle = new TaskVehicle();
+        taskVehicle.setTaskId(taskId);
+        taskVehicle.setVehicleId(vehicleId);
+        taskVehicle.setStatus(TaskVehicleStatus.ASSIGNED);
+        taskVehicle.setRemark(remark);
+        taskVehicleMapper.insert(taskVehicle);
+        assignedVehicles.add(taskVehicle);
+    }
+    
+    // 5. 璁板綍鎿嶄綔鏃ュ織
+    logTaskOperation(taskId, "ASSIGN_MULTIPLE_VEHICLES", 
+        "鍒嗛厤浜� " + vehicleIds.size() + " 杈嗚溅: " + vehicleIds.toString());
+}
+
+@Transactional
+public void unassignVehicleFromTask(Long taskId, Long vehicleId) {
+    // 1. 楠岃瘉浠诲姟杞﹁締鍏宠仈鏄惁瀛樺湪
+    TaskVehicle taskVehicle = taskVehicleMapper.selectByTaskAndVehicle(taskId, vehicleId);
+    if (taskVehicle == null) {
+        throw new BusinessException("浠诲姟杞﹁締鍏宠仈涓嶅瓨鍦�");
+    }
+    
+    // 2. 楠岃瘉鏄惁鍙互鍙栨秷鍒嗛厤
+    if (taskVehicle.getStatus() == TaskVehicleStatus.COMPLETED) {
+        throw new BusinessException("宸插畬鎴愮殑浠诲姟杞﹁締鍏宠仈涓嶈兘鍙栨秷");
+    }
+    
+    // 3. 鍒犻櫎鍏宠仈璁板綍
+    taskVehicleMapper.deleteById(taskVehicle.getId());
+    
+    // 4. 璁板綍鎿嶄綔鏃ュ織
+    logTaskOperation(taskId, "UNASSIGN_VEHICLE", "鍙栨秷鍒嗛厤杞﹁締ID: " + vehicleId);
+}
+```
+
+## 鎬荤粨
+
+閫氳繃浠ヤ笂璁捐锛屽疄鐜颁簡浠诲姟銆佽溅杈嗐�佹満鏋勫拰鎵ц浜轰箣闂寸殑瀹屾暣鍏宠仈鍏崇郴锛�
+
+1. **鏁版嵁瀹屾暣鎬�**锛氶�氳繃澶栭敭绾︽潫淇濊瘉鏁版嵁涓�鑷存��
+2. **鏉冮檺鎺у埗**锛氬熀浜庢満鏋勭殑鏁版嵁闅旂鍜屾潈闄愰獙璇�
+3. **涓氬姟鐏垫椿鎬�**锛氭敮鎸佸杞﹁締鍒嗛厤鍜岀姸鎬佺鐞�
+4. **鎵╁睍鎬�**锛氶鐣欎簡璁惧ID绛夊瓧娈碉紝鏀寔GPS瀹氫綅绛夊姛鑳芥墿灞�
+
+杩欎釜璁捐鏃㈡弧瓒充簡褰撳墠鐨勪笟鍔¢渶姹傦紝鍙堜负鏈潵鐨勫姛鑳芥墿灞曠暀涓嬩簡绌洪棿銆�
diff --git "a/prd/\351\200\232\347\224\250\344\273\273\345\212\241\347\256\241\347\220\206\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/prd/\351\200\232\347\224\250\344\273\273\345\212\241\347\256\241\347\220\206\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..a235574
--- /dev/null
+++ "b/prd/\351\200\232\347\224\250\344\273\273\345\212\241\347\256\241\347\220\206\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,1156 @@
+# 閫氱敤浠诲姟绠$悊鍔熻兘璇存槑
+
+## 鍔熻兘姒傝堪
+
+鏍规嵁闇�姹傛枃妗o紝宸插畬鎴愰�氱敤浠诲姟鍜岃浆杩愪换鍔$殑鍚庡彴绠$悊鍔熻兘寮�鍙戯紝鍖呮嫭锛�
+
+1. **閫氱敤浠诲姟绠$悊** - 鏀寔缁翠慨淇濆吇銆佸姞娌逛换鍔°�佸叾浠栦换鍔$被鍨�
+2. **瀹屾暣鐨凜RUD鎿嶄綔** - 鍒涘缓銆佹煡璇€�佹洿鏂般�佸垹闄ゃ�佸垎閰嶃�佺姸鎬佺鐞�
+3. **鏉冮檺鎺у埗** - 鍩轰簬瑙掕壊鐨勬搷浣滄潈闄愭帶鍒�
+4. **鏁版嵁闅旂** - 鍩轰簬鏈烘瀯鐨勬暟鎹潈闄愰殧绂�
+
+## 鎶�鏈灦鏋�
+### 鍚庣鏋舵瀯 (ruoyi-task妯″潡)
+- 閲囩敤DDD鏋舵瀯璁捐锛屽垎灞傛槑纭�
+- **棰嗗煙灞�**: 浠诲姟鑱氬悎鏍广�佸�煎璞°�侀鍩熸湇鍔�
+- **搴旂敤灞�**: CQRS鍛戒护鏌ヨ鍒嗙銆佸簲鐢ㄦ湇鍔�
+- **鍩虹璁炬柦灞�**: 鎸佷箙鍖栥�佹秷鎭帹閫�
+- **鎺ュ彛灞�**: REST API鎺у埗鍣�
+
+### 鍓嶇鏋舵瀯 (ruoyi-ui妯″潡)
+- **椤甸潰缁勪欢**: 浠诲姟鍒楄〃銆佷换鍔¤鎯呫�佷换鍔″垱寤�
+- **API鏈嶅姟**: 缁熶竴鐨凙PI鎺ュ彛璋冪敤
+- **璺敱閰嶇疆**: 鍔ㄦ�佽矾鐢卞拰鏉冮檺鎺у埗
+
+## 鏍稿績鍔熻兘
+
+### 1. 浠诲姟绫诲瀷绠$悊
+
+#### 閫氱敤浠诲姟绫诲瀷
+- **缁翠慨淇濆吇** (MAINTENANCE) - 杞﹁締缁翠慨淇濆吇浠诲姟
+- **鍔犳补浠诲姟** (FUEL) - 杞﹁締鍔犳补浠诲姟
+- **鍏朵粬** (OTHER) - 鍏朵粬绫诲瀷浠诲姟
+
+
+
+### 2. 浠诲姟鐘舵�佺鐞�
+
+#### 浠诲姟鐘舵�佸畾涔�
+- **寰呭紑濮�** (PENDING) - 浠诲姟宸插垱寤猴紝绛夊緟寮�濮�
+- **浠诲姟涓�** (IN_PROGRESS) - 浠诲姟宸茬粡寮�濮�
+- **宸插畬鎴�** (COMPLETED) - 浠诲姟宸插畬鎴�
+- **宸插彇娑�** (CANCELLED) - 浠诲姟宸插彇娑�
+
+
+#### 浠诲姟鐘舵�佹祦杞鍒�
+##### 浠诲姟鐘舵�佹祦杞鍒�
+- **PENDING** 鈫� **IN_PROGRESS** 鈫� **COMPLETED**
+- 浠讳綍鐘舵�侀兘鍙互娴佽浆鍒� **CANCELLED**锛堥櫎浜� **COMPLETED**锛�
+
+
+
+##### 鐘舵�佹祦杞害鏉�
+1. 浠诲姟鐘舵�佹祦杞繀椤荤鍚堜笟鍔¢�昏緫椤哄簭
+2. 鏀寔鐘舵�佸洖閫�锛堝浠� IN_PROGRESS 鍥炲埌 PENDING锛�
+3. 浠诲姟鍙栨秷鍚庝笉鑳藉啀娆℃縺娲�
+
+### 3. 浠诲姟瀛楁璁捐
+
+#### 閫氱敤瀛楁
+- 浠诲姟缂栧彿銆佷换鍔″垱寤轰汉锛屼换鍔″綊灞炴満鏋�
+- 浠诲姟绫诲瀷銆佷换鍔$姸鎬�
+- 浠诲姟鐩殑鍦板潃銆佷换鍔″嚭鍙戝湴鍧�
+- 璁″垝寮�濮嬫椂闂淬�佽鍒掔粨鏉熸椂闂�
+- 瀹為檯寮�濮嬫椂闂淬�佸疄闄呯粨鏉熸椂闂�
+- 浠诲姟澶囨敞銆侀檮浠跺垪琛�
+
+## 鏁版嵁搴撹璁�
+
+### 1. 鏍稿績琛ㄧ粨鏋�
+
+#### 1.1 浠诲姟涓昏〃 (sys_task)
+```sql
+CREATE TABLE sys_task (
+    task_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '浠诲姟ID',
+    task_code VARCHAR(50) NOT NULL UNIQUE COMMENT '浠诲姟缂栧彿',
+    task_type VARCHAR(20) NOT NULL COMMENT '浠诲姟绫诲瀷锛歁AINTENANCE-缁翠慨淇濆吇锛孎UEL-鍔犳补浠诲姟锛孫THER-鍏朵粬',
+    task_status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '浠诲姟鐘舵�侊細PENDING-寰呭紑濮嬶紝IN_PROGRESS-浠诲姟涓紝COMPLETED-宸插畬鎴愶紝CANCELLED-宸插彇娑�',    
+    task_description varchar(1000) COMMENT '浠诲姟鎻忚堪',
+    
+    -- 鍦板潃淇℃伅
+    departure_address VARCHAR(500) COMMENT '鍑哄彂鍦板潃',
+    destination_address VARCHAR(500) COMMENT '鐩殑鍦板潃',
+    
+    -- 鏃堕棿淇℃伅
+    planned_start_time DATETIME COMMENT '璁″垝寮�濮嬫椂闂�',
+    planned_end_time DATETIME COMMENT '璁″垝缁撴潫鏃堕棿',
+    actual_start_time DATETIME COMMENT '瀹為檯寮�濮嬫椂闂�',
+    actual_end_time DATETIME COMMENT '瀹為檯缁撴潫鏃堕棿',
+    
+    -- 浜哄憳淇℃伅
+    creator_id BIGINT NOT NULL COMMENT '鍒涘缓浜篒D',
+    assignee_id BIGINT COMMENT '鎵ц浜篒D',
+    dept_id BIGINT NOT NULL COMMENT '褰掑睘閮ㄩ棬ID',
+    
+    -- 绯荤粺瀛楁
+    create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+    create_by VARCHAR(64) NOT NULL COMMENT '鍒涘缓鑰�',
+    update_by VARCHAR(64) COMMENT '鏇存柊鑰�',
+    remark VARCHAR(500) COMMENT '澶囨敞',
+    del_flag CHAR(1) DEFAULT '0' COMMENT '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    
+    INDEX idx_task_code (task_code),
+    INDEX idx_task_type (task_type),
+    INDEX idx_task_status (task_status),
+    INDEX idx_creator_id (creator_id),
+    INDEX idx_assignee_id (assignee_id),
+    INDEX idx_dept_id (dept_id),
+    INDEX idx_planned_start_time (planned_start_time),
+    INDEX idx_create_time (create_time)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浠诲姟绠$悊琛�';
+```
+
+#### 1.2 杞﹁締淇℃伅琛� (tb_vehicle_info)
+```sql
+-- 鍩轰簬鐜版湁杞﹁締琛ㄧ粨鏋勶紝娣诲姞鏈烘瀯鍏宠仈瀛楁
+CREATE TABLE tb_vehicle_info (
+    vehicle_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '杞﹁締ID',
+    platform_code VARCHAR(50) NOT NULL COMMENT '骞冲彴鏍囪瘑锛圓/B锛�',
+    vehicle_no VARCHAR(50) NOT NULL COMMENT '杞︾墝鍙�',
+    vehicle_type VARCHAR(50) NOT NULL COMMENT '杞﹁締绫诲瀷锛欰MBULANCE-鏁戞姢杞︼紝TRANSFER-杞繍杞︼紝MAINTENANCE-缁翠慨杞�',
+    vehicle_brand VARCHAR(50) COMMENT '杞﹁締鍝佺墝',
+    vehicle_model VARCHAR(50) COMMENT '杞﹁締鍨嬪彿',
+    vehicle_color VARCHAR(20) COMMENT '杞﹁締棰滆壊',
+    vehicle_status CHAR(1) DEFAULT '0' COMMENT '杞﹁締鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    device_id VARCHAR(50) DEFAULT NULL COMMENT '璁惧ID',
+    
+    -- 鏈烘瀯鍏宠仈锛堟柊澧炲瓧娈碉級
+    dept_id BIGINT(20) DEFAULT NULL COMMENT '褰掑睘鏈烘瀯ID',
+    
+    -- 绯荤粺瀛楁
+    create_by VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+    create_time DATETIME COMMENT '鍒涘缓鏃堕棿',
+    update_by VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+    update_time DATETIME COMMENT '鏇存柊鏃堕棿',
+    remark VARCHAR(500) DEFAULT NULL COMMENT '澶囨敞',
+    
+    PRIMARY KEY (vehicle_id),
+    INDEX idx_vehicle_no (vehicle_no),
+    INDEX idx_vehicle_type (vehicle_type),
+    INDEX idx_vehicle_status (vehicle_status),
+    INDEX idx_dept_id (dept_id),
+    INDEX idx_platform_code (platform_code),
+    
+    FOREIGN KEY (dept_id) REFERENCES sys_dept(dept_id) ON DELETE SET NULL
+) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4 COMMENT='杞﹁締淇℃伅琛�';
+```
+
+#### 1.3 浠诲姟杞﹁締鍏宠仈琛� (sys_task_vehicle)
+```sql
+CREATE TABLE sys_task_vehicle (
+    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '鍏宠仈ID',
+    task_id BIGINT NOT NULL COMMENT '浠诲姟ID',
+    vehicle_id BIGINT NOT NULL COMMENT '杞﹁締ID',
+    assign_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒嗛厤鏃堕棿',
+    assign_by VARCHAR(64) NOT NULL COMMENT '鍒嗛厤浜�',
+    status VARCHAR(20) DEFAULT 'ASSIGNED' COMMENT '鍏宠仈鐘舵�侊細ASSIGNED-宸插垎閰嶏紝ACTIVE-鎵ц涓紝COMPLETED-宸插畬鎴愶紝CANCELLED-宸插彇娑�',
+    remark VARCHAR(500) COMMENT '澶囨敞',
+    
+    INDEX idx_task_id (task_id),
+    INDEX idx_vehicle_id (vehicle_id),
+    INDEX idx_status (status),
+    INDEX idx_assign_time (assign_time),
+    
+    UNIQUE KEY uk_task_vehicle (task_id, vehicle_id),
+    FOREIGN KEY (task_id) REFERENCES sys_task(task_id) ON DELETE CASCADE,
+    FOREIGN KEY (vehicle_id) REFERENCES tb_vehicle_info(vehicle_id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浠诲姟杞﹁締鍏宠仈琛�';
+```
+
+#### 1.4 浠诲姟闄勪欢琛� (sys_task_attachment)
+```sql
+CREATE TABLE sys_task_attachment (
+    attachment_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '闄勪欢ID',
+    task_id BIGINT NOT NULL COMMENT '浠诲姟ID',
+    file_name VARCHAR(255) NOT NULL COMMENT '鏂囦欢鍚�',
+    file_path VARCHAR(500) NOT NULL COMMENT '鏂囦欢璺緞',
+    file_size BIGINT COMMENT '鏂囦欢澶у皬锛堝瓧鑺傦級',
+    file_type VARCHAR(50) COMMENT '鏂囦欢绫诲瀷',
+    upload_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '涓婁紶鏃堕棿',
+    upload_by VARCHAR(64) NOT NULL COMMENT '涓婁紶鑰�',
+    
+    INDEX idx_task_id (task_id),
+    FOREIGN KEY (task_id) REFERENCES sys_task(task_id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浠诲姟闄勪欢琛�';
+```
+
+#### 1.3 浠诲姟鎿嶄綔鏃ュ織琛� (sys_task_log)
+```sql
+CREATE TABLE sys_task_log (
+    log_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '鏃ュ織ID',
+    task_id BIGINT NOT NULL COMMENT '浠诲姟ID',
+    operation_type VARCHAR(20) NOT NULL COMMENT '鎿嶄綔绫诲瀷锛欳REATE-鍒涘缓锛孶PDATE-鏇存柊锛孉SSIGN-鍒嗛厤锛孲TATUS_CHANGE-鐘舵�佸彉鏇达紝DELETE-鍒犻櫎',
+    operation_desc VARCHAR(500) COMMENT '鎿嶄綔鎻忚堪',
+    old_value TEXT COMMENT '鎿嶄綔鍓嶅��',
+    new_value TEXT COMMENT '鎿嶄綔鍚庡��',
+    operator_id BIGINT NOT NULL COMMENT '鎿嶄綔浜篒D',
+    operator_name VARCHAR(64) NOT NULL COMMENT '鎿嶄綔浜哄鍚�',
+    operation_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鎿嶄綔鏃堕棿',
+    ip_address VARCHAR(128) COMMENT 'IP鍦板潃',
+    
+    INDEX idx_task_id (task_id),
+    INDEX idx_operation_type (operation_type),
+    INDEX idx_operator_id (operator_id),
+    INDEX idx_operation_time (operation_time),
+    FOREIGN KEY (task_id) REFERENCES sys_task(task_id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浠诲姟鎿嶄綔鏃ュ織琛�';
+```
+
+### 2. 鏁版嵁瀛楀吀璁捐
+
+#### 2.1 浠诲姟绫诲瀷瀛楀吀
+```sql
+INSERT INTO sys_dict_type VALUES ('sys_task_type', '浠诲姟绫诲瀷', '0', 'admin', sysdate(), '', null, '浠诲姟绫诲瀷鍒楄〃');
+INSERT INTO sys_dict_data VALUES (1, 1, '缁翠慨淇濆吇', 'MAINTENANCE', 'sys_task_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '缁翠慨淇濆吇浠诲姟');
+INSERT INTO sys_dict_data VALUES (2, 2, '鍔犳补浠诲姟', 'FUEL', 'sys_task_type', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '鍔犳补浠诲姟');
+INSERT INTO sys_dict_data VALUES (3, 3, '鍏朵粬', 'OTHER', 'sys_task_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '鍏朵粬绫诲瀷浠诲姟');
+```
+
+#### 2.2 浠诲姟鐘舵�佸瓧鍏�
+```sql
+INSERT INTO sys_dict_type VALUES ('sys_task_status', '浠诲姟鐘舵��', '0', 'admin', sysdate(), '', null, '浠诲姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_data VALUES (4, 1, '寰呭紑濮�', 'PENDING', 'sys_task_status', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '浠诲姟宸插垱寤猴紝绛夊緟寮�濮�');
+INSERT INTO sys_dict_data VALUES (5, 2, '浠诲姟涓�', 'IN_PROGRESS', 'sys_task_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '浠诲姟宸茬粡寮�濮�');
+INSERT INTO sys_dict_data VALUES (6, 3, '宸插畬鎴�', 'COMPLETED', 'sys_task_status', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '浠诲姟宸插畬鎴�');
+INSERT INTO sys_dict_data VALUES (7, 4, '宸插彇娑�', 'CANCELLED', 'sys_task_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '浠诲姟宸插彇娑�');
+```
+
+#### 2.3 杞﹁締绫诲瀷瀛楀吀
+```sql
+INSERT INTO sys_dict_type VALUES ('sys_vehicle_type', '杞﹁締绫诲瀷', '0', 'admin', sysdate(), '', null, '杞﹁締绫诲瀷鍒楄〃');
+INSERT INTO sys_dict_data VALUES (8, 1, '鏁戞姢杞�', 'AMBULANCE', 'sys_vehicle_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '鏁戞姢杞�');
+INSERT INTO sys_dict_data VALUES (9, 2, '杞繍杞�', 'TRANSFER', 'sys_vehicle_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '杞繍杞�');
+INSERT INTO sys_dict_data VALUES (10, 3, '缁翠慨杞�', 'MAINTENANCE', 'sys_vehicle_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '缁翠慨杞�');
+```
+
+#### 2.4 杞﹁締鐘舵�佸瓧鍏�
+```sql
+INSERT INTO sys_dict_type VALUES ('sys_vehicle_status', '杞﹁締鐘舵��', '0', 'admin', sysdate(), '', null, '杞﹁締鐘舵�佸垪琛�');
+INSERT INTO sys_dict_data VALUES (11, 1, '姝e父', '0', 'sys_vehicle_status', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締姝e父浣跨敤');
+INSERT INTO sys_dict_data VALUES (12, 2, '鍋滅敤', '1', 'sys_vehicle_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締鍋滅敤');
+```
+
+#### 2.5 浠诲姟杞﹁締鍏宠仈鐘舵�佸瓧鍏�
+```sql
+INSERT INTO sys_dict_type VALUES ('sys_task_vehicle_status', '浠诲姟杞﹁締鍏宠仈鐘舵��', '0', 'admin', sysdate(), '', null, '浠诲姟杞﹁締鍏宠仈鐘舵�佸垪琛�');
+INSERT INTO sys_dict_data VALUES (15, 1, '宸插垎閰�', 'ASSIGNED', 'sys_task_vehicle_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締宸插垎閰嶇粰浠诲姟');
+INSERT INTO sys_dict_data VALUES (16, 2, '鎵ц涓�', 'ACTIVE', 'sys_task_vehicle_status', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締姝e湪鎵ц浠诲姟');
+INSERT INTO sys_dict_data VALUES (17, 3, '宸插畬鎴�', 'COMPLETED', 'sys_task_vehicle_status', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締浠诲姟宸插畬鎴�');
+INSERT INTO sys_dict_data VALUES (18, 4, '宸插彇娑�', 'CANCELLED', 'sys_task_vehicle_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締浠诲姟宸插彇娑�');
+```
+
+## 鎺ュ彛璁捐
+
+### 1. REST API 瑙勮寖
+
+#### 1.1 浠诲姟绠$悊鎺ュ彛
+
+##### 1.1.1 鍒涘缓浠诲姟
+```
+POST /api/task
+Content-Type: application/json
+
+Request Body:
+{
+    "taskType": "MAINTENANCE",
+    "taskTitle": "杞﹁締缁翠慨淇濆吇",
+    "taskDescription": "瀹氭湡淇濆吇妫�鏌�",
+    "departureAddress": "鍖椾含甯傛湞闃冲尯",
+    "destinationAddress": "鍖椾含甯傛捣娣�鍖虹淮淇巶",
+    "plannedStartTime": "2024-01-15 09:00:00",
+    "plannedEndTime": "2024-01-15 17:00:00",
+    "assigneeId": 100,
+    "remark": "绱ф�ョ淮淇�"
+}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛",
+    "data": {
+        "taskId": 1,
+        "taskCode": "TASK202401150001"
+    }
+}
+```
+
+##### 1.1.2 鏌ヨ浠诲姟鍒楄〃
+```
+GET /api/task/list?pageNum=1&pageSize=10&taskType=MAINTENANCE&taskStatus=PENDING
+
+Response:
+{
+    "code": 200,
+    "msg": "鏌ヨ鎴愬姛",
+    "rows": [
+        {
+            "taskId": 1,
+            "taskCode": "TASK202401150001",
+            "taskType": "MAINTENANCE",
+            "taskStatus": "PENDING",
+            "taskTitle": "杞﹁締缁翠慨淇濆吇",
+            "departureAddress": "鍖椾含甯傛湞闃冲尯",
+            "destinationAddress": "鍖椾含甯傛捣娣�鍖虹淮淇巶",
+            "plannedStartTime": "2024-01-15 09:00:00",
+            "plannedEndTime": "2024-01-15 17:00:00",
+            "creatorName": "寮犱笁",
+            "assigneeName": "鏉庡洓",
+            "createTime": "2024-01-15 08:30:00"
+        }
+    ],
+    "total": 1
+}
+```
+
+##### 1.1.3 鑾峰彇浠诲姟璇︽儏
+```
+GET /api/task/{taskId}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛",
+    "data": {
+        "taskId": 1,
+        "taskCode": "TASK202401150001",
+        "taskType": "MAINTENANCE",
+        "taskStatus": "PENDING",
+        "taskTitle": "杞﹁締缁翠慨淇濆吇",
+        "taskDescription": "瀹氭湡淇濆吇妫�鏌�",
+        "departureAddress": "鍖椾含甯傛湞闃冲尯",
+        "destinationAddress": "鍖椾含甯傛捣娣�鍖虹淮淇巶",
+        "plannedStartTime": "2024-01-15 09:00:00",
+        "plannedEndTime": "2024-01-15 17:00:00",
+        "actualStartTime": null,
+        "actualEndTime": null,
+        "creatorName": "寮犱笁",
+        "assigneeName": "鏉庡洓",
+        "remark": "绱ф�ョ淮淇�",
+        "attachments": [],
+        "operationLogs": [],
+        "assignedVehicles": [
+            {
+                "id": 1,
+                "vehicleId": 1,
+                "vehicleNo": "浜珹12345",
+                "vehicleType": "AMBULANCE",
+                "assignTime": "2024-01-15 09:00:00",
+                "assignBy": "寮犱笁",
+                "status": "ASSIGNED",
+                "remark": "鍒嗛厤鏁戞姢杞︽墽琛屼换鍔�"
+            }
+        ]
+    }
+}
+```
+
+##### 1.1.4 鏇存柊浠诲姟
+```
+PUT /api/task/{taskId}
+Content-Type: application/json
+
+Request Body:
+{
+    "taskTitle": "杞﹁締缁翠慨淇濆吇锛堟洿鏂帮級",
+    "taskDescription": "瀹氭湡淇濆吇妫�鏌ワ紝澧炲姞瀹夊叏妫�鏌�",
+    "plannedStartTime": "2024-01-15 10:00:00",
+    "assigneeId": 101,
+    "remark": "鏇存柊鍚庣殑澶囨敞"
+}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+##### 1.1.5 鏇存柊浠诲姟鐘舵��
+```
+PUT /api/task/{taskId}/status
+Content-Type: application/json
+
+Request Body:
+{
+    "taskStatus": "IN_PROGRESS",
+    "actualStartTime": "2024-01-15 10:15:00",
+    "remark": "浠诲姟寮�濮嬫墽琛�"
+}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+##### 1.1.6 鍒嗛厤浠诲姟
+```
+PUT /api/task/{taskId}/assign
+Content-Type: application/json
+
+Request Body:
+{
+    "assigneeId": 102,
+    "remark": "閲嶆柊鍒嗛厤缁欑帇浜�"
+}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+##### 1.1.7 鍒犻櫎浠诲姟
+```
+DELETE /api/task/{taskIds}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+#### 1.2 浠诲姟闄勪欢鎺ュ彛
+
+##### 1.2.1 涓婁紶闄勪欢
+```
+POST /api/task/{taskId}/attachment
+Content-Type: multipart/form-data
+
+Request Body:
+- file: 鏂囦欢鍐呭
+
+Response:
+{
+    "code": 200,
+    "msg": "涓婁紶鎴愬姛",
+    "data": {
+        "attachmentId": 1,
+        "fileName": "缁翠慨鎶ュ憡.pdf",
+        "filePath": "/uploads/task/2024/01/15/xxx.pdf"
+    }
+}
+```
+
+##### 1.2.2 鍒犻櫎闄勪欢
+```
+DELETE /api/task/attachment/{attachmentId}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+#### 1.3 杞﹁締绠$悊鎺ュ彛
+
+##### 1.3.1 鏌ヨ杞﹁締鍒楄〃
+```
+GET /api/vehicle/list?pageNum=1&pageSize=10&vehicleType=AMBULANCE&vehicleStatus=ACTIVE&deptId=100
+
+Response:
+{
+    "code": 200,
+    "msg": "鏌ヨ鎴愬姛",
+    "rows": [
+        {
+            "vehicleId": 1,
+            "platformCode": "A",
+            "vehicleNo": "浜珹12345",
+            "vehicleType": "AMBULANCE",
+            "vehicleBrand": "濂旈┌",
+            "vehicleModel": "Sprinter",
+            "vehicleStatus": "0",
+            "deviceId": "DEV001",
+            "deptId": 100,
+            "deptName": "鍖椾含鎬ユ晳涓績",
+            "createTime": "2024-01-15 08:30:00"
+        }
+    ],
+    "total": 1
+}
+```
+
+##### 1.3.2 鑾峰彇杞﹁締璇︽儏
+```
+GET /api/vehicle/{vehicleId}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛",
+    "data": {
+        "vehicleId": 1,
+        "platformCode": "A",
+        "vehicleNo": "浜珹12345",
+        "vehicleType": "AMBULANCE",
+        "vehicleBrand": "濂旈┌",
+        "vehicleModel": "Sprinter",
+        "vehicleColor": "鐧借壊",
+        "vehicleStatus": "0",
+        "deviceId": "DEV001",
+        "deptId": 100,
+        "deptName": "鍖椾含鎬ユ晳涓績",
+        "createBy": "admin",
+        "createTime": "2024-01-15 08:30:00",
+        "updateBy": "admin",
+        "updateTime": "2024-01-15 10:30:00",
+        "remark": "杞﹁締鐘舵�佽壇濂�"
+    }
+}
+```
+
+##### 1.3.3 鍒嗛厤杞﹁締缁欎换鍔�
+```
+POST /api/task/{taskId}/assign-vehicle
+Content-Type: application/json
+
+Request Body:
+{
+    "vehicleId": 1,
+    "remark": "鍒嗛厤鏁戞姢杞︽墽琛屼换鍔�"
+}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+##### 1.3.4 鎵归噺鍒嗛厤杞﹁締缁欎换鍔�
+```
+POST /api/task/{taskId}/assign-vehicles
+Content-Type: application/json
+
+Request Body:
+{
+    "vehicleIds": [1, 2, 3],
+    "remark": "鍒嗛厤澶氳締杞︽墽琛屼换鍔�"
+}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛",
+    "data": {
+        "successCount": 3,
+        "failedCount": 0,
+        "details": [
+            {
+                "vehicleId": 1,
+                "vehicleNo": "浜珹12345",
+                "status": "success",
+                "message": "鍒嗛厤鎴愬姛"
+            },
+            {
+                "vehicleId": 2,
+                "vehicleNo": "浜珹12346",
+                "status": "success",
+                "message": "鍒嗛厤鎴愬姛"
+            },
+            {
+                "vehicleId": 3,
+                "vehicleNo": "浜珹12347",
+                "status": "success",
+                "message": "鍒嗛厤鎴愬姛"
+            }
+        ]
+    }
+}
+```
+
+##### 1.3.5 鍙栨秷浠诲姟杞﹁締鍒嗛厤
+```
+DELETE /api/task/{taskId}/vehicle/{vehicleId}
+
+Response:
+{
+    "code": 200,
+    "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+##### 1.3.6 鏌ヨ浠诲姟鍏宠仈鐨勮溅杈�
+```
+GET /api/task/{taskId}/vehicles
+
+Response:
+{
+    "code": 200,
+    "msg": "鏌ヨ鎴愬姛",
+    "data": [
+        {
+            "id": 1,
+            "taskId": 1,
+            "vehicleId": 1,
+            "vehicleNo": "浜珹12345",
+            "vehicleType": "AMBULANCE",
+            "assignTime": "2024-01-15 09:00:00",
+            "assignBy": "寮犱笁",
+            "status": "ASSIGNED",
+            "remark": "鍒嗛厤鏁戞姢杞︽墽琛屼换鍔�"
+        }
+    ]
+}
+```
+
+##### 1.3.7 鏌ヨ鍙敤杞﹁締
+```
+GET /api/vehicle/available?deptId=100&taskType=MAINTENANCE
+
+Response:
+{
+    "code": 200,
+    "msg": "鏌ヨ鎴愬姛",
+    "data": [
+        {
+            "vehicleId": 1,
+            "vehicleNo": "浜珹12345",
+            "vehicleType": "AMBULANCE",
+            "vehicleBrand": "濂旈┌",
+            "vehicleModel": "Sprinter",
+            "vehicleStatus": "0",
+            "deptName": "鍖椾含鎬ユ晳涓績",
+            "currentLocation": "鍖椾含甯傛湞闃冲尯"
+        },
+        {
+            "vehicleId": 2,
+            "vehicleNo": "浜珹12346",
+            "vehicleType": "AMBULANCE",
+            "vehicleBrand": "濂旈┌",
+            "vehicleModel": "Sprinter",
+            "vehicleStatus": "0",
+            "deptName": "鍖椾含鎬ユ晳涓績",
+            "currentLocation": "鍖椾含甯傛捣娣�鍖�"
+        }
+    ]
+}
+```
+
+#### 1.4 浠诲姟缁熻鎺ュ彛
+
+##### 1.4.1 浠诲姟缁熻姒傝
+```
+GET /api/task/statistics
+
+Response:
+{
+    "code": 200,
+    "msg": "鏌ヨ鎴愬姛",
+    "data": {
+        "totalTasks": 100,
+        "pendingTasks": 20,
+        "inProgressTasks": 30,
+        "completedTasks": 45,
+        "cancelledTasks": 5,
+        "todayTasks": 8,
+        "overdueTasks": 3,
+        "vehicleUtilization": 85.5
+    }
+}
+```
+
+## 绋嬪簭璁捐
+
+### 1. 鍚庣鏋舵瀯璁捐
+
+#### 1.1 妯″潡缁撴瀯
+```
+ruoyi-task/
+鈹溾攢鈹� src/main/java/com/ruoyi/task/
+鈹�   鈹溾攢鈹� controller/          # 鎺у埗鍣ㄥ眰
+鈹�   鈹�   鈹溾攢鈹� TaskController.java
+鈹�   鈹�   鈹溾攢鈹� TaskAttachmentController.java
+鈹�   鈹�   鈹溾攢鈹� VehicleController.java
+鈹�   鈹�   鈹斺攢鈹� TaskVehicleController.java
+鈹�   鈹溾攢鈹� service/            # 鏈嶅姟灞�
+鈹�   鈹�   鈹溾攢鈹� ITaskService.java
+鈹�   鈹�   鈹溾攢鈹� impl/TaskServiceImpl.java
+鈹�   鈹�   鈹溾攢鈹� ITaskAttachmentService.java
+鈹�   鈹�   鈹溾攢鈹� impl/TaskAttachmentServiceImpl.java
+鈹�   鈹�   鈹溾攢鈹� IVehicleService.java
+鈹�   鈹�   鈹溾攢鈹� impl/VehicleServiceImpl.java
+鈹�   鈹�   鈹溾攢鈹� ITaskVehicleService.java
+鈹�   鈹�   鈹斺攢鈹� impl/TaskVehicleServiceImpl.java
+鈹�   鈹溾攢鈹� domain/             # 棰嗗煙灞�
+鈹�   鈹�   鈹溾攢鈹� Task.java
+鈹�   鈹�   鈹溾攢鈹� TaskAttachment.java
+鈹�   鈹�   鈹溾攢鈹� TaskLog.java
+鈹�   鈹�   鈹溾攢鈹� Vehicle.java
+鈹�   鈹�   鈹溾攢鈹� TaskVehicle.java
+鈹�   鈹�   鈹溾攢鈹� enums/
+鈹�   鈹�   鈹�   鈹溾攢鈹� TaskType.java
+鈹�   鈹�   鈹�   鈹溾攢鈹� TaskStatus.java
+鈹�   鈹�   鈹�   鈹溾攢鈹� VehicleType.java
+鈹�   鈹�   鈹�   鈹溾攢鈹� VehicleStatus.java
+鈹�   鈹�   鈹�   鈹斺攢鈹� TaskVehicleStatus.java
+鈹�   鈹�   鈹斺攢鈹� vo/
+鈹�   鈹�       鈹溾攢鈹� TaskQueryVO.java
+鈹�   鈹�       鈹溾攢鈹� TaskCreateVO.java
+鈹�   鈹�       鈹溾攢鈹� TaskUpdateVO.java
+鈹�   鈹�       鈹溾攢鈹� VehicleQueryVO.java
+鈹�   鈹�       鈹溾攢鈹� VehicleCreateVO.java
+鈹�   鈹�       鈹斺攢鈹� TaskVehicleAssignVO.java
+鈹�   鈹溾攢鈹� mapper/             # 鏁版嵁璁块棶灞�
+鈹�   鈹�   鈹溾攢鈹� TaskMapper.java
+鈹�   鈹�   鈹溾攢鈹� TaskAttachmentMapper.java
+鈹�   鈹�   鈹溾攢鈹� TaskLogMapper.java
+鈹�   鈹�   鈹溾攢鈹� VehicleMapper.java
+鈹�   鈹�   鈹斺攢鈹� TaskVehicleMapper.java
+鈹�   鈹溾攢鈹� config/             # 閰嶇疆绫�
+鈹�   鈹�   鈹斺攢鈹� TaskConfig.java
+鈹�   鈹斺攢鈹� utils/              # 宸ュ叿绫�
+鈹�       鈹溾攢鈹� TaskCodeGenerator.java
+鈹�       鈹溾攢鈹� TaskStatusValidator.java
+鈹�       鈹斺攢鈹� VehicleCodeGenerator.java
+鈹斺攢鈹� src/main/resources/
+    鈹斺攢鈹� mapper/
+        鈹溾攢鈹� TaskMapper.xml
+        鈹溾攢鈹� TaskAttachmentMapper.xml
+        鈹溾攢鈹� TaskLogMapper.xml
+        鈹溾攢鈹� VehicleMapper.xml
+        鈹斺攢鈹� TaskVehicleMapper.xml
+```
+
+#### 1.2 鏍稿績绫昏璁�
+
+##### 1.2.1 浠诲姟瀹炰綋绫� (Task.java)
+```java
+/**
+ * 浠诲姟瀹炰綋绫�
+ * 鍖呭惈浠诲姟鐨勬墍鏈夊睘鎬у拰涓氬姟鏂规硶
+ */
+public class Task extends BaseEntity {
+    private Long taskId;
+    private String taskCode;
+    private TaskType taskType;
+    private TaskStatus taskStatus;
+    private String taskTitle;
+    private String taskDescription;
+    private String departureAddress;
+    private String destinationAddress;
+    private Date plannedStartTime;
+    private Date plannedEndTime;
+    private Date actualStartTime;
+    private Date actualEndTime;
+    private Long creatorId;
+    private Long assigneeId;
+    private Long deptId;
+    
+    // 鍏宠仈杞﹁締鍒楄〃锛堥�氳繃涓棿琛ㄦ煡璇級
+    private List<TaskVehicle> assignedVehicles;
+    
+    // 涓氬姟鏂规硶
+    public boolean canChangeStatus(TaskStatus newStatus);
+    public boolean isOverdue();
+    public long getDuration();
+    public void start();
+    public void complete();
+    public void cancel();
+    public List<Vehicle> getAssignedVehicles();
+    public boolean hasVehicle(Long vehicleId);
+}
+```
+
+##### 1.2.2 浠诲姟鏈嶅姟鎺ュ彛 (ITaskService.java)
+```java
+/**
+ * 浠诲姟鏈嶅姟鎺ュ彛
+ * 瀹氫箟浠诲姟鐩稿叧鐨勪笟鍔℃搷浣�
+ */
+public interface ITaskService {
+    // 鍩虹CRUD鎿嶄綔
+    List<Task> selectTaskList(TaskQueryVO queryVO);
+    Task selectTaskById(Long taskId);
+    int insertTask(TaskCreateVO createVO);
+    int updateTask(TaskUpdateVO updateVO);
+    int deleteTaskByIds(Long[] taskIds);
+    
+    // 涓氬姟鎿嶄綔
+    int assignTask(Long taskId, Long assigneeId, String remark);
+    int changeTaskStatus(Long taskId, TaskStatus newStatus, String remark);
+    int uploadAttachment(Long taskId, MultipartFile file);
+    int deleteAttachment(Long attachmentId);
+    
+    // 杞﹁締绠$悊鎿嶄綔
+    int assignVehicleToTask(Long taskId, Long vehicleId, String remark);
+    int unassignVehicleFromTask(Long taskId, Long vehicleId);
+    int assignMultipleVehiclesToTask(Long taskId, List<Long> vehicleIds, String remark);
+    List<TaskVehicle> getTaskVehicles(Long taskId);
+    List<Vehicle> getAvailableVehicles(Long deptId, String taskType);
+    
+    // 缁熻鏌ヨ
+    TaskStatisticsVO getTaskStatistics();
+    List<Task> selectOverdueTasks();
+    List<Task> selectMyTasks(Long userId);
+}
+```
+
+#### 1.3 涓氬姟瑙勫垯璁捐
+
+##### 1.3.1 浠诲姟鐘舵�佹祦杞鍒�
+```java
+/**
+ * 浠诲姟鐘舵�佹祦杞獙璇佸櫒
+ */
+@Component
+public class TaskStatusValidator {
+    
+    private static final Map<TaskStatus, Set<TaskStatus>> ALLOWED_TRANSITIONS = new HashMap<>();
+    
+    static {
+        // PENDING -> IN_PROGRESS, CANCELLED
+        ALLOWED_TRANSITIONS.put(PENDING, Set.of(IN_PROGRESS, CANCELLED));
+        // IN_PROGRESS -> COMPLETED, CANCELLED, PENDING
+        ALLOWED_TRANSITIONS.put(IN_PROGRESS, Set.of(COMPLETED, CANCELLED, PENDING));
+        // COMPLETED -> 涓嶅厑璁镐换浣曠姸鎬佸彉鏇�
+        ALLOWED_TRANSITIONS.put(COMPLETED, Set.of());
+        // CANCELLED -> 涓嶅厑璁镐换浣曠姸鎬佸彉鏇�
+        ALLOWED_TRANSITIONS.put(CANCELLED, Set.of());
+    }
+    
+    public boolean canTransition(TaskStatus from, TaskStatus to) {
+        return ALLOWED_TRANSITIONS.get(from).contains(to);
+    }
+}
+```
+
+##### 1.3.2 浠诲姟缂栧彿鐢熸垚瑙勫垯
+```java
+/**
+ * 浠诲姟缂栧彿鐢熸垚鍣�
+ * 鏍煎紡锛歍ASK + YYYYMMDD + 4浣嶅簭鍙�
+ */
+@Component
+public class TaskCodeGenerator {
+    
+    public String generateTaskCode() {
+        String dateStr = DateUtils.formatDate(new Date(), "yyyyMMdd");
+        String sequence = getNextSequence(dateStr);
+        return "TASK" + dateStr + sequence;
+    }
+    
+    private String getNextSequence(String dateStr) {
+        // 鏌ヨ褰撴棩鏈�澶у簭鍙峰苟閫掑
+        // 瀹炵幇閫昏緫...
+    }
+}
+```
+
+### 2. 鍓嶇鏋舵瀯璁捐
+
+#### 2.1 椤甸潰缁勪欢缁撴瀯
+```
+src/views/task/
+鈹溾攢鈹� index.vue              # 浠诲姟鍒楄〃椤甸潰
+鈹溾攢鈹� detail.vue             # 浠诲姟璇︽儏椤甸潰
+鈹溾攢鈹� create.vue             # 鍒涘缓浠诲姟椤甸潰
+鈹溾攢鈹� edit.vue               # 缂栬緫浠诲姟椤甸潰
+鈹斺攢鈹� components/
+    鈹溾攢鈹� TaskList.vue       # 浠诲姟鍒楄〃缁勪欢
+    鈹溾攢鈹� TaskForm.vue       # 浠诲姟琛ㄥ崟缁勪欢
+    鈹溾攢鈹� TaskStatus.vue     # 浠诲姟鐘舵�佺粍浠�
+    鈹溾攢鈹� TaskAttachment.vue # 浠诲姟闄勪欢缁勪欢
+    鈹斺攢鈹� TaskLog.vue        # 浠诲姟鏃ュ織缁勪欢
+```
+
+#### 2.2 API鏈嶅姟璁捐
+```javascript
+// src/api/task.js
+import request from '@/utils/request'
+
+// 浠诲姟绠$悊API
+export function listTask(query) {
+  return request({
+    url: '/api/task/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getTask(taskId) {
+  return request({
+    url: '/api/task/' + taskId,
+    method: 'get'
+  })
+}
+
+export function addTask(data) {
+  return request({
+    url: '/api/task',
+    method: 'post',
+    data: data
+  })
+}
+
+export function updateTask(data) {
+  return request({
+    url: '/api/task/' + data.taskId,
+    method: 'put',
+    data: data
+  })
+}
+
+export function deleteTask(taskIds) {
+  return request({
+    url: '/api/task/' + taskIds,
+    method: 'delete'
+  })
+}
+
+export function assignTask(taskId, data) {
+  return request({
+    url: '/api/task/' + taskId + '/assign',
+    method: 'put',
+    data: data
+  })
+}
+
+export function changeTaskStatus(taskId, data) {
+  return request({
+    url: '/api/task/' + taskId + '/status',
+    method: 'put',
+    data: data
+  })
+}
+
+// 闄勪欢绠$悊API
+export function uploadAttachment(taskId, file) {
+  const formData = new FormData()
+  formData.append('file', file)
+  return request({
+    url: '/api/task/' + taskId + '/attachment',
+    method: 'post',
+    data: formData,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  })
+}
+
+export function deleteAttachment(attachmentId) {
+  return request({
+    url: '/api/task/attachment/' + attachmentId,
+    method: 'delete'
+  })
+}
+
+// 缁熻API
+export function getTaskStatistics() {
+  return request({
+    url: '/api/task/statistics',
+    method: 'get'
+  })
+}
+
+// 杞﹁締绠$悊API
+export function listVehicleByDept(deptId, query) {
+  return request({
+    url: '/api/vehicle/list-by-dept/' + deptId,
+    method: 'get',
+    params: query
+  })
+}
+
+export function listAvailableVehicles(deptId, taskType) {
+  return request({
+    url: '/api/vehicle/available',
+    method: 'get',
+    params: { deptId, taskType }
+  })
+}
+
+export function assignVehiclesToTask(taskId, vehicleIds, remark) {
+  return request({
+    url: '/api/task/' + taskId + '/assign-vehicles',
+    method: 'post',
+    data: { vehicleIds, remark }
+  })
+}
+
+export function getTaskVehicleUsage(taskId) {
+  return request({
+    url: '/api/task/' + taskId + '/vehicle-usage',
+    method: 'get'
+  })
+}
+```
+
+### 3. 鏉冮檺鎺у埗璁捐
+
+#### 3.1 鑿滃崟鏉冮檺閰嶇疆
+```sql
+-- 浠诲姟绠$悊鑿滃崟
+INSERT INTO sys_menu VALUES (2000, '浠诲姟绠$悊', 0, 5, 'task', null, '', 1, 0, 'M', '0', '0', '', 'task', 'admin', sysdate(), '', null, '浠诲姟绠$悊鐩綍');
+
+-- 閫氱敤浠诲姟鑿滃崟
+INSERT INTO sys_menu VALUES (2001, '閫氱敤浠诲姟', 2000, 1, 'general', 'task/general/index', '', 1, 0, 'C', '0', '0', 'task:general:view', 'list', 'admin', sysdate(), '', null, '閫氱敤浠诲姟鑿滃崟');
+
+-- 浠诲姟绠$悊鎸夐挳鏉冮檺
+INSERT INTO sys_menu VALUES (2002, '浠诲姟鏌ヨ', 2001, 1, '', '', '', 1, 0, 'F', '0', '0', 'task:general:query', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2003, '浠诲姟鏂板', 2001, 2, '', '', '', 1, 0, 'F', '0', '0', 'task:general:add', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2004, '浠诲姟淇敼', 2001, 3, '', '', '', 1, 0, 'F', '0', '0', 'task:general:edit', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2005, '浠诲姟鍒犻櫎', 2001, 4, '', '', '', 1, 0, 'F', '0', '0', 'task:general:remove', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2006, '浠诲姟鍒嗛厤', 2001, 5, '', '', '', 1, 0, 'F', '0', '0', 'task:general:assign', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2007, '鐘舵�佸彉鏇�', 2001, 6, '', '', '', 1, 0, 'F', '0', '0', 'task:general:status', '#', 'admin', sysdate(), '', null, '');
+```
+
+#### 3.2 鏁版嵁鏉冮檺鎺у埗
+```java
+/**
+ * 浠诲姟鏁版嵁鏉冮檺鎺у埗
+ * 鍩轰簬閮ㄩ棬杩涜鏁版嵁闅旂
+ */
+@Aspect
+@Component
+public class TaskDataScopeAspect {
+    
+    @Before("@annotation(dataScope)")
+    public void doBefore(JoinPoint point, DataScope dataScope) {
+        // 鑾峰彇褰撳墠鐢ㄦ埛閮ㄩ棬鏉冮檺
+        // 娣诲姞鏁版嵁鏉冮檺杩囨护鏉′欢
+        // 瀹炵幇閫昏緫...
+    }
+}
+```
+
+### 4. 寮傚父澶勭悊璁捐
+
+#### 4.1 涓氬姟寮傚父瀹氫箟
+```java
+/**
+ * 浠诲姟鐩稿叧涓氬姟寮傚父
+ */
+public class TaskException extends RuntimeException {
+    private String code;
+    private String message;
+    
+    public TaskException(String code, String message) {
+        super(message);
+        this.code = code;
+        this.message = message;
+    }
+}
+
+/**
+ * 浠诲姟寮傚父甯搁噺
+ */
+public class TaskErrorCode {
+    public static final String TASK_NOT_FOUND = "TASK_001";
+    public static final String TASK_STATUS_INVALID = "TASK_002";
+    public static final String TASK_ASSIGNEE_INVALID = "TASK_003";
+    public static final String TASK_PERMISSION_DENIED = "TASK_004";
+}
+```
+
+#### 4.2 鍏ㄥ眬寮傚父澶勭悊
+```java
+/**
+ * 鍏ㄥ眬寮傚父澶勭悊鍣�
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+    
+    @ExceptionHandler(TaskException.class)
+    public AjaxResult handleTaskException(TaskException e) {
+        return AjaxResult.error(e.getCode(), e.getMessage());
+    }
+}
+```
+
+## 閮ㄧ讲鍜岄厤缃�
+
+### 1. 鐜瑕佹眰
+- JDK 1.8+
+- MySQL 5.7+
+- Redis 3.0+
+- Maven 3.6+
+
+### 2. 閰嶇疆鏂囦欢
+```yaml
+# application.yml
+spring:
+  datasource:
+    url: jdbc:mysql://localhost:3306/ry-task?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+    username: root
+    password: password
+    
+  redis:
+    host: localhost
+    port: 6379
+    password: 
+    database: 0
+
+# 浠诲姟鐩稿叧閰嶇疆
+task:
+  # 浠诲姟缂栧彿鍓嶇紑
+  code-prefix: TASK
+  # 闄勪欢涓婁紶璺緞
+  upload-path: /uploads/task/
+  # 鏈�澶ч檮浠跺ぇ灏忥紙MB锛�
+  max-file-size: 10
+  # 鍏佽鐨勬枃浠剁被鍨�
+  allowed-file-types: pdf,doc,docx,jpg,jpeg,png
+```
+
+### 3. 鏁版嵁搴撳垵濮嬪寲
+```sql
+-- 鎵ц鏁版嵁搴撹〃鍒涘缓鑴氭湰
+source sql/task_tables.sql;
+
+-- 鎵ц鏁版嵁瀛楀吀鍒濆鍖栬剼鏈�
+source sql/task_dict_data.sql;
+
+-- 鎵ц鑿滃崟鏉冮檺鍒濆鍖栬剼鏈�
+source sql/task_menu.sql;
+```
+
+## 娴嬭瘯绛栫暐
+
+### 1. 鍗曞厓娴嬭瘯
+- 鏈嶅姟灞備笟鍔¢�昏緫娴嬭瘯
+- 鏁版嵁璁块棶灞傛祴璇�
+- 宸ュ叿绫绘祴璇�
+
+### 2. 闆嗘垚娴嬭瘯
+- API鎺ュ彛娴嬭瘯
+- 鏁版嵁搴撴搷浣滄祴璇�
+- 鏉冮檺鎺у埗娴嬭瘯
+
+### 3. 鎬ц兘娴嬭瘯
+- 骞跺彂鍒涘缓浠诲姟娴嬭瘯
+- 澶ф暟鎹噺鏌ヨ娴嬭瘯
+- 鏂囦欢涓婁紶鎬ц兘娴嬭瘯
+
+## 鐩戞帶鍜屾棩蹇�
+
+### 1. 涓氬姟鐩戞帶
+- 浠诲姟鍒涘缓鏁伴噺缁熻
+- 浠诲姟瀹屾垚鐜囩粺璁�
+- 浠诲姟瓒呮椂鐜囩粺璁�
+
+### 2. 绯荤粺鐩戞帶
+- API鍝嶅簲鏃堕棿鐩戞帶
+- 鏁版嵁搴撹繛鎺ユ睜鐩戞帶
+- 鏂囦欢瀛樺偍绌洪棿鐩戞帶
+
+### 3. 鏃ュ織璁板綍
+- 鎿嶄綔鏃ュ織璁板綍
+- 寮傚父鏃ュ織璁板綍
+- 鎬ц兘鏃ュ織璁板綍
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java
new file mode 100644
index 0000000..b12fa9e
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskAttachmentController.java
@@ -0,0 +1,84 @@
+package com.ruoyi.web.controller.task;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.system.domain.SysTask;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.SysTaskAttachment;
+import com.ruoyi.system.service.ISysTaskService;
+
+/**
+ * 浠诲姟闄勪欢Controller
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+@RestController
+@RequestMapping("/task/attachment")
+public class SysTaskAttachmentController extends BaseController {
+    
+    @Autowired
+    private ISysTaskService sysTaskService;
+
+    /**
+     * 鏌ヨ浠诲姟闄勪欢鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:query')")
+    @GetMapping("/list/{taskId}")
+    public AjaxResult list(@PathVariable("taskId") Long taskId) {
+        SysTask task = sysTaskService.getTaskDetail(taskId);
+        return success(task.getAttachments());
+    }
+
+    /**
+     * 涓婁紶浠诲姟闄勪欢
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:edit')")
+    @Log(title = "浠诲姟闄勪欢", businessType = BusinessType.INSERT)
+    @PostMapping("/upload/{taskId}")
+    public AjaxResult upload(@PathVariable("taskId") Long taskId, @RequestParam("file") MultipartFile file) {
+        try {
+            int result = sysTaskService.uploadAttachment(taskId, file);
+            if (result > 0) {
+                return success("涓婁紶鎴愬姛");
+            } else {
+                return error("涓婁紶澶辫触");
+            }
+        } catch (Exception e) {
+            return error("涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟闄勪欢
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:edit')")
+    @Log(title = "浠诲姟闄勪欢", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{attachmentId}")
+    public AjaxResult remove(@PathVariable("attachmentId") Long attachmentId) {
+        try {
+            int result = sysTaskService.deleteAttachment(attachmentId);
+            if (result > 0) {
+                return success("鍒犻櫎鎴愬姛");
+            } else {
+                return error("鍒犻櫎澶辫触");
+            }
+        } catch (Exception e) {
+            return error("鍒犻櫎澶辫触锛�" + e.getMessage());
+        }
+    }
+}
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
new file mode 100644
index 0000000..25cb9ec
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java
@@ -0,0 +1,205 @@
+package com.ruoyi.web.controller.task;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.SysTask;
+import com.ruoyi.system.domain.vo.TaskQueryVO;
+import com.ruoyi.system.domain.vo.TaskCreateVO;
+import com.ruoyi.system.domain.vo.TaskUpdateVO;
+import com.ruoyi.system.domain.vo.TaskStatisticsVO;
+import com.ruoyi.system.domain.enums.TaskStatus;
+import com.ruoyi.system.service.ISysTaskService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 浠诲姟绠$悊Controller
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+@RestController
+@RequestMapping("/task")
+public class SysTaskController extends BaseController {
+    
+    @Autowired
+    private ISysTaskService sysTaskService;
+
+    /**
+     * 鏌ヨ浠诲姟绠$悊鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:query')")
+    @GetMapping("/list")
+    public TableDataInfo list(TaskQueryVO queryVO) {
+        startPage();
+        List<SysTask> list = sysTaskService.selectSysTaskList(queryVO);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭浠诲姟绠$悊鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:export')")
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, TaskQueryVO queryVO) {
+        List<SysTask> list = sysTaskService.selectSysTaskList(queryVO);
+        ExcelUtil<SysTask> util = new ExcelUtil<SysTask>(SysTask.class);
+        util.exportExcel(response, list, "浠诲姟绠$悊鏁版嵁");
+    }
+
+    /**
+     * 鑾峰彇浠诲姟绠$悊璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:query')")
+    @GetMapping(value = "/{taskId}")
+    public AjaxResult getInfo(@PathVariable("taskId") Long taskId) {
+        return success(sysTaskService.getTaskDetail(taskId));
+    }
+
+    /**
+     * 鏂板浠诲姟绠$悊
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:add')")
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody TaskCreateVO createVO) {
+        return toAjax(sysTaskService.insertSysTask(createVO));
+    }
+
+    /**
+     * 淇敼浠诲姟绠$悊
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:edit')")
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody TaskUpdateVO updateVO) {
+        return toAjax(sysTaskService.updateSysTask(updateVO));
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟绠$悊
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:remove')")
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{taskIds}")
+    public AjaxResult remove(@PathVariable Long[] taskIds) {
+        return toAjax(sysTaskService.deleteSysTaskByTaskIds(taskIds));
+    }
+
+    /**
+     * 鍒嗛厤浠诲姟
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:assign')")
+    @Log(title = "浠诲姟鍒嗛厤", businessType = BusinessType.UPDATE)
+    @PutMapping("/{taskId}/assign")
+    public AjaxResult assignTask(@PathVariable Long taskId, @RequestBody AssignTaskRequest request) {
+        return toAjax(sysTaskService.assignTask(taskId, request.getAssigneeId(), request.getRemark()));
+    }
+
+    /**
+     * 鏇存柊浠诲姟鐘舵��
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:status')")
+    @Log(title = "浠诲姟鐘舵�佸彉鏇�", businessType = BusinessType.UPDATE)
+    @PutMapping("/{taskId}/status")
+    public AjaxResult changeTaskStatus(@PathVariable Long taskId, @RequestBody ChangeStatusRequest request) {
+        TaskStatus newStatus = TaskStatus.getByCode(request.getTaskStatus());
+        if (newStatus == null) {
+            return error("鏃犳晥鐨勪换鍔$姸鎬�");
+        }
+        return toAjax(sysTaskService.changeTaskStatus(taskId, newStatus, request.getRemark()));
+    }
+
+    /**
+     * 鏌ヨ浠诲姟缁熻淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:query')")
+    @GetMapping("/statistics")
+    public AjaxResult getStatistics() {
+        TaskStatisticsVO statistics = sysTaskService.getTaskStatistics();
+        return success(statistics);
+    }
+
+    /**
+     * 鏌ヨ瓒呮椂浠诲姟鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:query')")
+    @GetMapping("/overdue")
+    public AjaxResult getOverdueTasks() {
+        List<SysTask> list = sysTaskService.selectOverdueTasks();
+        return success(list);
+    }
+
+    /**
+     * 鏌ヨ鎴戠殑浠诲姟鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:query')")
+    @GetMapping("/my")
+    public AjaxResult getMyTasks() {
+        List<SysTask> list = sysTaskService.selectMyTasks(getUserId());
+        return success(list);
+    }
+
+    /**
+     * 鍒嗛厤浠诲姟璇锋眰瀵硅薄
+     */
+    public static class AssignTaskRequest {
+        private Long assigneeId;
+        private String remark;
+
+        public Long getAssigneeId() {
+            return assigneeId;
+        }
+
+        public void setAssigneeId(Long assigneeId) {
+            this.assigneeId = assigneeId;
+        }
+
+        public String getRemark() {
+            return remark;
+        }
+
+        public void setRemark(String remark) {
+            this.remark = remark;
+        }
+    }
+
+    /**
+     * 鍙樻洿鐘舵�佽姹傚璞�
+     */
+    public static class ChangeStatusRequest {
+        private String taskStatus;
+        private String remark;
+
+        public String getTaskStatus() {
+            return taskStatus;
+        }
+
+        public void setTaskStatus(String taskStatus) {
+            this.taskStatus = taskStatus;
+        }
+
+        public String getRemark() {
+            return remark;
+        }
+
+        public void setRemark(String remark) {
+            this.remark = remark;
+        }
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskVehicleController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskVehicleController.java
new file mode 100644
index 0000000..6d70f75
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskVehicleController.java
@@ -0,0 +1,158 @@
+package com.ruoyi.web.controller.task;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.SysTaskVehicle;
+import com.ruoyi.system.service.ISysTaskService;
+
+/**
+ * 浠诲姟杞﹁締鍏宠仈Controller
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+@RestController
+@RequestMapping("/task/vehicle")
+public class SysTaskVehicleController extends BaseController {
+    
+    @Autowired
+    private ISysTaskService sysTaskService;
+
+    /**
+     * 鏌ヨ浠诲姟鍏宠仈鐨勮溅杈嗗垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:query')")
+    @GetMapping("/list/{taskId}")
+    public AjaxResult list(@PathVariable("taskId") Long taskId) {
+        List<SysTaskVehicle> list = sysTaskService.getTaskVehicles(taskId);
+        return success(list);
+    }
+
+    /**
+     * 鏌ヨ鍙敤杞﹁締鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:query')")
+    @GetMapping("/available")
+    public AjaxResult getAvailableVehicles(@RequestParam Long deptId, @RequestParam(required = false) String taskType) {
+        List<SysTaskVehicle> list = sysTaskService.getAvailableVehicles(deptId, taskType);
+        return success(list);
+    }
+
+    /**
+     * 鍒嗛厤杞﹁締缁欎换鍔�
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:assign')")
+    @Log(title = "浠诲姟杞﹁締鍒嗛厤", businessType = BusinessType.INSERT)
+    @PostMapping("/assign/{taskId}")
+    public AjaxResult assignVehicle(@PathVariable("taskId") Long taskId, @RequestBody AssignVehicleRequest request) {
+        try {
+            int result = sysTaskService.assignVehicleToTask(taskId, request.getVehicleId(), request.getRemark());
+            if (result > 0) {
+                return success("鍒嗛厤鎴愬姛");
+            } else {
+                return error("鍒嗛厤澶辫触");
+            }
+        } catch (Exception e) {
+            return error("鍒嗛厤澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鎵归噺鍒嗛厤杞﹁締缁欎换鍔�
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:assign')")
+    @Log(title = "浠诲姟杞﹁締鎵归噺鍒嗛厤", businessType = BusinessType.INSERT)
+    @PostMapping("/assign-batch/{taskId}")
+    public AjaxResult assignVehicles(@PathVariable("taskId") Long taskId, @RequestBody BatchAssignVehicleRequest request) {
+        try {
+            int result = sysTaskService.assignMultipleVehiclesToTask(taskId, request.getVehicleIds(), request.getRemark());
+            if (result > 0) {
+                return success("鎵归噺鍒嗛厤鎴愬姛锛屽叡鍒嗛厤 " + result + " 杈嗚溅");
+            } else {
+                return error("鎵归噺鍒嗛厤澶辫触");
+            }
+        } catch (Exception e) {
+            return error("鎵归噺鍒嗛厤澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鍙栨秷浠诲姟杞﹁締鍒嗛厤
+     */
+    @PreAuthorize("@ss.hasPermi('task:general:assign')")
+    @Log(title = "鍙栨秷浠诲姟杞﹁締鍒嗛厤", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{taskId}/{vehicleId}")
+    public AjaxResult unassignVehicle(@PathVariable("taskId") Long taskId, @PathVariable("vehicleId") Long vehicleId) {
+        try {
+            int result = sysTaskService.unassignVehicleFromTask(taskId, vehicleId);
+            if (result > 0) {
+                return success("鍙栨秷鍒嗛厤鎴愬姛");
+            } else {
+                return error("鍙栨秷鍒嗛厤澶辫触");
+            }
+        } catch (Exception e) {
+            return error("鍙栨秷鍒嗛厤澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鍒嗛厤杞﹁締璇锋眰瀵硅薄
+     */
+    public static class AssignVehicleRequest {
+        private Long vehicleId;
+        private String remark;
+
+        public Long getVehicleId() {
+            return vehicleId;
+        }
+
+        public void setVehicleId(Long vehicleId) {
+            this.vehicleId = vehicleId;
+        }
+
+        public String getRemark() {
+            return remark;
+        }
+
+        public void setRemark(String remark) {
+            this.remark = remark;
+        }
+    }
+
+    /**
+     * 鎵归噺鍒嗛厤杞﹁締璇锋眰瀵硅薄
+     */
+    public static class BatchAssignVehicleRequest {
+        private List<Long> vehicleIds;
+        private String remark;
+
+        public List<Long> getVehicleIds() {
+            return vehicleIds;
+        }
+
+        public void setVehicleIds(List<Long> vehicleIds) {
+            this.vehicleIds = vehicleIds;
+        }
+
+        public String getRemark() {
+            return remark;
+        }
+
+        public void setRemark(String remark) {
+            this.remark = remark;
+        }
+    }
+}
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
new file mode 100644
index 0000000..0286efe
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTask.java
@@ -0,0 +1,369 @@
+package com.ruoyi.system.domain;
+
+import java.util.Date;
+import java.util.List;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.system.domain.enums.TaskStatus;
+import com.ruoyi.system.domain.enums.TaskType;
+
+/**
+ * 浠诲姟绠$悊瀵硅薄 sys_task
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public class SysTask extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 浠诲姟ID */
+    private Long taskId;
+
+    /** 浠诲姟缂栧彿 */
+    @Excel(name = "浠诲姟缂栧彿")
+    private String taskCode;
+
+    /** 浠诲姟绫诲瀷 */
+    @Excel(name = "浠诲姟绫诲瀷", readConverterExp = "MAINTENANCE=缁翠慨淇濆吇,FUEL=鍔犳补浠诲姟,OTHER=鍏朵粬")
+    private String taskType;
+
+    /** 浠诲姟鐘舵�� */
+    @Excel(name = "浠诲姟鐘舵��", readConverterExp = "PENDING=寰呭紑濮�,IN_PROGRESS=浠诲姟涓�,COMPLETED=宸插畬鎴�,CANCELLED=宸插彇娑�")
+    private String taskStatus;
+
+    /** 浠诲姟鎻忚堪 */
+    @Excel(name = "浠诲姟鎻忚堪")
+    private String taskDescription;
+
+    /** 鍑哄彂鍦板潃 */
+    @Excel(name = "鍑哄彂鍦板潃")
+    private String departureAddress;
+
+    /** 鐩殑鍦板潃 */
+    @Excel(name = "鐩殑鍦板潃")
+    private String destinationAddress;
+
+    /** 璁″垝寮�濮嬫椂闂� */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "璁″垝寮�濮嬫椂闂�", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedStartTime;
+
+    /** 璁″垝缁撴潫鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "璁″垝缁撴潫鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedEndTime;
+
+    /** 瀹為檯寮�濮嬫椂闂� */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "瀹為檯寮�濮嬫椂闂�", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date actualStartTime;
+
+    /** 瀹為檯缁撴潫鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "瀹為檯缁撴潫鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date actualEndTime;
+
+    /** 鍒涘缓浜篒D */
+    @Excel(name = "鍒涘缓浜篒D")
+    private Long creatorId;
+
+    /** 鎵ц浜篒D */
+    @Excel(name = "鎵ц浜篒D")
+    private Long assigneeId;
+
+    /** 褰掑睘閮ㄩ棬ID */
+    @Excel(name = "褰掑睘閮ㄩ棬ID")
+    private Long deptId;
+
+    /** 鍒涘缓浜哄鍚� */
+    @Excel(name = "鍒涘缓浜�")
+    private String creatorName;
+
+    /** 鎵ц浜哄鍚� */
+    @Excel(name = "鎵ц浜�")
+    private String assigneeName;
+
+    /** 閮ㄩ棬鍚嶇О */
+    @Excel(name = "閮ㄩ棬鍚嶇О")
+    private String deptName;
+
+    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
+    private String delFlag;
+
+    /** 鍏宠仈杞﹁締鍒楄〃 */
+    private List<SysTaskVehicle> assignedVehicles;
+
+    /** 闄勪欢鍒楄〃 */
+    private List<SysTaskAttachment> attachments;
+
+    /** 鎿嶄綔鏃ュ織鍒楄〃 */
+    private List<SysTaskLog> operationLogs;
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskCode(String taskCode) {
+        this.taskCode = taskCode;
+    }
+
+    public String getTaskCode() {
+        return taskCode;
+    }
+
+    public void setTaskType(String taskType) {
+        this.taskType = taskType;
+    }
+
+    public String getTaskType() {
+        return taskType;
+    }
+
+    public void setTaskStatus(String taskStatus) {
+        this.taskStatus = taskStatus;
+    }
+
+    public String getTaskStatus() {
+        return taskStatus;
+    }
+
+    public void setTaskDescription(String taskDescription) {
+        this.taskDescription = taskDescription;
+    }
+
+    public String getTaskDescription() {
+        return taskDescription;
+    }
+
+    public void setDepartureAddress(String departureAddress) {
+        this.departureAddress = departureAddress;
+    }
+
+    public String getDepartureAddress() {
+        return departureAddress;
+    }
+
+    public void setDestinationAddress(String destinationAddress) {
+        this.destinationAddress = destinationAddress;
+    }
+
+    public String getDestinationAddress() {
+        return destinationAddress;
+    }
+
+    public void setPlannedStartTime(Date plannedStartTime) {
+        this.plannedStartTime = plannedStartTime;
+    }
+
+    public Date getPlannedStartTime() {
+        return plannedStartTime;
+    }
+
+    public void setPlannedEndTime(Date plannedEndTime) {
+        this.plannedEndTime = plannedEndTime;
+    }
+
+    public Date getPlannedEndTime() {
+        return plannedEndTime;
+    }
+
+    public void setActualStartTime(Date actualStartTime) {
+        this.actualStartTime = actualStartTime;
+    }
+
+    public Date getActualStartTime() {
+        return actualStartTime;
+    }
+
+    public void setActualEndTime(Date actualEndTime) {
+        this.actualEndTime = actualEndTime;
+    }
+
+    public Date getActualEndTime() {
+        return actualEndTime;
+    }
+
+    public void setCreatorId(Long creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public Long getCreatorId() {
+        return creatorId;
+    }
+
+    public void setAssigneeId(Long assigneeId) {
+        this.assigneeId = assigneeId;
+    }
+
+    public Long getAssigneeId() {
+        return assigneeId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setCreatorName(String creatorName) {
+        this.creatorName = creatorName;
+    }
+
+    public String getCreatorName() {
+        return creatorName;
+    }
+
+    public void setAssigneeName(String assigneeName) {
+        this.assigneeName = assigneeName;
+    }
+
+    public String getAssigneeName() {
+        return assigneeName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setAssignedVehicles(List<SysTaskVehicle> assignedVehicles) {
+        this.assignedVehicles = assignedVehicles;
+    }
+
+    public List<SysTaskVehicle> getAssignedVehicles() {
+        return assignedVehicles;
+    }
+
+    public void setAttachments(List<SysTaskAttachment> attachments) {
+        this.attachments = attachments;
+    }
+
+    public List<SysTaskAttachment> getAttachments() {
+        return attachments;
+    }
+
+    public void setOperationLogs(List<SysTaskLog> operationLogs) {
+        this.operationLogs = operationLogs;
+    }
+
+    public List<SysTaskLog> getOperationLogs() {
+        return operationLogs;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鍙互鍙樻洿鐘舵��
+     */
+    public boolean canChangeStatus(TaskStatus newStatus) {
+        TaskStatus currentStatus = TaskStatus.getByCode(this.taskStatus);
+        if (currentStatus == null || newStatus == null) {
+            return false;
+        }
+        
+        // 鐘舵�佹祦杞鍒�
+        switch (currentStatus) {
+            case PENDING:
+                return newStatus == TaskStatus.IN_PROGRESS || newStatus == TaskStatus.CANCELLED;
+            case IN_PROGRESS:
+                return newStatus == TaskStatus.COMPLETED || newStatus == TaskStatus.CANCELLED || newStatus == TaskStatus.PENDING;
+            case COMPLETED:
+            case CANCELLED:
+                return false;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁瓒呮椂
+     */
+    public boolean isOverdue() {
+        if (plannedEndTime == null) {
+            return false;
+        }
+        return new Date().after(plannedEndTime) && !TaskStatus.COMPLETED.getCode().equals(taskStatus);
+    }
+
+    /**
+     * 鑾峰彇浠诲姟鎸佺画鏃堕棿锛堝垎閽燂級
+     */
+    public long getDuration() {
+        if (actualStartTime != null && actualEndTime != null) {
+            return (actualEndTime.getTime() - actualStartTime.getTime()) / (1000 * 60);
+        }
+        return 0;
+    }
+
+    /**
+     * 寮�濮嬩换鍔�
+     */
+    public void start() {
+        this.taskStatus = TaskStatus.IN_PROGRESS.getCode();
+        this.actualStartTime = new Date();
+    }
+
+    /**
+     * 瀹屾垚浠诲姟
+     */
+    public void complete() {
+        this.taskStatus = TaskStatus.COMPLETED.getCode();
+        this.actualEndTime = new Date();
+    }
+
+    /**
+     * 鍙栨秷浠诲姟
+     */
+    public void cancel() {
+        this.taskStatus = TaskStatus.CANCELLED.getCode();
+    }
+
+    /**
+     * 妫�鏌ユ槸鍚﹀垎閰嶄簡鎸囧畾杞﹁締
+     */
+    public boolean hasVehicle(Long vehicleId) {
+        if (assignedVehicles == null || vehicleId == null) {
+            return false;
+        }
+        return assignedVehicles.stream().anyMatch(v -> vehicleId.equals(v.getVehicleId()));
+    }
+
+    @Override
+    public String toString() {
+        return "SysTask{" +
+                "taskId=" + taskId +
+                ", taskCode='" + taskCode + '\'' +
+                ", taskType='" + taskType + '\'' +
+                ", taskStatus='" + taskStatus + '\'' +
+                ", taskDescription='" + taskDescription + '\'' +
+                ", departureAddress='" + departureAddress + '\'' +
+                ", destinationAddress='" + destinationAddress + '\'' +
+                ", plannedStartTime=" + plannedStartTime +
+                ", plannedEndTime=" + plannedEndTime +
+                ", actualStartTime=" + actualStartTime +
+                ", actualEndTime=" + actualEndTime +
+                ", creatorId=" + creatorId +
+                ", assigneeId=" + assigneeId +
+                ", deptId=" + deptId +
+                ", creatorName='" + creatorName + '\'' +
+                ", assigneeName='" + assigneeName + '\'' +
+                ", deptName='" + deptName + '\'' +
+                '}';
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java
new file mode 100644
index 0000000..6dd5bff
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskAttachment.java
@@ -0,0 +1,126 @@
+package com.ruoyi.system.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 浠诲姟闄勪欢瀵硅薄 sys_task_attachment
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public class SysTaskAttachment extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 闄勪欢ID */
+    private Long attachmentId;
+
+    /** 浠诲姟ID */
+    @Excel(name = "浠诲姟ID")
+    private Long taskId;
+
+    /** 鏂囦欢鍚� */
+    @Excel(name = "鏂囦欢鍚�")
+    private String fileName;
+
+    /** 鏂囦欢璺緞 */
+    @Excel(name = "鏂囦欢璺緞")
+    private String filePath;
+
+    /** 鏂囦欢澶у皬锛堝瓧鑺傦級 */
+    @Excel(name = "鏂囦欢澶у皬")
+    private Long fileSize;
+
+    /** 鏂囦欢绫诲瀷 */
+    @Excel(name = "鏂囦欢绫诲瀷")
+    private String fileType;
+
+    /** 涓婁紶鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "涓婁紶鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date uploadTime;
+
+    /** 涓婁紶鑰� */
+    @Excel(name = "涓婁紶鑰�")
+    private String uploadBy;
+
+    public void setAttachmentId(Long attachmentId) {
+        this.attachmentId = attachmentId;
+    }
+
+    public Long getAttachmentId() {
+        return attachmentId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFileSize(Long fileSize) {
+        this.fileSize = fileSize;
+    }
+
+    public Long getFileSize() {
+        return fileSize;
+    }
+
+    public void setFileType(String fileType) {
+        this.fileType = fileType;
+    }
+
+    public String getFileType() {
+        return fileType;
+    }
+
+    public void setUploadTime(Date uploadTime) {
+        this.uploadTime = uploadTime;
+    }
+
+    public Date getUploadTime() {
+        return uploadTime;
+    }
+
+    public void setUploadBy(String uploadBy) {
+        this.uploadBy = uploadBy;
+    }
+
+    public String getUploadBy() {
+        return uploadBy;
+    }
+
+    @Override
+    public String toString() {
+        return "SysTaskAttachment{" +
+                "attachmentId=" + attachmentId +
+                ", taskId=" + taskId +
+                ", fileName='" + fileName + '\'' +
+                ", filePath='" + filePath + '\'' +
+                ", fileSize=" + fileSize +
+                ", fileType='" + fileType + '\'' +
+                ", uploadTime=" + uploadTime +
+                ", uploadBy='" + uploadBy + '\'' +
+                '}';
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java
new file mode 100644
index 0000000..36c9638
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskLog.java
@@ -0,0 +1,152 @@
+package com.ruoyi.system.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 浠诲姟鎿嶄綔鏃ュ織瀵硅薄 sys_task_log
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public class SysTaskLog extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 鏃ュ織ID */
+    private Long logId;
+
+    /** 浠诲姟ID */
+    @Excel(name = "浠诲姟ID")
+    private Long taskId;
+
+    /** 鎿嶄綔绫诲瀷 */
+    @Excel(name = "鎿嶄綔绫诲瀷", readConverterExp = "CREATE=鍒涘缓,UPDATE=鏇存柊,ASSIGN=鍒嗛厤,STATUS_CHANGE=鐘舵�佸彉鏇�,DELETE=鍒犻櫎")
+    private String operationType;
+
+    /** 鎿嶄綔鎻忚堪 */
+    @Excel(name = "鎿嶄綔鎻忚堪")
+    private String operationDesc;
+
+    /** 鎿嶄綔鍓嶅�� */
+    @Excel(name = "鎿嶄綔鍓嶅��")
+    private String oldValue;
+
+    /** 鎿嶄綔鍚庡�� */
+    @Excel(name = "鎿嶄綔鍚庡��")
+    private String newValue;
+
+    /** 鎿嶄綔浜篒D */
+    @Excel(name = "鎿嶄綔浜篒D")
+    private Long operatorId;
+
+    /** 鎿嶄綔浜哄鍚� */
+    @Excel(name = "鎿嶄綔浜哄鍚�")
+    private String operatorName;
+
+    /** 鎿嶄綔鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "鎿嶄綔鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date operationTime;
+
+    /** IP鍦板潃 */
+    @Excel(name = "IP鍦板潃")
+    private String ipAddress;
+
+    public void setLogId(Long logId) {
+        this.logId = logId;
+    }
+
+    public Long getLogId() {
+        return logId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setOperationType(String operationType) {
+        this.operationType = operationType;
+    }
+
+    public String getOperationType() {
+        return operationType;
+    }
+
+    public void setOperationDesc(String operationDesc) {
+        this.operationDesc = operationDesc;
+    }
+
+    public String getOperationDesc() {
+        return operationDesc;
+    }
+
+    public void setOldValue(String oldValue) {
+        this.oldValue = oldValue;
+    }
+
+    public String getOldValue() {
+        return oldValue;
+    }
+
+    public void setNewValue(String newValue) {
+        this.newValue = newValue;
+    }
+
+    public String getNewValue() {
+        return newValue;
+    }
+
+    public void setOperatorId(Long operatorId) {
+        this.operatorId = operatorId;
+    }
+
+    public Long getOperatorId() {
+        return operatorId;
+    }
+
+    public void setOperatorName(String operatorName) {
+        this.operatorName = operatorName;
+    }
+
+    public String getOperatorName() {
+        return operatorName;
+    }
+
+    public void setOperationTime(Date operationTime) {
+        this.operationTime = operationTime;
+    }
+
+    public Date getOperationTime() {
+        return operationTime;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    @Override
+    public String toString() {
+        return "SysTaskLog{" +
+                "logId=" + logId +
+                ", taskId=" + taskId +
+                ", operationType='" + operationType + '\'' +
+                ", operationDesc='" + operationDesc + '\'' +
+                ", oldValue='" + oldValue + '\'' +
+                ", newValue='" + newValue + '\'' +
+                ", operatorId=" + operatorId +
+                ", operatorName='" + operatorName + '\'' +
+                ", operationTime=" + operationTime +
+                ", ipAddress='" + ipAddress + '\'' +
+                '}';
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskVehicle.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskVehicle.java
new file mode 100644
index 0000000..6630b8f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskVehicle.java
@@ -0,0 +1,152 @@
+package com.ruoyi.system.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 浠诲姟杞﹁締鍏宠仈瀵硅薄 sys_task_vehicle
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public class SysTaskVehicle extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 鍏宠仈ID */
+    private Long id;
+
+    /** 浠诲姟ID */
+    @Excel(name = "浠诲姟ID")
+    private Long taskId;
+
+    /** 杞﹁締ID */
+    @Excel(name = "杞﹁締ID")
+    private Long vehicleId;
+
+    /** 鍒嗛厤鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "鍒嗛厤鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date assignTime;
+
+    /** 鍒嗛厤浜� */
+    @Excel(name = "鍒嗛厤浜�")
+    private String assignBy;
+
+    /** 鍏宠仈鐘舵�� */
+    @Excel(name = "鍏宠仈鐘舵��", readConverterExp = "ASSIGNED=宸插垎閰�,ACTIVE=鎵ц涓�,COMPLETED=宸插畬鎴�,CANCELLED=宸插彇娑�")
+    private String status;
+
+    /** 杞︾墝鍙� */
+    @Excel(name = "杞︾墝鍙�")
+    private String vehicleNo;
+
+    /** 杞﹁締绫诲瀷 */
+    @Excel(name = "杞﹁締绫诲瀷", readConverterExp = "AMBULANCE=鏁戞姢杞�,TRANSFER=杞繍杞�,MAINTENANCE=缁翠慨杞�")
+    private String vehicleType;
+
+    /** 杞﹁締鍝佺墝 */
+    @Excel(name = "杞﹁締鍝佺墝")
+    private String vehicleBrand;
+
+    /** 杞﹁締鍨嬪彿 */
+    @Excel(name = "杞﹁締鍨嬪彿")
+    private String vehicleModel;
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setVehicleId(Long vehicleId) {
+        this.vehicleId = vehicleId;
+    }
+
+    public Long getVehicleId() {
+        return vehicleId;
+    }
+
+    public void setAssignTime(Date assignTime) {
+        this.assignTime = assignTime;
+    }
+
+    public Date getAssignTime() {
+        return assignTime;
+    }
+
+    public void setAssignBy(String assignBy) {
+        this.assignBy = assignBy;
+    }
+
+    public String getAssignBy() {
+        return assignBy;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setVehicleNo(String vehicleNo) {
+        this.vehicleNo = vehicleNo;
+    }
+
+    public String getVehicleNo() {
+        return vehicleNo;
+    }
+
+    public void setVehicleType(String vehicleType) {
+        this.vehicleType = vehicleType;
+    }
+
+    public String getVehicleType() {
+        return vehicleType;
+    }
+
+    public void setVehicleBrand(String vehicleBrand) {
+        this.vehicleBrand = vehicleBrand;
+    }
+
+    public String getVehicleBrand() {
+        return vehicleBrand;
+    }
+
+    public void setVehicleModel(String vehicleModel) {
+        this.vehicleModel = vehicleModel;
+    }
+
+    public String getVehicleModel() {
+        return vehicleModel;
+    }
+
+    @Override
+    public String toString() {
+        return "SysTaskVehicle{" +
+                "id=" + id +
+                ", taskId=" + taskId +
+                ", vehicleId=" + vehicleId +
+                ", assignTime=" + assignTime +
+                ", assignBy='" + assignBy + '\'' +
+                ", status='" + status + '\'' +
+                ", vehicleNo='" + vehicleNo + '\'' +
+                ", vehicleType='" + vehicleType + '\'' +
+                ", vehicleBrand='" + vehicleBrand + '\'' +
+                ", vehicleModel='" + vehicleModel + '\'' +
+                '}';
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java
new file mode 100644
index 0000000..9deb1dd
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java
@@ -0,0 +1,46 @@
+package com.ruoyi.system.domain.enums;
+
+/**
+ * 浠诲姟鐘舵�佹灇涓�
+ * 
+ * @author ruoyi
+ */
+public enum TaskStatus {
+    
+    /** 寰呭紑濮� */
+    PENDING("PENDING", "寰呭紑濮�"),
+    
+    /** 浠诲姟涓� */
+    IN_PROGRESS("IN_PROGRESS", "浠诲姟涓�"),
+    
+    /** 宸插畬鎴� */
+    COMPLETED("COMPLETED", "宸插畬鎴�"),
+    
+    /** 宸插彇娑� */
+    CANCELLED("CANCELLED", "宸插彇娑�");
+    
+    private final String code;
+    private final String info;
+    
+    TaskStatus(String code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+    
+    public String getCode() {
+        return code;
+    }
+    
+    public String getInfo() {
+        return info;
+    }
+    
+    public static TaskStatus getByCode(String code) {
+        for (TaskStatus status : values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskType.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskType.java
new file mode 100644
index 0000000..1cdb98a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskType.java
@@ -0,0 +1,43 @@
+package com.ruoyi.system.domain.enums;
+
+/**
+ * 浠诲姟绫诲瀷鏋氫妇
+ * 
+ * @author ruoyi
+ */
+public enum TaskType {
+    
+    /** 缁翠慨淇濆吇 */
+    MAINTENANCE("MAINTENANCE", "缁翠慨淇濆吇"),
+    
+    /** 鍔犳补浠诲姟 */
+    FUEL("FUEL", "鍔犳补浠诲姟"),
+    
+    /** 鍏朵粬 */
+    OTHER("OTHER", "鍏朵粬");
+    
+    private final String code;
+    private final String info;
+    
+    TaskType(String code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+    
+    public String getCode() {
+        return code;
+    }
+    
+    public String getInfo() {
+        return info;
+    }
+    
+    public static TaskType getByCode(String code) {
+        for (TaskType type : values()) {
+            if (type.getCode().equals(code)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskVehicleStatus.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskVehicleStatus.java
new file mode 100644
index 0000000..4a6c99e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskVehicleStatus.java
@@ -0,0 +1,46 @@
+package com.ruoyi.system.domain.enums;
+
+/**
+ * 浠诲姟杞﹁締鍏宠仈鐘舵�佹灇涓�
+ * 
+ * @author ruoyi
+ */
+public enum TaskVehicleStatus {
+    
+    /** 宸插垎閰� */
+    ASSIGNED("ASSIGNED", "宸插垎閰�"),
+    
+    /** 鎵ц涓� */
+    ACTIVE("ACTIVE", "鎵ц涓�"),
+    
+    /** 宸插畬鎴� */
+    COMPLETED("COMPLETED", "宸插畬鎴�"),
+    
+    /** 宸插彇娑� */
+    CANCELLED("CANCELLED", "宸插彇娑�");
+    
+    private final String code;
+    private final String info;
+    
+    TaskVehicleStatus(String code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+    
+    public String getCode() {
+        return code;
+    }
+    
+    public String getInfo() {
+        return info;
+    }
+    
+    public static TaskVehicleStatus getByCode(String code) {
+        for (TaskVehicleStatus status : values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/VehicleType.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/VehicleType.java
new file mode 100644
index 0000000..36d8fb9
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/VehicleType.java
@@ -0,0 +1,43 @@
+package com.ruoyi.system.domain.enums;
+
+/**
+ * 杞﹁締绫诲瀷鏋氫妇
+ * 
+ * @author ruoyi
+ */
+public enum VehicleType {
+    
+    /** 鏁戞姢杞� */
+    AMBULANCE("AMBULANCE", "鏁戞姢杞�"),
+    
+    /** 杞繍杞� */
+    TRANSFER("TRANSFER", "杞繍杞�"),
+    
+    /** 缁翠慨杞� */
+    MAINTENANCE("MAINTENANCE", "缁翠慨杞�");
+    
+    private final String code;
+    private final String info;
+    
+    VehicleType(String code, String info) {
+        this.code = code;
+        this.info = info;
+    }
+    
+    public String getCode() {
+        return code;
+    }
+    
+    public String getInfo() {
+        return info;
+    }
+    
+    public static VehicleType getByCode(String code) {
+        for (VehicleType type : values()) {
+            if (type.getCode().equals(code)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
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
new file mode 100644
index 0000000..c1f60e4
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
@@ -0,0 +1,103 @@
+package com.ruoyi.system.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 浠诲姟鍒涘缓瀵硅薄
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public class TaskCreateVO {
+    
+    /** 浠诲姟绫诲瀷 */
+    private String taskType;
+
+    /** 浠诲姟鎻忚堪 */
+    private String taskDescription;
+
+    /** 鍑哄彂鍦板潃 */
+    private String departureAddress;
+
+    /** 鐩殑鍦板潃 */
+    private String destinationAddress;
+
+    /** 璁″垝寮�濮嬫椂闂� */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedStartTime;
+
+    /** 璁″垝缁撴潫鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedEndTime;
+
+    /** 鎵ц浜篒D */
+    private Long assigneeId;
+
+    /** 澶囨敞 */
+    private String remark;
+
+    public String getTaskType() {
+        return taskType;
+    }
+
+    public void setTaskType(String taskType) {
+        this.taskType = taskType;
+    }
+
+    public String getTaskDescription() {
+        return taskDescription;
+    }
+
+    public void setTaskDescription(String taskDescription) {
+        this.taskDescription = taskDescription;
+    }
+
+    public String getDepartureAddress() {
+        return departureAddress;
+    }
+
+    public void setDepartureAddress(String departureAddress) {
+        this.departureAddress = departureAddress;
+    }
+
+    public String getDestinationAddress() {
+        return destinationAddress;
+    }
+
+    public void setDestinationAddress(String destinationAddress) {
+        this.destinationAddress = destinationAddress;
+    }
+
+    public Date getPlannedStartTime() {
+        return plannedStartTime;
+    }
+
+    public void setPlannedStartTime(Date plannedStartTime) {
+        this.plannedStartTime = plannedStartTime;
+    }
+
+    public Date getPlannedEndTime() {
+        return plannedEndTime;
+    }
+
+    public void setPlannedEndTime(Date plannedEndTime) {
+        this.plannedEndTime = plannedEndTime;
+    }
+
+    public Long getAssigneeId() {
+        return assigneeId;
+    }
+
+    public void setAssigneeId(Long assigneeId) {
+        this.assigneeId = assigneeId;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java
new file mode 100644
index 0000000..d300330
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskQueryVO.java
@@ -0,0 +1,140 @@
+package com.ruoyi.system.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 浠诲姟鏌ヨ瀵硅薄 sys_task
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public class TaskQueryVO extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 浠诲姟缂栧彿 */
+    private String taskCode;
+
+    /** 浠诲姟绫诲瀷 */
+    private String taskType;
+
+    /** 浠诲姟鐘舵�� */
+    private String taskStatus;
+
+    /** 鍒涘缓浜篒D */
+    private Long creatorId;
+
+    /** 鎵ц浜篒D */
+    private Long assigneeId;
+
+    /** 褰掑睘閮ㄩ棬ID */
+    private Long deptId;
+
+    /** 璁″垝寮�濮嬫椂闂�-寮�濮� */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedStartTimeBegin;
+
+    /** 璁″垝寮�濮嬫椂闂�-缁撴潫 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedStartTimeEnd;
+
+    /** 璁″垝缁撴潫鏃堕棿-寮�濮� */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedEndTimeBegin;
+
+    /** 璁″垝缁撴潫鏃堕棿-缁撴潫 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedEndTimeEnd;
+
+    /** 鏄惁瓒呮椂 */
+    private Boolean overdue;
+
+    public String getTaskCode() {
+        return taskCode;
+    }
+
+    public void setTaskCode(String taskCode) {
+        this.taskCode = taskCode;
+    }
+
+    public String getTaskType() {
+        return taskType;
+    }
+
+    public void setTaskType(String taskType) {
+        this.taskType = taskType;
+    }
+
+    public String getTaskStatus() {
+        return taskStatus;
+    }
+
+    public void setTaskStatus(String taskStatus) {
+        this.taskStatus = taskStatus;
+    }
+
+    public Long getCreatorId() {
+        return creatorId;
+    }
+
+    public void setCreatorId(Long creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public Long getAssigneeId() {
+        return assigneeId;
+    }
+
+    public void setAssigneeId(Long assigneeId) {
+        this.assigneeId = assigneeId;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Date getPlannedStartTimeBegin() {
+        return plannedStartTimeBegin;
+    }
+
+    public void setPlannedStartTimeBegin(Date plannedStartTimeBegin) {
+        this.plannedStartTimeBegin = plannedStartTimeBegin;
+    }
+
+    public Date getPlannedStartTimeEnd() {
+        return plannedStartTimeEnd;
+    }
+
+    public void setPlannedStartTimeEnd(Date plannedStartTimeEnd) {
+        this.plannedStartTimeEnd = plannedStartTimeEnd;
+    }
+
+    public Date getPlannedEndTimeBegin() {
+        return plannedEndTimeBegin;
+    }
+
+    public void setPlannedEndTimeBegin(Date plannedEndTimeBegin) {
+        this.plannedEndTimeBegin = plannedEndTimeBegin;
+    }
+
+    public Date getPlannedEndTimeEnd() {
+        return plannedEndTimeEnd;
+    }
+
+    public void setPlannedEndTimeEnd(Date plannedEndTimeEnd) {
+        this.plannedEndTimeEnd = plannedEndTimeEnd;
+    }
+
+    public Boolean getOverdue() {
+        return overdue;
+    }
+
+    public void setOverdue(Boolean overdue) {
+        this.overdue = overdue;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskStatisticsVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskStatisticsVO.java
new file mode 100644
index 0000000..25c4f20
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskStatisticsVO.java
@@ -0,0 +1,98 @@
+package com.ruoyi.system.domain.vo;
+
+/**
+ * 浠诲姟缁熻瀵硅薄
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public class TaskStatisticsVO {
+    
+    /** 鎬讳换鍔℃暟 */
+    private Long totalTasks;
+
+    /** 寰呭紑濮嬩换鍔℃暟 */
+    private Long pendingTasks;
+
+    /** 浠诲姟涓暟閲� */
+    private Long inProgressTasks;
+
+    /** 宸插畬鎴愪换鍔℃暟 */
+    private Long completedTasks;
+
+    /** 宸插彇娑堜换鍔℃暟 */
+    private Long cancelledTasks;
+
+    /** 浠婃棩浠诲姟鏁� */
+    private Long todayTasks;
+
+    /** 瓒呮椂浠诲姟鏁� */
+    private Long overdueTasks;
+
+    /** 杞﹁締鍒╃敤鐜� */
+    private Double vehicleUtilization;
+
+    public Long getTotalTasks() {
+        return totalTasks;
+    }
+
+    public void setTotalTasks(Long totalTasks) {
+        this.totalTasks = totalTasks;
+    }
+
+    public Long getPendingTasks() {
+        return pendingTasks;
+    }
+
+    public void setPendingTasks(Long pendingTasks) {
+        this.pendingTasks = pendingTasks;
+    }
+
+    public Long getInProgressTasks() {
+        return inProgressTasks;
+    }
+
+    public void setInProgressTasks(Long inProgressTasks) {
+        this.inProgressTasks = inProgressTasks;
+    }
+
+    public Long getCompletedTasks() {
+        return completedTasks;
+    }
+
+    public void setCompletedTasks(Long completedTasks) {
+        this.completedTasks = completedTasks;
+    }
+
+    public Long getCancelledTasks() {
+        return cancelledTasks;
+    }
+
+    public void setCancelledTasks(Long cancelledTasks) {
+        this.cancelledTasks = cancelledTasks;
+    }
+
+    public Long getTodayTasks() {
+        return todayTasks;
+    }
+
+    public void setTodayTasks(Long todayTasks) {
+        this.todayTasks = todayTasks;
+    }
+
+    public Long getOverdueTasks() {
+        return overdueTasks;
+    }
+
+    public void setOverdueTasks(Long overdueTasks) {
+        this.overdueTasks = overdueTasks;
+    }
+
+    public Double getVehicleUtilization() {
+        return vehicleUtilization;
+    }
+
+    public void setVehicleUtilization(Double vehicleUtilization) {
+        this.vehicleUtilization = vehicleUtilization;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskUpdateVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskUpdateVO.java
new file mode 100644
index 0000000..155b5ed
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskUpdateVO.java
@@ -0,0 +1,103 @@
+package com.ruoyi.system.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 浠诲姟鏇存柊瀵硅薄
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public class TaskUpdateVO {
+    
+    /** 浠诲姟ID */
+    private Long taskId;
+
+    /** 浠诲姟鎻忚堪 */
+    private String taskDescription;
+
+    /** 鍑哄彂鍦板潃 */
+    private String departureAddress;
+
+    /** 鐩殑鍦板潃 */
+    private String destinationAddress;
+
+    /** 璁″垝寮�濮嬫椂闂� */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedStartTime;
+
+    /** 璁″垝缁撴潫鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date plannedEndTime;
+
+    /** 鎵ц浜篒D */
+    private Long assigneeId;
+
+    /** 澶囨敞 */
+    private String remark;
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public String getTaskDescription() {
+        return taskDescription;
+    }
+
+    public void setTaskDescription(String taskDescription) {
+        this.taskDescription = taskDescription;
+    }
+
+    public String getDepartureAddress() {
+        return departureAddress;
+    }
+
+    public void setDepartureAddress(String departureAddress) {
+        this.departureAddress = departureAddress;
+    }
+
+    public String getDestinationAddress() {
+        return destinationAddress;
+    }
+
+    public void setDestinationAddress(String destinationAddress) {
+        this.destinationAddress = destinationAddress;
+    }
+
+    public Date getPlannedStartTime() {
+        return plannedStartTime;
+    }
+
+    public void setPlannedStartTime(Date plannedStartTime) {
+        this.plannedStartTime = plannedStartTime;
+    }
+
+    public Date getPlannedEndTime() {
+        return plannedEndTime;
+    }
+
+    public void setPlannedEndTime(Date plannedEndTime) {
+        this.plannedEndTime = plannedEndTime;
+    }
+
+    public Long getAssigneeId() {
+        return assigneeId;
+    }
+
+    public void setAssigneeId(Long assigneeId) {
+        this.assigneeId = assigneeId;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskAttachmentMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskAttachmentMapper.java
new file mode 100644
index 0000000..69b7200
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskAttachmentMapper.java
@@ -0,0 +1,77 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysTaskAttachment;
+
+/**
+ * 浠诲姟闄勪欢Mapper鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public interface SysTaskAttachmentMapper {
+    
+    /**
+     * 鏌ヨ浠诲姟闄勪欢
+     * 
+     * @param attachmentId 浠诲姟闄勪欢涓婚敭
+     * @return 浠诲姟闄勪欢
+     */
+    public SysTaskAttachment selectSysTaskAttachmentByAttachmentId(Long attachmentId);
+
+    /**
+     * 鏌ヨ浠诲姟闄勪欢鍒楄〃
+     * 
+     * @param sysTaskAttachment 浠诲姟闄勪欢
+     * @return 浠诲姟闄勪欢闆嗗悎
+     */
+    public List<SysTaskAttachment> selectSysTaskAttachmentList(SysTaskAttachment sysTaskAttachment);
+
+    /**
+     * 鏍规嵁浠诲姟ID鏌ヨ闄勪欢鍒楄〃
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 浠诲姟闄勪欢闆嗗悎
+     */
+    public List<SysTaskAttachment> selectSysTaskAttachmentByTaskId(Long taskId);
+
+    /**
+     * 鏂板浠诲姟闄勪欢
+     * 
+     * @param sysTaskAttachment 浠诲姟闄勪欢
+     * @return 缁撴灉
+     */
+    public int insertSysTaskAttachment(SysTaskAttachment sysTaskAttachment);
+
+    /**
+     * 淇敼浠诲姟闄勪欢
+     * 
+     * @param sysTaskAttachment 浠诲姟闄勪欢
+     * @return 缁撴灉
+     */
+    public int updateSysTaskAttachment(SysTaskAttachment sysTaskAttachment);
+
+    /**
+     * 鍒犻櫎浠诲姟闄勪欢
+     * 
+     * @param attachmentId 浠诲姟闄勪欢涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskAttachmentByAttachmentId(Long attachmentId);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟闄勪欢
+     * 
+     * @param attachmentIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskAttachmentByAttachmentIds(Long[] attachmentIds);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍒犻櫎闄勪欢
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskAttachmentByTaskId(Long taskId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskLogMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskLogMapper.java
new file mode 100644
index 0000000..bc90d4e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskLogMapper.java
@@ -0,0 +1,77 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysTaskLog;
+
+/**
+ * 浠诲姟鎿嶄綔鏃ュ織Mapper鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public interface SysTaskLogMapper {
+    
+    /**
+     * 鏌ヨ浠诲姟鎿嶄綔鏃ュ織
+     * 
+     * @param logId 浠诲姟鎿嶄綔鏃ュ織涓婚敭
+     * @return 浠诲姟鎿嶄綔鏃ュ織
+     */
+    public SysTaskLog selectSysTaskLogByLogId(Long logId);
+
+    /**
+     * 鏌ヨ浠诲姟鎿嶄綔鏃ュ織鍒楄〃
+     * 
+     * @param sysTaskLog 浠诲姟鎿嶄綔鏃ュ織
+     * @return 浠诲姟鎿嶄綔鏃ュ織闆嗗悎
+     */
+    public List<SysTaskLog> selectSysTaskLogList(SysTaskLog sysTaskLog);
+
+    /**
+     * 鏍规嵁浠诲姟ID鏌ヨ鎿嶄綔鏃ュ織鍒楄〃
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 浠诲姟鎿嶄綔鏃ュ織闆嗗悎
+     */
+    public List<SysTaskLog> selectSysTaskLogByTaskId(Long taskId);
+
+    /**
+     * 鏂板浠诲姟鎿嶄綔鏃ュ織
+     * 
+     * @param sysTaskLog 浠诲姟鎿嶄綔鏃ュ織
+     * @return 缁撴灉
+     */
+    public int insertSysTaskLog(SysTaskLog sysTaskLog);
+
+    /**
+     * 淇敼浠诲姟鎿嶄綔鏃ュ織
+     * 
+     * @param sysTaskLog 浠诲姟鎿嶄綔鏃ュ織
+     * @return 缁撴灉
+     */
+    public int updateSysTaskLog(SysTaskLog sysTaskLog);
+
+    /**
+     * 鍒犻櫎浠诲姟鎿嶄綔鏃ュ織
+     * 
+     * @param logId 浠诲姟鎿嶄綔鏃ュ織涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskLogByLogId(Long logId);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟鎿嶄綔鏃ュ織
+     * 
+     * @param logIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskLogByLogIds(Long[] logIds);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍒犻櫎鎿嶄綔鏃ュ織
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskLogByTaskId(Long taskId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskMapper.java
new file mode 100644
index 0000000..6a914c5
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskMapper.java
@@ -0,0 +1,109 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysTask;
+import com.ruoyi.system.domain.vo.TaskQueryVO;
+import com.ruoyi.system.domain.vo.TaskStatisticsVO;
+
+/**
+ * 浠诲姟绠$悊Mapper鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public interface SysTaskMapper {
+    
+    /**
+     * 鏌ヨ浠诲姟绠$悊
+     * 
+     * @param taskId 浠诲姟绠$悊涓婚敭
+     * @return 浠诲姟绠$悊
+     */
+    public SysTask selectSysTaskByTaskId(Long taskId);
+
+    /**
+     * 鏌ヨ浠诲姟绠$悊鍒楄〃
+     * 
+     * @param sysTask 浠诲姟绠$悊
+     * @return 浠诲姟绠$悊闆嗗悎
+     */
+    public List<SysTask> selectSysTaskList(TaskQueryVO queryVO);
+
+    /**
+     * 鏂板浠诲姟绠$悊
+     * 
+     * @param sysTask 浠诲姟绠$悊
+     * @return 缁撴灉
+     */
+    public int insertSysTask(SysTask sysTask);
+
+    /**
+     * 淇敼浠诲姟绠$悊
+     * 
+     * @param sysTask 浠诲姟绠$悊
+     * @return 缁撴灉
+     */
+    public int updateSysTask(SysTask sysTask);
+
+    /**
+     * 鍒犻櫎浠诲姟绠$悊
+     * 
+     * @param taskId 浠诲姟绠$悊涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskByTaskId(Long taskId);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟绠$悊
+     * 
+     * @param taskIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskByTaskIds(Long[] taskIds);
+
+    /**
+     * 鏌ヨ浠诲姟缁熻淇℃伅
+     * 
+     * @return 浠诲姟缁熻淇℃伅
+     */
+    public TaskStatisticsVO selectTaskStatistics();
+
+    /**
+     * 鏌ヨ瓒呮椂浠诲姟鍒楄〃
+     * 
+     * @return 瓒呮椂浠诲姟闆嗗悎
+     */
+    public List<SysTask> selectOverdueTasks();
+
+    /**
+     * 鏌ヨ鎴戠殑浠诲姟鍒楄〃
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鎴戠殑浠诲姟闆嗗悎
+     */
+    public List<SysTask> selectMyTasks(Long userId);
+
+    /**
+     * 鏍规嵁浠诲姟缂栧彿鏌ヨ浠诲姟
+     * 
+     * @param taskCode 浠诲姟缂栧彿
+     * @return 浠诲姟淇℃伅
+     */
+    public SysTask selectSysTaskByTaskCode(String taskCode);
+
+    /**
+     * 鏇存柊浠诲姟鐘舵��
+     * 
+     * @param sysTask 浠诲姟淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateTaskStatus(SysTask sysTask);
+
+    /**
+     * 鍒嗛厤浠诲姟
+     * 
+     * @param sysTask 浠诲姟淇℃伅
+     * @return 缁撴灉
+     */
+    public int assignTask(SysTask sysTask);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskVehicleMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskVehicleMapper.java
new file mode 100644
index 0000000..1969629
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskVehicleMapper.java
@@ -0,0 +1,103 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysTaskVehicle;
+
+/**
+ * 浠诲姟杞﹁締鍏宠仈Mapper鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public interface SysTaskVehicleMapper {
+    
+    /**
+     * 鏌ヨ浠诲姟杞﹁締鍏宠仈
+     * 
+     * @param id 浠诲姟杞﹁締鍏宠仈涓婚敭
+     * @return 浠诲姟杞﹁締鍏宠仈
+     */
+    public SysTaskVehicle selectSysTaskVehicleById(Long id);
+
+    /**
+     * 鏌ヨ浠诲姟杞﹁締鍏宠仈鍒楄〃
+     * 
+     * @param sysTaskVehicle 浠诲姟杞﹁締鍏宠仈
+     * @return 浠诲姟杞﹁締鍏宠仈闆嗗悎
+     */
+    public List<SysTaskVehicle> selectSysTaskVehicleList(SysTaskVehicle sysTaskVehicle);
+
+    /**
+     * 鏍规嵁浠诲姟ID鏌ヨ鍏宠仈杞﹁締鍒楄〃
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 浠诲姟杞﹁締鍏宠仈闆嗗悎
+     */
+    public List<SysTaskVehicle> selectSysTaskVehicleByTaskId(Long taskId);
+
+    /**
+     * 鏂板浠诲姟杞﹁締鍏宠仈
+     * 
+     * @param sysTaskVehicle 浠诲姟杞﹁締鍏宠仈
+     * @return 缁撴灉
+     */
+    public int insertSysTaskVehicle(SysTaskVehicle sysTaskVehicle);
+
+    /**
+     * 淇敼浠诲姟杞﹁締鍏宠仈
+     * 
+     * @param sysTaskVehicle 浠诲姟杞﹁締鍏宠仈
+     * @return 缁撴灉
+     */
+    public int updateSysTaskVehicle(SysTaskVehicle sysTaskVehicle);
+
+    /**
+     * 鍒犻櫎浠诲姟杞﹁締鍏宠仈
+     * 
+     * @param id 浠诲姟杞﹁締鍏宠仈涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskVehicleById(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟杞﹁締鍏宠仈
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskVehicleByIds(Long[] ids);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍒犻櫎杞﹁締鍏宠仈
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskVehicleByTaskId(Long taskId);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岃溅杈咺D鍒犻櫎鍏宠仈
+     * 
+     * @param taskId 浠诲姟ID
+     * @param vehicleId 杞﹁締ID
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskVehicleByTaskIdAndVehicleId(Long taskId, Long vehicleId);
+
+    /**
+     * 妫�鏌ヤ换鍔¤溅杈嗗叧鑱旀槸鍚﹀瓨鍦�
+     * 
+     * @param taskId 浠诲姟ID
+     * @param vehicleId 杞﹁締ID
+     * @return 缁撴灉
+     */
+    public int checkTaskVehicleExists(Long taskId, Long vehicleId);
+
+    /**
+     * 鎵归噺鏂板浠诲姟杞﹁締鍏宠仈
+     * 
+     * @param sysTaskVehicleList 浠诲姟杞﹁締鍏宠仈鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batchInsertSysTaskVehicle(List<SysTaskVehicle> sysTaskVehicleList);
+}
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
new file mode 100644
index 0000000..c56fa71
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
@@ -0,0 +1,174 @@
+package com.ruoyi.system.service;
+
+import java.util.List;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.system.domain.SysTask;
+import com.ruoyi.system.domain.SysTaskVehicle;
+import com.ruoyi.system.domain.SysTaskAttachment;
+import com.ruoyi.system.domain.vo.TaskQueryVO;
+import com.ruoyi.system.domain.vo.TaskCreateVO;
+import com.ruoyi.system.domain.vo.TaskUpdateVO;
+import com.ruoyi.system.domain.vo.TaskStatisticsVO;
+import com.ruoyi.system.domain.enums.TaskStatus;
+
+/**
+ * 浠诲姟绠$悊Service鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+public interface ISysTaskService {
+    
+    /**
+     * 鏌ヨ浠诲姟绠$悊
+     * 
+     * @param taskId 浠诲姟绠$悊涓婚敭
+     * @return 浠诲姟绠$悊
+     */
+    public SysTask selectSysTaskByTaskId(Long taskId);
+
+    /**
+     * 鏌ヨ浠诲姟绠$悊鍒楄〃
+     * 
+     * @param queryVO 浠诲姟鏌ヨ瀵硅薄
+     * @return 浠诲姟绠$悊闆嗗悎
+     */
+    public List<SysTask> selectSysTaskList(TaskQueryVO queryVO);
+
+    /**
+     * 鏂板浠诲姟绠$悊
+     * 
+     * @param createVO 浠诲姟鍒涘缓瀵硅薄
+     * @return 缁撴灉
+     */
+    public int insertSysTask(TaskCreateVO createVO);
+
+    /**
+     * 淇敼浠诲姟绠$悊
+     * 
+     * @param updateVO 浠诲姟鏇存柊瀵硅薄
+     * @return 缁撴灉
+     */
+    public int updateSysTask(TaskUpdateVO updateVO);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟绠$悊
+     * 
+     * @param taskIds 闇�瑕佸垹闄ょ殑浠诲姟绠$悊涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskByTaskIds(Long[] taskIds);
+
+    /**
+     * 鍒嗛厤浠诲姟
+     * 
+     * @param taskId 浠诲姟ID
+     * @param assigneeId 鎵ц浜篒D
+     * @param remark 澶囨敞
+     * @return 缁撴灉
+     */
+    public int assignTask(Long taskId, Long assigneeId, String remark);
+
+    /**
+     * 鍙樻洿浠诲姟鐘舵��
+     * 
+     * @param taskId 浠诲姟ID
+     * @param newStatus 鏂扮姸鎬�
+     * @param remark 澶囨敞
+     * @return 缁撴灉
+     */
+    public int changeTaskStatus(Long taskId, TaskStatus newStatus, String remark);
+
+    /**
+     * 涓婁紶浠诲姟闄勪欢
+     * 
+     * @param taskId 浠诲姟ID
+     * @param file 鏂囦欢
+     * @return 缁撴灉
+     */
+    public int uploadAttachment(Long taskId, MultipartFile file);
+
+    /**
+     * 鍒犻櫎浠诲姟闄勪欢
+     * 
+     * @param attachmentId 闄勪欢ID
+     * @return 缁撴灉
+     */
+    public int deleteAttachment(Long attachmentId);
+
+    /**
+     * 鍒嗛厤杞﹁締缁欎换鍔�
+     * 
+     * @param taskId 浠诲姟ID
+     * @param vehicleId 杞﹁締ID
+     * @param remark 澶囨敞
+     * @return 缁撴灉
+     */
+    public int assignVehicleToTask(Long taskId, Long vehicleId, String remark);
+
+    /**
+     * 鍙栨秷浠诲姟杞﹁締鍒嗛厤
+     * 
+     * @param taskId 浠诲姟ID
+     * @param vehicleId 杞﹁締ID
+     * @return 缁撴灉
+     */
+    public int unassignVehicleFromTask(Long taskId, Long vehicleId);
+
+    /**
+     * 鎵归噺鍒嗛厤杞﹁締缁欎换鍔�
+     * 
+     * @param taskId 浠诲姟ID
+     * @param vehicleIds 杞﹁締ID鍒楄〃
+     * @param remark 澶囨敞
+     * @return 缁撴灉
+     */
+    public int assignMultipleVehiclesToTask(Long taskId, List<Long> vehicleIds, String remark);
+
+    /**
+     * 鏌ヨ浠诲姟鍏宠仈鐨勮溅杈�
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 浠诲姟杞﹁締鍏宠仈鍒楄〃
+     */
+    public List<SysTaskVehicle> getTaskVehicles(Long taskId);
+
+    /**
+     * 鏌ヨ鍙敤杞﹁締
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @param taskType 浠诲姟绫诲瀷
+     * @return 鍙敤杞﹁締鍒楄〃
+     */
+    public List<SysTaskVehicle> getAvailableVehicles(Long deptId, String taskType);
+
+    /**
+     * 鏌ヨ浠诲姟缁熻淇℃伅
+     * 
+     * @return 浠诲姟缁熻淇℃伅
+     */
+    public TaskStatisticsVO getTaskStatistics();
+
+    /**
+     * 鏌ヨ瓒呮椂浠诲姟鍒楄〃
+     * 
+     * @return 瓒呮椂浠诲姟鍒楄〃
+     */
+    public List<SysTask> selectOverdueTasks();
+
+    /**
+     * 鏌ヨ鎴戠殑浠诲姟鍒楄〃
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鎴戠殑浠诲姟鍒楄〃
+     */
+    public List<SysTask> selectMyTasks(Long userId);
+
+    /**
+     * 鑾峰彇浠诲姟璇︽儏锛堝寘鍚叧鑱旀暟鎹級
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 浠诲姟璇︽儏
+     */
+    public SysTask getTaskDetail(Long taskId);
+}
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
new file mode 100644
index 0000000..093a6a4
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
@@ -0,0 +1,567 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.File;
+import java.io.IOException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.common.utils.file.FileUtils;
+import com.ruoyi.system.domain.SysTask;
+import com.ruoyi.system.domain.SysTaskVehicle;
+import com.ruoyi.system.domain.SysTaskAttachment;
+import com.ruoyi.system.domain.SysTaskLog;
+import com.ruoyi.system.domain.vo.TaskQueryVO;
+import com.ruoyi.system.domain.vo.TaskCreateVO;
+import com.ruoyi.system.domain.vo.TaskUpdateVO;
+import com.ruoyi.system.domain.vo.TaskStatisticsVO;
+import com.ruoyi.system.domain.enums.TaskStatus;
+import com.ruoyi.system.mapper.SysTaskMapper;
+import com.ruoyi.system.mapper.SysTaskVehicleMapper;
+import com.ruoyi.system.mapper.SysTaskAttachmentMapper;
+import com.ruoyi.system.mapper.SysTaskLogMapper;
+import com.ruoyi.system.service.ISysTaskService;
+
+/**
+ * 浠诲姟绠$悊Service涓氬姟灞傚鐞�
+ * 
+ * @author ruoyi
+ * @date 2024-01-15
+ */
+@Service
+public class SysTaskServiceImpl implements ISysTaskService {
+    
+    @Autowired
+    private SysTaskMapper sysTaskMapper;
+    
+    @Autowired
+    private SysTaskVehicleMapper sysTaskVehicleMapper;
+    
+    @Autowired
+    private SysTaskAttachmentMapper sysTaskAttachmentMapper;
+    
+    @Autowired
+    private SysTaskLogMapper sysTaskLogMapper;
+
+    /**
+     * 鏌ヨ浠诲姟绠$悊
+     * 
+     * @param taskId 浠诲姟绠$悊涓婚敭
+     * @return 浠诲姟绠$悊
+     */
+    @Override
+    public SysTask selectSysTaskByTaskId(Long taskId) {
+        return sysTaskMapper.selectSysTaskByTaskId(taskId);
+    }
+
+    /**
+     * 鏌ヨ浠诲姟绠$悊鍒楄〃
+     * 
+     * @param queryVO 浠诲姟鏌ヨ瀵硅薄
+     * @return 浠诲姟绠$悊
+     */
+    @Override
+    public List<SysTask> selectSysTaskList(TaskQueryVO queryVO) {
+        return sysTaskMapper.selectSysTaskList(queryVO);
+    }
+
+    /**
+     * 鏂板浠诲姟绠$悊
+     * 
+     * @param createVO 浠诲姟鍒涘缓瀵硅薄
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int insertSysTask(TaskCreateVO createVO) {
+        SysTask task = new SysTask();
+        task.setTaskCode(generateTaskCode());
+        task.setTaskType(createVO.getTaskType());
+        task.setTaskStatus(TaskStatus.PENDING.getCode());
+        task.setTaskDescription(createVO.getTaskDescription());
+        task.setDepartureAddress(createVO.getDepartureAddress());
+        task.setDestinationAddress(createVO.getDestinationAddress());
+        task.setPlannedStartTime(createVO.getPlannedStartTime());
+        task.setPlannedEndTime(createVO.getPlannedEndTime());
+        task.setAssigneeId(createVO.getAssigneeId());
+        task.setCreatorId(SecurityUtils.getUserId());
+        task.setDeptId(SecurityUtils.getDeptId());
+        task.setCreateBy(SecurityUtils.getUsername());
+        task.setCreateTime(DateUtils.getNowDate());
+        task.setRemark(createVO.getRemark());
+        task.setDelFlag("0");
+        
+        int result = sysTaskMapper.insertSysTask(task);
+        
+        // 璁板綍鎿嶄綔鏃ュ織
+        if (result > 0) {
+            recordTaskLog(task.getTaskId(), "CREATE", "鍒涘缓浠诲姟", null, 
+                         "浠诲姟绫诲瀷锛�" + createVO.getTaskType(), SecurityUtils.getUserId(), SecurityUtils.getUsername());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 淇敼浠诲姟绠$悊
+     * 
+     * @param updateVO 浠诲姟鏇存柊瀵硅薄
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int updateSysTask(TaskUpdateVO updateVO) {
+        SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(updateVO.getTaskId());
+        if (oldTask == null) {
+            throw new RuntimeException("浠诲姟涓嶅瓨鍦�");
+        }
+        
+        SysTask task = new SysTask();
+        task.setTaskId(updateVO.getTaskId());
+        task.setTaskDescription(updateVO.getTaskDescription());
+        task.setDepartureAddress(updateVO.getDepartureAddress());
+        task.setDestinationAddress(updateVO.getDestinationAddress());
+        task.setPlannedStartTime(updateVO.getPlannedStartTime());
+        task.setPlannedEndTime(updateVO.getPlannedEndTime());
+        task.setAssigneeId(updateVO.getAssigneeId());
+        task.setUpdateBy(SecurityUtils.getUsername());
+        task.setUpdateTime(DateUtils.getNowDate());
+        task.setRemark(updateVO.getRemark());
+        
+        int result = sysTaskMapper.updateSysTask(task);
+        
+        // 璁板綍鎿嶄綔鏃ュ織
+        if (result > 0) {
+            recordTaskLog(updateVO.getTaskId(), "UPDATE", "鏇存柊浠诲姟", 
+                         buildTaskDescription(oldTask), buildTaskDescription(task), 
+                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟绠$悊
+     * 
+     * @param taskIds 闇�瑕佸垹闄ょ殑浠诲姟绠$悊涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int deleteSysTaskByTaskIds(Long[] taskIds) {
+        int result = 0;
+        for (Long taskId : taskIds) {
+            // 璁板綍鍒犻櫎鏃ュ織
+            recordTaskLog(taskId, "DELETE", "鍒犻櫎浠诲姟", null, null, 
+                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
+            result += sysTaskMapper.deleteSysTaskByTaskId(taskId);
+        }
+        return result;
+    }
+
+    /**
+     * 鍒嗛厤浠诲姟
+     * 
+     * @param taskId 浠诲姟ID
+     * @param assigneeId 鎵ц浜篒D
+     * @param remark 澶囨敞
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int assignTask(Long taskId, Long assigneeId, String remark) {
+        SysTask task = new SysTask();
+        task.setTaskId(taskId);
+        task.setAssigneeId(assigneeId);
+        task.setUpdateBy(SecurityUtils.getUsername());
+        
+        int result = sysTaskMapper.assignTask(task);
+        
+        // 璁板綍鎿嶄綔鏃ュ織
+        if (result > 0) {
+            recordTaskLog(taskId, "ASSIGN", "鍒嗛厤浠诲姟", null, 
+                         "鍒嗛厤缁欑敤鎴稩D锛�" + assigneeId + "锛屽娉細" + remark, 
+                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 鍙樻洿浠诲姟鐘舵��
+     * 
+     * @param taskId 浠诲姟ID
+     * @param newStatus 鏂扮姸鎬�
+     * @param remark 澶囨敞
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int changeTaskStatus(Long taskId, TaskStatus newStatus, String remark) {
+        SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(taskId);
+        if (oldTask == null) {
+            throw new RuntimeException("浠诲姟涓嶅瓨鍦�");
+        }
+        
+        // 楠岃瘉鐘舵�佹祦杞槸鍚﹀悎娉�
+        TaskStatus oldTaskStatus = TaskStatus.getByCode(oldTask.getTaskStatus());
+        if (!oldTask.canChangeStatus(newStatus)) {
+            throw new RuntimeException("鐘舵�佹祦杞笉鍚堟硶锛氫粠 " + oldTaskStatus.getInfo() + " 鍒� " + newStatus.getInfo());
+        }
+        
+        SysTask task = new SysTask();
+        task.setTaskId(taskId);
+        task.setTaskStatus(newStatus.getCode());
+        task.setUpdateBy(SecurityUtils.getUsername());
+        
+        // 鏍规嵁鐘舵�佽缃浉搴旂殑鏃堕棿
+        if (newStatus == TaskStatus.IN_PROGRESS && oldTask.getActualStartTime() == null) {
+            task.setActualStartTime(DateUtils.getNowDate());
+        } else if (newStatus == TaskStatus.COMPLETED) {
+            task.setActualEndTime(DateUtils.getNowDate());
+        }
+        
+        int result = sysTaskMapper.updateTaskStatus(task);
+        
+        // 璁板綍鎿嶄綔鏃ュ織
+        if (result > 0) {
+            recordTaskLog(taskId, "STATUS_CHANGE", "鐘舵�佸彉鏇�", 
+                         "鐘舵�侊細" + oldTaskStatus.getInfo(), 
+                         "鐘舵�侊細" + newStatus.getInfo() + "锛屽娉細" + remark, 
+                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 涓婁紶浠诲姟闄勪欢
+     * 
+     * @param taskId 浠诲姟ID
+     * @param file 鏂囦欢
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int uploadAttachment(Long taskId, MultipartFile file) {
+        try {
+            // 涓婁紶鏂囦欢
+            String fileName = FileUploadUtils.upload("/task", file);
+            String filePath = FileUploadUtils.getDefaultBaseDir() + fileName;
+            
+            SysTaskAttachment attachment = new SysTaskAttachment();
+            attachment.setTaskId(taskId);
+            attachment.setFileName(file.getOriginalFilename());
+            attachment.setFilePath(filePath);
+            attachment.setFileSize(file.getSize());
+            attachment.setFileType(getFileType(file.getOriginalFilename()));
+            attachment.setUploadTime(DateUtils.getNowDate());
+            attachment.setUploadBy(SecurityUtils.getUsername());
+            
+            int result = sysTaskAttachmentMapper.insertSysTaskAttachment(attachment);
+            
+            // 璁板綍鎿嶄綔鏃ュ織
+            if (result > 0) {
+                recordTaskLog(taskId, "UPDATE", "涓婁紶闄勪欢", null, 
+                             "涓婁紶鏂囦欢锛�" + file.getOriginalFilename(), 
+                             SecurityUtils.getUserId(), SecurityUtils.getUsername());
+            }
+            
+            return result;
+        } catch (IOException e) {
+            throw new RuntimeException("鏂囦欢涓婁紶澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟闄勪欢
+     * 
+     * @param attachmentId 闄勪欢ID
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int deleteAttachment(Long attachmentId) {
+        SysTaskAttachment attachment = sysTaskAttachmentMapper.selectSysTaskAttachmentByAttachmentId(attachmentId);
+        if (attachment == null) {
+            throw new RuntimeException("闄勪欢涓嶅瓨鍦�");
+        }
+        
+        // 鍒犻櫎鐗╃悊鏂囦欢
+        try {
+            FileUtils.deleteFile(attachment.getFilePath());
+        } catch (Exception e) {
+            // 蹇界暐鏂囦欢鍒犻櫎澶辫触
+        }
+        
+        int result = sysTaskAttachmentMapper.deleteSysTaskAttachmentByAttachmentId(attachmentId);
+        
+        // 璁板綍鎿嶄綔鏃ュ織
+        if (result > 0) {
+            recordTaskLog(attachment.getTaskId(), "UPDATE", "鍒犻櫎闄勪欢", 
+                         "鍒犻櫎鏂囦欢锛�" + attachment.getFileName(), null, 
+                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 鍒嗛厤杞﹁締缁欎换鍔�
+     * 
+     * @param taskId 浠诲姟ID
+     * @param vehicleId 杞﹁締ID
+     * @param remark 澶囨敞
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int assignVehicleToTask(Long taskId, Long vehicleId, String remark) {
+        // 妫�鏌ユ槸鍚﹀凡缁忓垎閰�
+        int exists = sysTaskVehicleMapper.checkTaskVehicleExists(taskId, vehicleId);
+        if (exists > 0) {
+            throw new RuntimeException("杞﹁締宸茬粡鍒嗛厤缁欒浠诲姟");
+        }
+        
+        SysTaskVehicle taskVehicle = new SysTaskVehicle();
+        taskVehicle.setTaskId(taskId);
+        taskVehicle.setVehicleId(vehicleId);
+        taskVehicle.setAssignTime(DateUtils.getNowDate());
+        taskVehicle.setAssignBy(SecurityUtils.getUsername());
+        taskVehicle.setStatus("ASSIGNED");
+        taskVehicle.setRemark(remark);
+        
+        int result = sysTaskVehicleMapper.insertSysTaskVehicle(taskVehicle);
+        
+        // 璁板綍鎿嶄綔鏃ュ織
+        if (result > 0) {
+            recordTaskLog(taskId, "ASSIGN", "鍒嗛厤杞﹁締", null, 
+                         "鍒嗛厤杞﹁締ID锛�" + vehicleId + "锛屽娉細" + remark, 
+                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 鍙栨秷浠诲姟杞﹁締鍒嗛厤
+     * 
+     * @param taskId 浠诲姟ID
+     * @param vehicleId 杞﹁締ID
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int unassignVehicleFromTask(Long taskId, Long vehicleId) {
+        int result = sysTaskVehicleMapper.deleteSysTaskVehicleByTaskIdAndVehicleId(taskId, vehicleId);
+        
+        // 璁板綍鎿嶄綔鏃ュ織
+        if (result > 0) {
+            recordTaskLog(taskId, "ASSIGN", "鍙栨秷杞﹁締鍒嗛厤", 
+                         "鍙栨秷杞﹁締ID锛�" + vehicleId, null, 
+                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 鎵归噺鍒嗛厤杞﹁締缁欎换鍔�
+     * 
+     * @param taskId 浠诲姟ID
+     * @param vehicleIds 杞﹁締ID鍒楄〃
+     * @param remark 澶囨敞
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int assignMultipleVehiclesToTask(Long taskId, List<Long> vehicleIds, String remark) {
+        List<SysTaskVehicle> taskVehicles = new ArrayList<>();
+        Date now = DateUtils.getNowDate();
+        String assignBy = SecurityUtils.getUsername();
+        
+        for (Long vehicleId : vehicleIds) {
+            // 妫�鏌ユ槸鍚﹀凡缁忓垎閰�
+            int exists = sysTaskVehicleMapper.checkTaskVehicleExists(taskId, vehicleId);
+            if (exists == 0) {
+                SysTaskVehicle taskVehicle = new SysTaskVehicle();
+                taskVehicle.setTaskId(taskId);
+                taskVehicle.setVehicleId(vehicleId);
+                taskVehicle.setAssignTime(now);
+                taskVehicle.setAssignBy(assignBy);
+                taskVehicle.setStatus("ASSIGNED");
+                taskVehicle.setRemark(remark);
+                taskVehicles.add(taskVehicle);
+            }
+        }
+        
+        int result = 0;
+        if (!taskVehicles.isEmpty()) {
+            result = sysTaskVehicleMapper.batchInsertSysTaskVehicle(taskVehicles);
+        }
+        
+        // 璁板綍鎿嶄綔鏃ュ織
+        if (result > 0) {
+            recordTaskLog(taskId, "ASSIGN", "鎵归噺鍒嗛厤杞﹁締", null, 
+                         "鍒嗛厤杞﹁締鏁伴噺锛�" + result + "锛屽娉細" + remark, 
+                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 鏌ヨ浠诲姟鍏宠仈鐨勮溅杈�
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 浠诲姟杞﹁締鍏宠仈鍒楄〃
+     */
+    @Override
+    public List<SysTaskVehicle> getTaskVehicles(Long taskId) {
+        return sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId);
+    }
+
+    /**
+     * 鏌ヨ鍙敤杞﹁締
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @param taskType 浠诲姟绫诲瀷
+     * @return 鍙敤杞﹁締鍒楄〃
+     */
+    @Override
+    public List<SysTaskVehicle> getAvailableVehicles(Long deptId, String taskType) {
+        // 杩欓噷闇�瑕佹牴鎹笟鍔¢�昏緫鏌ヨ鍙敤杞﹁締
+        // 鏆傛椂杩斿洖绌哄垪琛紝瀹為檯瀹炵幇闇�瑕佹煡璇㈣溅杈嗚〃
+        return new ArrayList<>();
+    }
+
+    /**
+     * 鏌ヨ浠诲姟缁熻淇℃伅
+     * 
+     * @return 浠诲姟缁熻淇℃伅
+     */
+    @Override
+    public TaskStatisticsVO getTaskStatistics() {
+        return sysTaskMapper.selectTaskStatistics();
+    }
+
+    /**
+     * 鏌ヨ瓒呮椂浠诲姟鍒楄〃
+     * 
+     * @return 瓒呮椂浠诲姟鍒楄〃
+     */
+    @Override
+    public List<SysTask> selectOverdueTasks() {
+        return sysTaskMapper.selectOverdueTasks();
+    }
+
+    /**
+     * 鏌ヨ鎴戠殑浠诲姟鍒楄〃
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鎴戠殑浠诲姟鍒楄〃
+     */
+    @Override
+    public List<SysTask> selectMyTasks(Long userId) {
+        return sysTaskMapper.selectMyTasks(userId);
+    }
+
+    /**
+     * 鑾峰彇浠诲姟璇︽儏锛堝寘鍚叧鑱旀暟鎹級
+     * 
+     * @param taskId 浠诲姟ID
+     * @return 浠诲姟璇︽儏
+     */
+    @Override
+    public SysTask getTaskDetail(Long taskId) {
+        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
+        if (task != null) {
+            // 鏌ヨ鍏宠仈杞﹁締
+            task.setAssignedVehicles(sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId));
+            // 鏌ヨ闄勪欢
+            task.setAttachments(sysTaskAttachmentMapper.selectSysTaskAttachmentByTaskId(taskId));
+            // 鏌ヨ鎿嶄綔鏃ュ織
+            task.setOperationLogs(sysTaskLogMapper.selectSysTaskLogByTaskId(taskId));
+        }
+        return task;
+    }
+
+    /**
+     * 鐢熸垚浠诲姟缂栧彿
+     * 
+     * @return 浠诲姟缂栧彿
+     */
+    private String generateTaskCode() {
+        String dateStr = DateUtils.dateTimeNow("yyyyMMdd");
+        return "TASK" + dateStr + "0001";
+    }
+
+    /**
+     * 璁板綍浠诲姟鎿嶄綔鏃ュ織
+     * 
+     * @param taskId 浠诲姟ID
+     * @param operationType 鎿嶄綔绫诲瀷
+     * @param operationDesc 鎿嶄綔鎻忚堪
+     * @param oldValue 鎿嶄綔鍓嶅��
+     * @param newValue 鎿嶄綔鍚庡��
+     * @param operatorId 鎿嶄綔浜篒D
+     * @param operatorName 鎿嶄綔浜哄鍚�
+     */
+    private void recordTaskLog(Long taskId, String operationType, String operationDesc, 
+                              String oldValue, String newValue, Long operatorId, String operatorName) {
+        SysTaskLog log = new SysTaskLog();
+        log.setTaskId(taskId);
+        log.setOperationType(operationType);
+        log.setOperationDesc(operationDesc);
+        log.setOldValue(oldValue);
+        log.setNewValue(newValue);
+        log.setOperatorId(operatorId);
+        log.setOperatorName(operatorName);
+        log.setOperationTime(DateUtils.getNowDate());
+        // 杩欓噷鍙互鑾峰彇IP鍦板潃
+        log.setIpAddress("127.0.0.1");
+        
+        sysTaskLogMapper.insertSysTaskLog(log);
+    }
+
+    /**
+     * 鏋勫缓浠诲姟鎻忚堪
+     * 
+     * @param task 浠诲姟瀵硅薄
+     * @return 浠诲姟鎻忚堪
+     */
+    private String buildTaskDescription(SysTask task) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("浠诲姟缂栧彿锛�").append(task.getTaskCode()).append("锛�");
+        sb.append("浠诲姟绫诲瀷锛�").append(task.getTaskType()).append("锛�");
+        sb.append("浠诲姟鐘舵�侊細").append(task.getTaskStatus()).append("锛�");
+        if (StringUtils.isNotEmpty(task.getTaskDescription())) {
+            sb.append("浠诲姟鎻忚堪锛�").append(task.getTaskDescription()).append("锛�");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 鑾峰彇鏂囦欢绫诲瀷
+     * 
+     * @param fileName 鏂囦欢鍚�
+     * @return 鏂囦欢绫诲瀷
+     */
+    private String getFileType(String fileName) {
+        if (StringUtils.isEmpty(fileName)) {
+            return "";
+        }
+        int lastDotIndex = fileName.lastIndexOf(".");
+        if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
+            return fileName.substring(lastDotIndex + 1).toLowerCase();
+        }
+        return "";
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskCodeGenerator.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskCodeGenerator.java
new file mode 100644
index 0000000..6f73f74
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskCodeGenerator.java
@@ -0,0 +1,38 @@
+package com.ruoyi.system.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.utils.DateUtils;
+
+/**
+ * 浠诲姟缂栧彿鐢熸垚鍣�
+ * 
+ * @author ruoyi
+ */
+@Component
+public class TaskCodeGenerator {
+    
+    /**
+     * 鐢熸垚浠诲姟缂栧彿
+     * 鏍煎紡锛歍ASK + YYYYMMDD + 4浣嶅簭鍙�
+     * 
+     * @return 浠诲姟缂栧彿
+     */
+    public String generateTaskCode() {
+        String dateStr = DateUtils.dateTimeNow("yyyyMMdd");
+        return "TASK" + dateStr + "0001";
+    }
+    
+    /**
+     * 鏍规嵁鏃ユ湡鐢熸垚浠诲姟缂栧彿
+     * 
+     * @param date 鏃ユ湡
+     * @return 浠诲姟缂栧彿
+     */
+    public String generateTaskCode(Date date) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+        String dateStr = sdf.format(date);
+        return "TASK" + dateStr + "0001";
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java
new file mode 100644
index 0000000..b62b5d6
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusValidator.java
@@ -0,0 +1,66 @@
+package com.ruoyi.system.utils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.springframework.stereotype.Component;
+import com.ruoyi.system.domain.enums.TaskStatus;
+
+/**
+ * 浠诲姟鐘舵�佹祦杞獙璇佸櫒
+ * 
+ * @author ruoyi
+ */
+@Component
+public class TaskStatusValidator {
+    
+    private static final Map<TaskStatus, Set<TaskStatus>> ALLOWED_TRANSITIONS = new HashMap<>();
+    
+    static {
+        // PENDING -> IN_PROGRESS, CANCELLED
+        Set<TaskStatus> pendingTransitions = new HashSet<>();
+        pendingTransitions.add(TaskStatus.IN_PROGRESS);
+        pendingTransitions.add(TaskStatus.CANCELLED);
+        ALLOWED_TRANSITIONS.put(TaskStatus.PENDING, pendingTransitions);
+        
+        // IN_PROGRESS -> COMPLETED, CANCELLED, PENDING
+        Set<TaskStatus> inProgressTransitions = new HashSet<>();
+        inProgressTransitions.add(TaskStatus.COMPLETED);
+        inProgressTransitions.add(TaskStatus.CANCELLED);
+        inProgressTransitions.add(TaskStatus.PENDING);
+        ALLOWED_TRANSITIONS.put(TaskStatus.IN_PROGRESS, inProgressTransitions);
+        
+        // COMPLETED -> 涓嶅厑璁镐换浣曠姸鎬佸彉鏇�
+        ALLOWED_TRANSITIONS.put(TaskStatus.COMPLETED, new HashSet<>());
+        // CANCELLED -> 涓嶅厑璁镐换浣曠姸鎬佸彉鏇�
+        ALLOWED_TRANSITIONS.put(TaskStatus.CANCELLED, new HashSet<>());
+    }
+    
+    /**
+     * 楠岃瘉鐘舵�佹祦杞槸鍚﹀悎娉�
+     * 
+     * @param from 鍘熺姸鎬�
+     * @param to 鐩爣鐘舵��
+     * @return 鏄惁鍏佽娴佽浆
+     */
+    public boolean canTransition(TaskStatus from, TaskStatus to) {
+        if (from == null || to == null) {
+            return false;
+        }
+        return ALLOWED_TRANSITIONS.get(from).contains(to);
+    }
+    
+    /**
+     * 鑾峰彇鍏佽鐨勭姸鎬佹祦杞垪琛�
+     * 
+     * @param from 鍘熺姸鎬�
+     * @return 鍏佽鐨勭洰鏍囩姸鎬侀泦鍚�
+     */
+    public Set<TaskStatus> getAllowedTransitions(TaskStatus from) {
+        if (from == null) {
+            return new HashSet<>();
+        }
+        return ALLOWED_TRANSITIONS.get(from);
+    }
+}
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml
new file mode 100644
index 0000000..dcda30a
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskAttachmentMapper.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.SysTaskAttachmentMapper">
+    
+    <resultMap type="SysTaskAttachment" id="SysTaskAttachmentResult">
+        <result property="attachmentId"     column="attachment_id"     />
+        <result property="taskId"           column="task_id"           />
+        <result property="fileName"         column="file_name"         />
+        <result property="filePath"         column="file_path"         />
+        <result property="fileSize"         column="file_size"         />
+        <result property="fileType"         column="file_type"         />
+        <result property="uploadTime"       column="upload_time"       />
+        <result property="uploadBy"         column="upload_by"         />
+    </resultMap>
+
+    <sql id="selectSysTaskAttachmentVo">
+        select attachment_id, task_id, file_name, file_path, file_size, file_type, upload_time, upload_by 
+        from sys_task_attachment
+    </sql>
+
+    <select id="selectSysTaskAttachmentList" parameterType="SysTaskAttachment" resultMap="SysTaskAttachmentResult">
+        <include refid="selectSysTaskAttachmentVo"/>
+        <where>  
+            <if test="taskId != null "> and task_id = #{taskId}</if>
+            <if test="fileName != null  and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
+            <if test="fileType != null  and fileType != ''"> and file_type = #{fileType}</if>
+            <if test="uploadBy != null  and uploadBy != ''"> and upload_by like concat('%', #{uploadBy}, '%')</if>
+        </where>
+        order by upload_time desc
+    </select>
+    
+    <select id="selectSysTaskAttachmentByAttachmentId" parameterType="Long" resultMap="SysTaskAttachmentResult">
+        <include refid="selectSysTaskAttachmentVo"/>
+        where attachment_id = #{attachmentId}
+    </select>
+
+    <select id="selectSysTaskAttachmentByTaskId" parameterType="Long" resultMap="SysTaskAttachmentResult">
+        <include refid="selectSysTaskAttachmentVo"/>
+        where task_id = #{taskId}
+        order by upload_time desc
+    </select>
+        
+    <insert id="insertSysTaskAttachment" parameterType="SysTaskAttachment" useGeneratedKeys="true" keyProperty="attachmentId">
+        insert into sys_task_attachment
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">task_id,</if>
+            <if test="fileName != null and fileName != ''">file_name,</if>
+            <if test="filePath != null and filePath != ''">file_path,</if>
+            <if test="fileSize != null">file_size,</if>
+            <if test="fileType != null">file_type,</if>
+            <if test="uploadTime != null">upload_time,</if>
+            <if test="uploadBy != null and uploadBy != ''">upload_by,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">#{taskId},</if>
+            <if test="fileName != null and fileName != ''">#{fileName},</if>
+            <if test="filePath != null and filePath != ''">#{filePath},</if>
+            <if test="fileSize != null">#{fileSize},</if>
+            <if test="fileType != null">#{fileType},</if>
+            <if test="uploadTime != null">#{uploadTime},</if>
+            <if test="uploadBy != null and uploadBy != ''">#{uploadBy},</if>
+         </trim>
+    </insert>
+
+    <update id="updateSysTaskAttachment" parameterType="SysTaskAttachment">
+        update sys_task_attachment
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskId != null">task_id = #{taskId},</if>
+            <if test="fileName != null and fileName != ''">file_name = #{fileName},</if>
+            <if test="filePath != null and filePath != ''">file_path = #{filePath},</if>
+            <if test="fileSize != null">file_size = #{fileSize},</if>
+            <if test="fileType != null">file_type = #{fileType},</if>
+            <if test="uploadTime != null">upload_time = #{uploadTime},</if>
+            <if test="uploadBy != null and uploadBy != ''">upload_by = #{uploadBy},</if>
+        </trim>
+        where attachment_id = #{attachmentId}
+    </update>
+
+    <delete id="deleteSysTaskAttachmentByAttachmentId" parameterType="Long">
+        delete from sys_task_attachment where attachment_id = #{attachmentId}
+    </delete>
+
+    <delete id="deleteSysTaskAttachmentByAttachmentIds" parameterType="String">
+        delete from sys_task_attachment where attachment_id in 
+        <foreach item="attachmentId" collection="array" open="(" separator="," close=")">
+            #{attachmentId}
+        </foreach>
+    </delete>
+
+    <delete id="deleteSysTaskAttachmentByTaskId" parameterType="Long">
+        delete from sys_task_attachment where task_id = #{taskId}
+    </delete>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml
new file mode 100644
index 0000000..0144d40
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskLogMapper.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.SysTaskLogMapper">
+    
+    <resultMap type="SysTaskLog" id="SysTaskLogResult">
+        <result property="logId"            column="log_id"            />
+        <result property="taskId"           column="task_id"           />
+        <result property="operationType"    column="operation_type"    />
+        <result property="operationDesc"    column="operation_desc"    />
+        <result property="oldValue"         column="old_value"         />
+        <result property="newValue"         column="new_value"         />
+        <result property="operatorId"       column="operator_id"       />
+        <result property="operatorName"     column="operator_name"     />
+        <result property="operationTime"    column="operation_time"    />
+        <result property="ipAddress"        column="ip_address"        />
+    </resultMap>
+
+    <sql id="selectSysTaskLogVo">
+        select log_id, task_id, operation_type, operation_desc, old_value, new_value, 
+               operator_id, operator_name, operation_time, ip_address 
+        from sys_task_log
+    </sql>
+
+    <select id="selectSysTaskLogList" parameterType="SysTaskLog" resultMap="SysTaskLogResult">
+        <include refid="selectSysTaskLogVo"/>
+        <where>  
+            <if test="taskId != null "> and task_id = #{taskId}</if>
+            <if test="operationType != null  and operationType != ''"> and operation_type = #{operationType}</if>
+            <if test="operatorId != null "> and operator_id = #{operatorId}</if>
+            <if test="operatorName != null  and operatorName != ''"> and operator_name like concat('%', #{operatorName}, '%')</if>
+        </where>
+        order by operation_time desc
+    </select>
+    
+    <select id="selectSysTaskLogByLogId" parameterType="Long" resultMap="SysTaskLogResult">
+        <include refid="selectSysTaskLogVo"/>
+        where log_id = #{logId}
+    </select>
+
+    <select id="selectSysTaskLogByTaskId" parameterType="Long" resultMap="SysTaskLogResult">
+        <include refid="selectSysTaskLogVo"/>
+        where task_id = #{taskId}
+        order by operation_time desc
+    </select>
+        
+    <insert id="insertSysTaskLog" parameterType="SysTaskLog" useGeneratedKeys="true" keyProperty="logId">
+        insert into sys_task_log
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">task_id,</if>
+            <if test="operationType != null and operationType != ''">operation_type,</if>
+            <if test="operationDesc != null">operation_desc,</if>
+            <if test="oldValue != null">old_value,</if>
+            <if test="newValue != null">new_value,</if>
+            <if test="operatorId != null">operator_id,</if>
+            <if test="operatorName != null and operatorName != ''">operator_name,</if>
+            <if test="operationTime != null">operation_time,</if>
+            <if test="ipAddress != null">ip_address,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">#{taskId},</if>
+            <if test="operationType != null and operationType != ''">#{operationType},</if>
+            <if test="operationDesc != null">#{operationDesc},</if>
+            <if test="oldValue != null">#{oldValue},</if>
+            <if test="newValue != null">#{newValue},</if>
+            <if test="operatorId != null">#{operatorId},</if>
+            <if test="operatorName != null and operatorName != ''">#{operatorName},</if>
+            <if test="operationTime != null">#{operationTime},</if>
+            <if test="ipAddress != null">#{ipAddress},</if>
+         </trim>
+    </insert>
+
+    <update id="updateSysTaskLog" parameterType="SysTaskLog">
+        update sys_task_log
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskId != null">task_id = #{taskId},</if>
+            <if test="operationType != null and operationType != ''">operation_type = #{operationType},</if>
+            <if test="operationDesc != null">operation_desc = #{operationDesc},</if>
+            <if test="oldValue != null">old_value = #{oldValue},</if>
+            <if test="newValue != null">new_value = #{newValue},</if>
+            <if test="operatorId != null">operator_id = #{operatorId},</if>
+            <if test="operatorName != null and operatorName != ''">operator_name = #{operatorName},</if>
+            <if test="operationTime != null">operation_time = #{operationTime},</if>
+            <if test="ipAddress != null">ip_address = #{ipAddress},</if>
+        </trim>
+        where log_id = #{logId}
+    </update>
+
+    <delete id="deleteSysTaskLogByLogId" parameterType="Long">
+        delete from sys_task_log where log_id = #{logId}
+    </delete>
+
+    <delete id="deleteSysTaskLogByLogIds" parameterType="String">
+        delete from sys_task_log where log_id in 
+        <foreach item="logId" collection="array" open="(" separator="," close=")">
+            #{logId}
+        </foreach>
+    </delete>
+
+    <delete id="deleteSysTaskLogByTaskId" parameterType="Long">
+        delete from sys_task_log where task_id = #{taskId}
+    </delete>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
new file mode 100644
index 0000000..359443d
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.SysTaskMapper">
+    
+    <resultMap type="SysTask" id="SysTaskResult">
+        <result property="taskId"           column="task_id"           />
+        <result property="taskCode"         column="task_code"         />
+        <result property="taskType"         column="task_type"         />
+        <result property="taskStatus"       column="task_status"       />
+        <result property="taskDescription"  column="task_description"  />
+        <result property="departureAddress" column="departure_address" />
+        <result property="destinationAddress" column="destination_address" />
+        <result property="plannedStartTime" column="planned_start_time" />
+        <result property="plannedEndTime"   column="planned_end_time"  />
+        <result property="actualStartTime"  column="actual_start_time" />
+        <result property="actualEndTime"    column="actual_end_time"   />
+        <result property="creatorId"        column="creator_id"        />
+        <result property="assigneeId"       column="assignee_id"       />
+        <result property="deptId"           column="dept_id"           />
+        <result property="createTime"       column="create_time"       />
+        <result property="updateTime"       column="update_time"       />
+        <result property="createBy"         column="create_by"         />
+        <result property="updateBy"         column="update_by"         />
+        <result property="remark"           column="remark"            />
+        <result property="delFlag"          column="del_flag"          />
+        <result property="creatorName"      column="creator_name"      />
+        <result property="assigneeName"     column="assignee_name"     />
+        <result property="deptName"         column="dept_name"         />
+    </resultMap>
+
+    <sql id="selectSysTaskVo">
+        select t.task_id, t.task_code, t.task_type, t.task_status, t.task_description, 
+               t.departure_address, t.destination_address, t.planned_start_time, t.planned_end_time,
+               t.actual_start_time, t.actual_end_time, t.creator_id, t.assignee_id, t.dept_id,
+               t.create_time, t.update_time, t.create_by, t.update_by, t.remark, t.del_flag,
+               u1.nick_name as creator_name, u2.nick_name as assignee_name, d.dept_name
+        from sys_task t
+        left join sys_user u1 on t.creator_id = u1.user_id
+        left join sys_user u2 on t.assignee_id = u2.user_id
+        left join sys_dept d on t.dept_id = d.dept_id
+    </sql>
+
+    <select id="selectSysTaskList" parameterType="TaskQueryVO" resultMap="SysTaskResult">
+        <include refid="selectSysTaskVo"/>
+        <where>  
+            t.del_flag = '0'
+            <if test="taskCode != null  and taskCode != ''"> and t.task_code like concat('%', #{taskCode}, '%')</if>
+            <if test="taskType != null  and taskType != ''"> and t.task_type = #{taskType}</if>
+            <if test="taskStatus != null  and taskStatus != ''"> and t.task_status = #{taskStatus}</if>
+            <if test="creatorId != null "> and t.creator_id = #{creatorId}</if>
+            <if test="assigneeId != null "> and t.assignee_id = #{assigneeId}</if>
+            <if test="deptId != null "> and t.dept_id = #{deptId}</if>
+            <if test="plannedStartTimeBegin != null "> and t.planned_start_time &gt;= #{plannedStartTimeBegin}</if>
+            <if test="plannedStartTimeEnd != null "> and t.planned_start_time &lt;= #{plannedStartTimeEnd}</if>
+            <if test="plannedEndTimeBegin != null "> and t.planned_end_time &gt;= #{plannedEndTimeBegin}</if>
+            <if test="plannedEndTimeEnd != null "> and t.planned_end_time &lt;= #{plannedEndTimeEnd}</if>
+            <if test="overdue != null and overdue == true"> and t.planned_end_time &lt; now() and t.task_status != 'COMPLETED'</if>
+        </where>
+        order by t.create_time desc
+    </select>
+    
+    <select id="selectSysTaskByTaskId" parameterType="Long" resultMap="SysTaskResult">
+        <include refid="selectSysTaskVo"/>
+        where t.task_id = #{taskId} and t.del_flag = '0'
+    </select>
+
+    <select id="selectSysTaskByTaskCode" parameterType="String" resultMap="SysTaskResult">
+        <include refid="selectSysTaskVo"/>
+        where t.task_code = #{taskCode} and t.del_flag = '0'
+    </select>
+
+    <select id="selectOverdueTasks" resultMap="SysTaskResult">
+        <include refid="selectSysTaskVo"/>
+        where t.del_flag = '0' and t.planned_end_time &lt; now() and t.task_status != 'COMPLETED'
+        order by t.planned_end_time asc
+    </select>
+
+    <select id="selectMyTasks" parameterType="Long" resultMap="SysTaskResult">
+        <include refid="selectSysTaskVo"/>
+        where t.del_flag = '0' and (t.creator_id = #{userId} or t.assignee_id = #{userId})
+        order by t.create_time desc
+    </select>
+
+    <select id="selectTaskStatistics" resultType="TaskStatisticsVO">
+        select 
+            count(*) as totalTasks,
+            sum(case when task_status = 'PENDING' then 1 else 0 end) as pendingTasks,
+            sum(case when task_status = 'IN_PROGRESS' then 1 else 0 end) as inProgressTasks,
+            sum(case when task_status = 'COMPLETED' then 1 else 0 end) as completedTasks,
+            sum(case when task_status = 'CANCELLED' then 1 else 0 end) as cancelledTasks,
+            sum(case when date(create_time) = curdate() then 1 else 0 end) as todayTasks,
+            sum(case when planned_end_time &lt; now() and task_status != 'COMPLETED' then 1 else 0 end) as overdueTasks,
+            round(sum(case when task_status = 'IN_PROGRESS' then 1 else 0 end) * 100.0 / count(*), 2) as vehicleUtilization
+        from sys_task 
+        where del_flag = '0'
+    </select>
+        
+    <insert id="insertSysTask" parameterType="SysTask" useGeneratedKeys="true" keyProperty="taskId">
+        insert into sys_task
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskCode != null and taskCode != ''">task_code,</if>
+            <if test="taskType != null and taskType != ''">task_type,</if>
+            <if test="taskStatus != null and taskStatus != ''">task_status,</if>
+            <if test="taskDescription != null">task_description,</if>
+            <if test="departureAddress != null">departure_address,</if>
+            <if test="destinationAddress != null">destination_address,</if>
+            <if test="plannedStartTime != null">planned_start_time,</if>
+            <if test="plannedEndTime != null">planned_end_time,</if>
+            <if test="actualStartTime != null">actual_start_time,</if>
+            <if test="actualEndTime != null">actual_end_time,</if>
+            <if test="creatorId != null">creator_id,</if>
+            <if test="assigneeId != null">assignee_id,</if>
+            <if test="deptId != null">dept_id,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="remark != null">remark,</if>
+            <if test="delFlag != null">del_flag,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="taskCode != null and taskCode != ''">#{taskCode},</if>
+            <if test="taskType != null and taskType != ''">#{taskType},</if>
+            <if test="taskStatus != null and taskStatus != ''">#{taskStatus},</if>
+            <if test="taskDescription != null">#{taskDescription},</if>
+            <if test="departureAddress != null">#{departureAddress},</if>
+            <if test="destinationAddress != null">#{destinationAddress},</if>
+            <if test="plannedStartTime != null">#{plannedStartTime},</if>
+            <if test="plannedEndTime != null">#{plannedEndTime},</if>
+            <if test="actualStartTime != null">#{actualStartTime},</if>
+            <if test="actualEndTime != null">#{actualEndTime},</if>
+            <if test="creatorId != null">#{creatorId},</if>
+            <if test="assigneeId != null">#{assigneeId},</if>
+            <if test="deptId != null">#{deptId},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+         </trim>
+    </insert>
+
+    <update id="updateSysTask" parameterType="SysTask">
+        update sys_task
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskCode != null and taskCode != ''">task_code = #{taskCode},</if>
+            <if test="taskType != null and taskType != ''">task_type = #{taskType},</if>
+            <if test="taskStatus != null and taskStatus != ''">task_status = #{taskStatus},</if>
+            <if test="taskDescription != null">task_description = #{taskDescription},</if>
+            <if test="departureAddress != null">departure_address = #{departureAddress},</if>
+            <if test="destinationAddress != null">destination_address = #{destinationAddress},</if>
+            <if test="plannedStartTime != null">planned_start_time = #{plannedStartTime},</if>
+            <if test="plannedEndTime != null">planned_end_time = #{plannedEndTime},</if>
+            <if test="actualStartTime != null">actual_start_time = #{actualStartTime},</if>
+            <if test="actualEndTime != null">actual_end_time = #{actualEndTime},</if>
+            <if test="creatorId != null">creator_id = #{creatorId},</if>
+            <if test="assigneeId != null">assignee_id = #{assigneeId},</if>
+            <if test="deptId != null">dept_id = #{deptId},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="delFlag != null">del_flag = #{delFlag},</if>
+        </trim>
+        where task_id = #{taskId}
+    </update>
+
+    <update id="updateTaskStatus" parameterType="SysTask">
+        update sys_task set 
+            task_status = #{taskStatus},
+            <if test="actualStartTime != null">actual_start_time = #{actualStartTime},</if>
+            <if test="actualEndTime != null">actual_end_time = #{actualEndTime},</if>
+            update_time = now(),
+            update_by = #{updateBy}
+        where task_id = #{taskId}
+    </update>
+
+    <update id="assignTask" parameterType="SysTask">
+        update sys_task set 
+            assignee_id = #{assigneeId},
+            update_time = now(),
+            update_by = #{updateBy}
+        where task_id = #{taskId}
+    </update>
+
+    <delete id="deleteSysTaskByTaskId" parameterType="Long">
+        update sys_task set del_flag = '2' where task_id = #{taskId}
+    </delete>
+
+    <delete id="deleteSysTaskByTaskIds" parameterType="String">
+        update sys_task set del_flag = '2' where task_id in 
+        <foreach item="taskId" collection="array" open="(" separator="," close=")">
+            #{taskId}
+        </foreach>
+    </delete>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysTaskVehicleMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysTaskVehicleMapper.xml
new file mode 100644
index 0000000..e8a3a0f
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysTaskVehicleMapper.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.SysTaskVehicleMapper">
+    
+    <resultMap type="SysTaskVehicle" id="SysTaskVehicleResult">
+        <result property="id"               column="id"               />
+        <result property="taskId"           column="task_id"          />
+        <result property="vehicleId"        column="vehicle_id"       />
+        <result property="assignTime"       column="assign_time"      />
+        <result property="assignBy"         column="assign_by"        />
+        <result property="status"           column="status"           />
+        <result property="remark"           column="remark"           />
+        <result property="vehicleNo"        column="vehicle_no"       />
+        <result property="vehicleType"      column="vehicle_type"     />
+        <result property="vehicleBrand"     column="vehicle_brand"    />
+        <result property="vehicleModel"     column="vehicle_model"    />
+    </resultMap>
+
+    <sql id="selectSysTaskVehicleVo">
+        select tv.id, tv.task_id, tv.vehicle_id, tv.assign_time, tv.assign_by, tv.status, tv.remark,
+               v.vehicle_no, v.vehicle_type, v.vehicle_brand, v.vehicle_model
+        from sys_task_vehicle tv
+        left join tb_vehicle_info v on tv.vehicle_id = v.vehicle_id
+    </sql>
+
+    <select id="selectSysTaskVehicleList" parameterType="SysTaskVehicle" resultMap="SysTaskVehicleResult">
+        <include refid="selectSysTaskVehicleVo"/>
+        <where>  
+            <if test="taskId != null "> and tv.task_id = #{taskId}</if>
+            <if test="vehicleId != null "> and tv.vehicle_id = #{vehicleId}</if>
+            <if test="status != null  and status != ''"> and tv.status = #{status}</if>
+            <if test="assignBy != null  and assignBy != ''"> and tv.assign_by like concat('%', #{assignBy}, '%')</if>
+        </where>
+        order by tv.assign_time desc
+    </select>
+    
+    <select id="selectSysTaskVehicleById" parameterType="Long" resultMap="SysTaskVehicleResult">
+        <include refid="selectSysTaskVehicleVo"/>
+        where tv.id = #{id}
+    </select>
+
+    <select id="selectSysTaskVehicleByTaskId" parameterType="Long" resultMap="SysTaskVehicleResult">
+        <include refid="selectSysTaskVehicleVo"/>
+        where tv.task_id = #{taskId}
+        order by tv.assign_time desc
+    </select>
+
+    <select id="checkTaskVehicleExists" resultType="int">
+        select count(1) from sys_task_vehicle 
+        where task_id = #{taskId} and vehicle_id = #{vehicleId}
+    </select>
+        
+    <insert id="insertSysTaskVehicle" parameterType="SysTaskVehicle" useGeneratedKeys="true" keyProperty="id">
+        insert into sys_task_vehicle
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">task_id,</if>
+            <if test="vehicleId != null">vehicle_id,</if>
+            <if test="assignTime != null">assign_time,</if>
+            <if test="assignBy != null and assignBy != ''">assign_by,</if>
+            <if test="status != null and status != ''">status,</if>
+            <if test="remark != null">remark,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">#{taskId},</if>
+            <if test="vehicleId != null">#{vehicleId},</if>
+            <if test="assignTime != null">#{assignTime},</if>
+            <if test="assignBy != null and assignBy != ''">#{assignBy},</if>
+            <if test="status != null and status != ''">#{status},</if>
+            <if test="remark != null">#{remark},</if>
+         </trim>
+    </insert>
+
+    <insert id="batchInsertSysTaskVehicle" parameterType="java.util.List">
+        insert into sys_task_vehicle (task_id, vehicle_id, assign_time, assign_by, status, remark)
+        values
+        <foreach collection="list" item="item" separator=",">
+            (#{item.taskId}, #{item.vehicleId}, #{item.assignTime}, #{item.assignBy}, #{item.status}, #{item.remark})
+        </foreach>
+    </insert>
+
+    <update id="updateSysTaskVehicle" parameterType="SysTaskVehicle">
+        update sys_task_vehicle
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskId != null">task_id = #{taskId},</if>
+            <if test="vehicleId != null">vehicle_id = #{vehicleId},</if>
+            <if test="assignTime != null">assign_time = #{assignTime},</if>
+            <if test="assignBy != null and assignBy != ''">assign_by = #{assignBy},</if>
+            <if test="status != null and status != ''">status = #{status},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteSysTaskVehicleById" parameterType="Long">
+        delete from sys_task_vehicle where id = #{id}
+    </delete>
+
+    <delete id="deleteSysTaskVehicleByIds" parameterType="String">
+        delete from sys_task_vehicle where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <delete id="deleteSysTaskVehicleByTaskId" parameterType="Long">
+        delete from sys_task_vehicle where task_id = #{taskId}
+    </delete>
+
+    <delete id="deleteSysTaskVehicleByTaskIdAndVehicleId">
+        delete from sys_task_vehicle where task_id = #{taskId} and vehicle_id = #{vehicleId}
+    </delete>
+</mapper>
diff --git a/ruoyi-ui/src/api/task.js b/ruoyi-ui/src/api/task.js
new file mode 100644
index 0000000..abeb5fb
--- /dev/null
+++ b/ruoyi-ui/src/api/task.js
@@ -0,0 +1,159 @@
+import request from '@/utils/request'
+
+// 鏌ヨ浠诲姟绠$悊鍒楄〃
+export function listTask(query) {
+  return request({
+    url: '/task/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ浠诲姟绠$悊璇︾粏
+export function getTask(taskId) {
+  return request({
+    url: '/task/' + taskId,
+    method: 'get'
+  })
+}
+
+// 鏂板浠诲姟绠$悊
+export function addTask(data) {
+  return request({
+    url: '/task',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼浠诲姟绠$悊
+export function updateTask(data) {
+  return request({
+    url: '/task',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎浠诲姟绠$悊
+export function delTask(taskIds) {
+  return request({
+    url: '/task/' + taskIds,
+    method: 'delete'
+  })
+}
+
+// 鍒嗛厤浠诲姟
+export function assignTask(taskId, data) {
+  return request({
+    url: '/task/' + taskId + '/assign',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鏇存柊浠诲姟鐘舵��
+export function changeTaskStatus(taskId, data) {
+  return request({
+    url: '/task/' + taskId + '/status',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鏌ヨ浠诲姟缁熻淇℃伅
+export function getTaskStatistics() {
+  return request({
+    url: '/task/statistics',
+    method: 'get'
+  })
+}
+
+// 鏌ヨ瓒呮椂浠诲姟鍒楄〃
+export function getOverdueTasks() {
+  return request({
+    url: '/task/overdue',
+    method: 'get'
+  })
+}
+
+// 鏌ヨ鎴戠殑浠诲姟鍒楄〃
+export function getMyTasks() {
+  return request({
+    url: '/task/my',
+    method: 'get'
+  })
+}
+
+// 涓婁紶浠诲姟闄勪欢
+export function uploadAttachment(taskId, file) {
+  const formData = new FormData()
+  formData.append('file', file)
+  return request({
+    url: '/task/attachment/upload/' + taskId,
+    method: 'post',
+    data: formData,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  })
+}
+
+// 鍒犻櫎浠诲姟闄勪欢
+export function deleteAttachment(attachmentId) {
+  return request({
+    url: '/task/attachment/' + attachmentId,
+    method: 'delete'
+  })
+}
+
+// 鏌ヨ浠诲姟闄勪欢鍒楄〃
+export function getTaskAttachments(taskId) {
+  return request({
+    url: '/task/attachment/list/' + taskId,
+    method: 'get'
+  })
+}
+
+// 鏌ヨ浠诲姟鍏宠仈鐨勮溅杈嗗垪琛�
+export function getTaskVehicles(taskId) {
+  return request({
+    url: '/task/vehicle/list/' + taskId,
+    method: 'get'
+  })
+}
+
+// 鏌ヨ鍙敤杞﹁締鍒楄〃
+export function getAvailableVehicles(deptId, taskType) {
+  return request({
+    url: '/task/vehicle/available',
+    method: 'get',
+    params: { deptId, taskType }
+  })
+}
+
+// 鍒嗛厤杞﹁締缁欎换鍔�
+export function assignVehicleToTask(taskId, data) {
+  return request({
+    url: '/task/vehicle/assign/' + taskId,
+    method: 'post',
+    data: data
+  })
+}
+
+// 鎵归噺鍒嗛厤杞﹁締缁欎换鍔�
+export function assignVehiclesToTask(taskId, data) {
+  return request({
+    url: '/task/vehicle/assign-batch/' + taskId,
+    method: 'post',
+    data: data
+  })
+}
+
+// 鍙栨秷浠诲姟杞﹁締鍒嗛厤
+export function unassignVehicleFromTask(taskId, vehicleId) {
+  return request({
+    url: '/task/vehicle/' + taskId + '/' + vehicleId,
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index bf8f5be..41e0f28 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -197,6 +197,20 @@
         meta: { title: '淇敼鐢熸垚閰嶇疆', activeMenu: '/tool/gen' }
       }
     ]
+  },
+  {
+    path: '/task/general-detail',
+    component: Layout,
+    hidden: true,
+    permissions: ['task:general:query'],
+    children: [
+      {
+        path: 'index/:taskId(\\d+)',
+        component: () => import('@/views/task/general/detail'),
+        name: 'TaskDetail',
+        meta: { title: '浠诲姟璇︽儏', activeMenu: '/task/general' }
+      }
+    ]
   }
 ]
 
diff --git a/ruoyi-ui/src/views/task/general/detail.vue b/ruoyi-ui/src/views/task/general/detail.vue
new file mode 100644
index 0000000..99fd176
--- /dev/null
+++ b/ruoyi-ui/src/views/task/general/detail.vue
@@ -0,0 +1,564 @@
+<template>
+  <div class="app-container">
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <span>浠诲姟璇︽儏</span>
+        <el-button style="float: right; padding: 3px 0" type="text" @click="goBack">杩斿洖</el-button>
+      </div>
+      
+      <!-- 鍩烘湰淇℃伅 -->
+      <el-descriptions title="鍩烘湰淇℃伅" :column="2" border>
+        <el-descriptions-item label="浠诲姟缂栧彿">{{ taskDetail.taskCode }}</el-descriptions-item>
+        <el-descriptions-item label="浠诲姟绫诲瀷">
+          <dict-tag :options="dict.type.sys_task_type" :value="taskDetail.taskType"/>
+        </el-descriptions-item>
+        <el-descriptions-item label="浠诲姟鐘舵��">
+          <dict-tag :options="dict.type.sys_task_status" :value="taskDetail.taskStatus"/>
+        </el-descriptions-item>
+        <el-descriptions-item label="鍒涘缓浜�">{{ taskDetail.creatorName }}</el-descriptions-item>
+        <el-descriptions-item label="鎵ц浜�">{{ taskDetail.assigneeName }}</el-descriptions-item>
+        <el-descriptions-item label="閮ㄩ棬">{{ taskDetail.deptName }}</el-descriptions-item>
+        <el-descriptions-item label="浠诲姟鎻忚堪" :span="2">{{ taskDetail.taskDescription }}</el-descriptions-item>
+        <el-descriptions-item label="鍑哄彂鍦板潃" :span="2">{{ taskDetail.departureAddress }}</el-descriptions-item>
+        <el-descriptions-item label="鐩殑鍦板潃" :span="2">{{ taskDetail.destinationAddress }}</el-descriptions-item>
+        <el-descriptions-item label="璁″垝寮�濮嬫椂闂�">{{ parseTime(taskDetail.plannedStartTime) }}</el-descriptions-item>
+        <el-descriptions-item label="璁″垝缁撴潫鏃堕棿">{{ parseTime(taskDetail.plannedEndTime) }}</el-descriptions-item>
+        <el-descriptions-item label="瀹為檯寮�濮嬫椂闂�">{{ parseTime(taskDetail.actualStartTime) }}</el-descriptions-item>
+        <el-descriptions-item label="瀹為檯缁撴潫鏃堕棿">{{ parseTime(taskDetail.actualEndTime) }}</el-descriptions-item>
+        <el-descriptions-item label="鍒涘缓鏃堕棿">{{ parseTime(taskDetail.createTime) }}</el-descriptions-item>
+        <el-descriptions-item label="鏇存柊鏃堕棿">{{ parseTime(taskDetail.updateTime) }}</el-descriptions-item>
+        <el-descriptions-item label="澶囨敞" :span="2">{{ taskDetail.remark }}</el-descriptions-item>
+      </el-descriptions>
+
+      <!-- 鎿嶄綔鎸夐挳 -->
+      <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>
+    </el-card>
+
+    <!-- 鍏宠仈杞﹁締 -->
+    <el-card class="box-card" style="margin-top: 20px;">
+      <div slot="header" class="clearfix">
+        <span>鍏宠仈杞﹁締</span>
+        <el-button style="float: right; padding: 3px 0" type="text" @click="handleVehicleAssign" v-hasPermi="['task:general:assign']">鍒嗛厤杞﹁締</el-button>
+      </div>
+      
+      <el-table :data="taskDetail.assignedVehicles" v-loading="vehicleLoading">
+        <el-table-column label="杞︾墝鍙�" align="center" prop="vehicleNo" />
+        <el-table-column label="杞﹁締绫诲瀷" align="center" prop="vehicleType">
+          <template slot-scope="scope">
+            <dict-tag :options="dict.type.sys_vehicle_type" :value="scope.row.vehicleType"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="杞﹁締鍝佺墝" align="center" prop="vehicleBrand" />
+        <el-table-column label="杞﹁締鍨嬪彿" align="center" prop="vehicleModel" />
+        <el-table-column label="鍒嗛厤鏃堕棿" align="center" prop="assignTime" width="180">
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.assignTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍒嗛厤浜�" align="center" prop="assignBy" />
+        <el-table-column label="鐘舵��" align="center" prop="status">
+          <template slot-scope="scope">
+            <dict-tag :options="dict.type.sys_task_vehicle_status" :value="scope.row.status"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleUnassignVehicle(scope.row)"
+              v-hasPermi="['task:general:assign']"
+            >鍙栨秷鍒嗛厤</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <!-- 浠诲姟闄勪欢 -->
+    <el-card class="box-card" style="margin-top: 20px;">
+      <div slot="header" class="clearfix">
+        <span>浠诲姟闄勪欢</span>
+        <el-button style="float: right; padding: 3px 0" type="text" @click="handleUpload" v-hasPermi="['task:general:edit']">涓婁紶闄勪欢</el-button>
+      </div>
+      
+      <el-table :data="taskDetail.attachments" v-loading="attachmentLoading">
+        <el-table-column label="鏂囦欢鍚�" align="center" prop="fileName" />
+        <el-table-column label="鏂囦欢绫诲瀷" align="center" prop="fileType" />
+        <el-table-column label="鏂囦欢澶у皬" align="center" prop="fileSize">
+          <template slot-scope="scope">
+            <span>{{ formatFileSize(scope.row.fileSize) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="涓婁紶鏃堕棿" align="center" prop="uploadTime" width="180">
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.uploadTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="涓婁紶鑰�" align="center" prop="uploadBy" />
+        <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-download"
+              @click="handleDownload(scope.row)"
+            >涓嬭浇</el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDeleteAttachment(scope.row)"
+              v-hasPermi="['task:general:edit']"
+            >鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <!-- 鎿嶄綔鏃ュ織 -->
+    <el-card class="box-card" style="margin-top: 20px;">
+      <div slot="header" class="clearfix">
+        <span>鎿嶄綔鏃ュ織</span>
+      </div>
+      
+      <el-timeline>
+        <el-timeline-item
+          v-for="log in taskDetail.operationLogs"
+          :key="log.logId"
+          :timestamp="parseTime(log.operationTime)"
+          placement="top"
+        >
+          <el-card>
+            <h4>{{ log.operationDesc }}</h4>
+            <p>鎿嶄綔浜猴細{{ log.operatorName }}</p>
+            <p v-if="log.oldValue">鎿嶄綔鍓嶏細{{ log.oldValue }}</p>
+            <p v-if="log.newValue">鎿嶄綔鍚庯細{{ log.newValue }}</p>
+          </el-card>
+        </el-timeline-item>
+      </el-timeline>
+    </el-card>
+
+    <!-- 缂栬緫浠诲姟瀵硅瘽妗� -->
+    <el-dialog :title="'缂栬緫浠诲姟'" :visible.sync="editOpen" width="600px" append-to-body>
+      <el-form ref="editForm" :model="editForm" :rules="editRules" label-width="80px">
+        <el-form-item label="浠诲姟鎻忚堪" prop="taskDescription">
+          <el-input v-model="editForm.taskDescription" type="textarea" placeholder="璇疯緭鍏ヤ换鍔℃弿杩�" />
+        </el-form-item>
+        <el-form-item label="鍑哄彂鍦板潃" prop="departureAddress">
+          <el-input v-model="editForm.departureAddress" placeholder="璇疯緭鍏ュ嚭鍙戝湴鍧�" />
+        </el-form-item>
+        <el-form-item label="鐩殑鍦板潃" prop="destinationAddress">
+          <el-input v-model="editForm.destinationAddress" placeholder="璇疯緭鍏ョ洰鐨勫湴鍧�" />
+        </el-form-item>
+        <el-form-item label="璁″垝寮�濮嬫椂闂�" prop="plannedStartTime">
+          <el-date-picker clearable
+            v-model="editForm.plannedStartTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            placeholder="璇烽�夋嫨璁″垝寮�濮嬫椂闂�">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="璁″垝缁撴潫鏃堕棿" prop="plannedEndTime">
+          <el-date-picker clearable
+            v-model="editForm.plannedEndTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            placeholder="璇烽�夋嫨璁″垝缁撴潫鏃堕棿">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="鎵ц浜�" prop="assigneeId">
+          <el-select v-model="editForm.assigneeId" placeholder="璇烽�夋嫨鎵ц浜�" clearable>
+            <el-option
+              v-for="user in userList"
+              :key="user.userId"
+              :label="user.nickName"
+              :value="user.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="editForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitEdit">纭� 瀹�</el-button>
+        <el-button @click="cancelEdit">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 鍒嗛厤浠诲姟瀵硅瘽妗� -->
+    <el-dialog title="鍒嗛厤浠诲姟" :visible.sync="assignOpen" width="500px" append-to-body>
+      <el-form ref="assignForm" :model="assignForm" :rules="assignRules" label-width="80px">
+        <el-form-item label="鎵ц浜�" prop="assigneeId">
+          <el-select v-model="assignForm.assigneeId" placeholder="璇烽�夋嫨鎵ц浜�" clearable>
+            <el-option
+              v-for="user in userList"
+              :key="user.userId"
+              :label="user.nickName"
+              :value="user.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="assignForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitAssign">纭� 瀹�</el-button>
+        <el-button @click="cancelAssign">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 鐘舵�佸彉鏇村璇濇 -->
+    <el-dialog title="鐘舵�佸彉鏇�" :visible.sync="statusOpen" width="500px" append-to-body>
+      <el-form ref="statusForm" :model="statusForm" :rules="statusRules" label-width="80px">
+        <el-form-item label="浠诲姟鐘舵��" prop="taskStatus">
+          <el-select v-model="statusForm.taskStatus" placeholder="璇烽�夋嫨浠诲姟鐘舵��">
+            <el-option
+              v-for="dict in dict.type.sys_task_status"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="statusForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitStatusChange">纭� 瀹�</el-button>
+        <el-button @click="cancelStatusChange">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 鍒嗛厤杞﹁締瀵硅瘽妗� -->
+    <el-dialog title="鍒嗛厤杞﹁締" :visible.sync="vehicleAssignOpen" width="600px" append-to-body>
+      <el-form ref="vehicleAssignForm" :model="vehicleAssignForm" :rules="vehicleAssignRules" label-width="80px">
+        <el-form-item label="杞﹁締" prop="vehicleIds">
+          <el-select v-model="vehicleAssignForm.vehicleIds" placeholder="璇烽�夋嫨杞﹁締" multiple clearable>
+            <el-option
+              v-for="vehicle in availableVehicles"
+              :key="vehicle.vehicleId"
+              :label="vehicle.vehicleNo + ' (' + vehicle.vehicleType + ')'"
+              :value="vehicle.vehicleId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="vehicleAssignForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitVehicleAssign">纭� 瀹�</el-button>
+        <el-button @click="cancelVehicleAssign">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 涓婁紶闄勪欢瀵硅瘽妗� -->
+    <el-dialog title="涓婁紶闄勪欢" :visible.sync="uploadOpen" width="500px" append-to-body>
+      <el-upload
+        class="upload-demo"
+        drag
+        :action="uploadUrl"
+        :headers="uploadHeaders"
+        :data="uploadData"
+        :on-success="handleUploadSuccess"
+        :on-error="handleUploadError"
+        :before-upload="beforeUpload"
+        multiple>
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+        <div class="el-upload__tip" slot="tip">鍙兘涓婁紶jpg/png/pdf/doc/docx鏂囦欢锛屼笖涓嶈秴杩�10MB</div>
+      </el-upload>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getTask, updateTask, assignTask, changeTaskStatus, uploadAttachment, deleteAttachment, getTaskVehicles, getAvailableVehicles, assignVehiclesToTask, unassignVehicleFromTask } from "@/api/task";
+import { listUser } from "@/api/system/user";
+import { getToken } from "@/utils/auth";
+
+export default {
+  name: "TaskDetail",
+  dicts: ['sys_task_type', 'sys_task_status', 'sys_vehicle_type', 'sys_task_vehicle_status'],
+  data() {
+    return {
+      // 浠诲姟璇︽儏
+      taskDetail: {
+        assignedVehicles: [],
+        attachments: [],
+        operationLogs: []
+      },
+      // 鏄惁鏄剧ず缂栬緫瀵硅瘽妗�
+      editOpen: false,
+      // 鏄惁鏄剧ず鍒嗛厤瀵硅瘽妗�
+      assignOpen: false,
+      // 鏄惁鏄剧ず鐘舵�佸彉鏇村璇濇
+      statusOpen: false,
+      // 鏄惁鏄剧ず杞﹁締鍒嗛厤瀵硅瘽妗�
+      vehicleAssignOpen: false,
+      // 鏄惁鏄剧ず涓婁紶瀵硅瘽妗�
+      uploadOpen: false,
+      // 缂栬緫琛ㄥ崟
+      editForm: {},
+      // 鍒嗛厤琛ㄥ崟
+      assignForm: {},
+      // 鐘舵�佸彉鏇磋〃鍗�
+      statusForm: {},
+      // 杞﹁締鍒嗛厤琛ㄥ崟
+      vehicleAssignForm: {},
+      // 鐢ㄦ埛鍒楄〃
+      userList: [],
+      // 鍙敤杞﹁締鍒楄〃
+      availableVehicles: [],
+      // 鍔犺浇鐘舵��
+      vehicleLoading: false,
+      attachmentLoading: false,
+      // 涓婁紶鐩稿叧
+      uploadUrl: process.env.VUE_APP_BASE_API + "/task/attachment/upload/" + this.$route.params.taskId,
+      uploadHeaders: {
+        Authorization: "Bearer " + getToken()
+      },
+      uploadData: {},
+      // 琛ㄥ崟鏍¢獙
+      editRules: {
+        taskDescription: [
+          { required: true, message: "浠诲姟鎻忚堪涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        plannedStartTime: [
+          { required: true, message: "璁″垝寮�濮嬫椂闂翠笉鑳戒负绌�", trigger: "blur" }
+        ],
+        plannedEndTime: [
+          { required: true, message: "璁″垝缁撴潫鏃堕棿涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      },
+      assignRules: {
+        assigneeId: [
+          { required: true, message: "鎵ц浜轰笉鑳戒负绌�", trigger: "change" }
+        ]
+      },
+      statusRules: {
+        taskStatus: [
+          { required: true, message: "浠诲姟鐘舵�佷笉鑳戒负绌�", trigger: "change" }
+        ]
+      },
+      vehicleAssignRules: {
+        vehicleIds: [
+          { required: true, message: "杞﹁締涓嶈兘涓虹┖", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getTaskDetail();
+    this.getUserList();
+  },
+  methods: {
+    /** 鑾峰彇浠诲姟璇︽儏 */
+    getTaskDetail() {
+      getTask(this.$route.params.taskId).then(response => {
+        this.taskDetail = response.data;
+      });
+    },
+    /** 鑾峰彇鐢ㄦ埛鍒楄〃 */
+    getUserList() {
+      listUser().then(response => {
+        this.userList = response.rows;
+      });
+    },
+    /** 鑾峰彇鍙敤杞﹁締鍒楄〃 */
+    getAvailableVehicleList() {
+      getAvailableVehicles(this.taskDetail.deptId, this.taskDetail.taskType).then(response => {
+        this.availableVehicles = response.data;
+      });
+    },
+    /** 杩斿洖 */
+    goBack() {
+      this.$router.go(-1);
+    },
+    /** 缂栬緫浠诲姟 */
+    handleEdit() {
+      this.editForm = {
+        taskId: this.taskDetail.taskId,
+        taskDescription: this.taskDetail.taskDescription,
+        departureAddress: this.taskDetail.departureAddress,
+        destinationAddress: this.taskDetail.destinationAddress,
+        plannedStartTime: this.taskDetail.plannedStartTime,
+        plannedEndTime: this.taskDetail.plannedEndTime,
+        assigneeId: this.taskDetail.assigneeId,
+        remark: this.taskDetail.remark
+      };
+      this.editOpen = true;
+    },
+    /** 鍒嗛厤浠诲姟 */
+    handleAssign() {
+      this.assignForm = {
+        taskId: this.taskDetail.taskId,
+        assigneeId: this.taskDetail.assigneeId,
+        remark: null
+      };
+      this.assignOpen = true;
+    },
+    /** 鐘舵�佸彉鏇� */
+    handleStatusChange() {
+      this.statusForm = {
+        taskId: this.taskDetail.taskId,
+        taskStatus: this.taskDetail.taskStatus,
+        remark: null
+      };
+      this.statusOpen = true;
+    },
+    /** 鍒嗛厤杞﹁締 */
+    handleVehicleAssign() {
+      this.getAvailableVehicleList();
+      this.vehicleAssignForm = {
+        taskId: this.taskDetail.taskId,
+        vehicleIds: [],
+        remark: null
+      };
+      this.vehicleAssignOpen = true;
+    },
+    /** 涓婁紶闄勪欢 */
+    handleUpload() {
+      this.uploadOpen = true;
+    },
+    /** 鍙栨秷杞﹁締鍒嗛厤 */
+    handleUnassignVehicle(row) {
+      this.$modal.confirm('鏄惁纭鍙栨秷杞﹁締"' + row.vehicleNo + '"鐨勫垎閰嶏紵').then(() => {
+        return unassignVehicleFromTask(this.taskDetail.taskId, row.vehicleId);
+      }).then(() => {
+        this.$modal.msgSuccess("鍙栨秷鍒嗛厤鎴愬姛");
+        this.getTaskDetail();
+      }).catch(() => {});
+    },
+    /** 涓嬭浇闄勪欢 */
+    handleDownload(row) {
+      window.open(row.filePath);
+    },
+    /** 鍒犻櫎闄勪欢 */
+    handleDeleteAttachment(row) {
+      this.$modal.confirm('鏄惁纭鍒犻櫎闄勪欢"' + row.fileName + '"锛�').then(() => {
+        return deleteAttachment(row.attachmentId);
+      }).then(() => {
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        this.getTaskDetail();
+      }).catch(() => {});
+    },
+    /** 鎻愪氦缂栬緫 */
+    submitEdit() {
+      this.$refs["editForm"].validate(valid => {
+        if (valid) {
+          updateTask(this.editForm).then(response => {
+            this.$modal.msgSuccess("淇敼鎴愬姛");
+            this.editOpen = false;
+            this.getTaskDetail();
+          });
+        }
+      });
+    },
+    /** 鎻愪氦鍒嗛厤 */
+    submitAssign() {
+      this.$refs["assignForm"].validate(valid => {
+        if (valid) {
+          assignTask(this.assignForm.taskId, this.assignForm).then(response => {
+            this.$modal.msgSuccess("鍒嗛厤鎴愬姛");
+            this.assignOpen = false;
+            this.getTaskDetail();
+          });
+        }
+      });
+    },
+    /** 鎻愪氦鐘舵�佸彉鏇� */
+    submitStatusChange() {
+      this.$refs["statusForm"].validate(valid => {
+        if (valid) {
+          changeTaskStatus(this.statusForm.taskId, this.statusForm).then(response => {
+            this.$modal.msgSuccess("鐘舵�佸彉鏇存垚鍔�");
+            this.statusOpen = false;
+            this.getTaskDetail();
+          });
+        }
+      });
+    },
+    /** 鎻愪氦杞﹁締鍒嗛厤 */
+    submitVehicleAssign() {
+      this.$refs["vehicleAssignForm"].validate(valid => {
+        if (valid) {
+          assignVehiclesToTask(this.vehicleAssignForm.taskId, this.vehicleAssignForm).then(response => {
+            this.$modal.msgSuccess("鍒嗛厤鎴愬姛");
+            this.vehicleAssignOpen = false;
+            this.getTaskDetail();
+          });
+        }
+      });
+    },
+    /** 鍙栨秷缂栬緫 */
+    cancelEdit() {
+      this.editOpen = false;
+      this.editForm = {};
+    },
+    /** 鍙栨秷鍒嗛厤 */
+    cancelAssign() {
+      this.assignOpen = false;
+      this.assignForm = {};
+    },
+    /** 鍙栨秷鐘舵�佸彉鏇� */
+    cancelStatusChange() {
+      this.statusOpen = false;
+      this.statusForm = {};
+    },
+    /** 鍙栨秷杞﹁締鍒嗛厤 */
+    cancelVehicleAssign() {
+      this.vehicleAssignOpen = false;
+      this.vehicleAssignForm = {};
+    },
+    /** 涓婁紶鍓嶆鏌� */
+    beforeUpload(file) {
+      const isValidType = ['image/jpeg', 'image/png', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'].includes(file.type);
+      const isLt10M = file.size / 1024 / 1024 < 10;
+
+      if (!isValidType) {
+        this.$message.error('鍙兘涓婁紶 JPG/PNG/PDF/DOC/DOCX 鏍煎紡鐨勬枃浠�!');
+      }
+      if (!isLt10M) {
+        this.$message.error('涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 10MB!');
+      }
+      return isValidType && isLt10M;
+    },
+    /** 涓婁紶鎴愬姛 */
+    handleUploadSuccess(response, file, fileList) {
+      this.$modal.msgSuccess("涓婁紶鎴愬姛");
+      this.uploadOpen = false;
+      this.getTaskDetail();
+    },
+    /** 涓婁紶澶辫触 */
+    handleUploadError(err, file, fileList) {
+      this.$modal.msgError("涓婁紶澶辫触");
+    },
+    /** 鏍煎紡鍖栨枃浠跺ぇ灏� */
+    formatFileSize(size) {
+      if (size < 1024) {
+        return size + ' B';
+      } else if (size < 1024 * 1024) {
+        return (size / 1024).toFixed(2) + ' KB';
+      } else {
+        return (size / 1024 / 1024).toFixed(2) + ' MB';
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+.box-card {
+  margin-bottom: 20px;
+}
+</style>
diff --git a/ruoyi-ui/src/views/task/general/index.vue b/ruoyi-ui/src/views/task/general/index.vue
new file mode 100644
index 0000000..9feb3cb
--- /dev/null
+++ b/ruoyi-ui/src/views/task/general/index.vue
@@ -0,0 +1,535 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="浠诲姟缂栧彿" prop="taskCode">
+        <el-input
+          v-model="queryParams.taskCode"
+          placeholder="璇疯緭鍏ヤ换鍔$紪鍙�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="浠诲姟绫诲瀷" prop="taskType">
+        <el-select v-model="queryParams.taskType" placeholder="璇烽�夋嫨浠诲姟绫诲瀷" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_task_type"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="浠诲姟鐘舵��" prop="taskStatus">
+        <el-select v-model="queryParams.taskStatus" placeholder="璇烽�夋嫨浠诲姟鐘舵��" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_task_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="璁″垝寮�濮嬫椂闂�">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['task:general:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['task:general:edit']"
+        >淇敼</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['task:general:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['task:general:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <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" />
+      <el-table-column label="浠诲姟绫诲瀷" align="center" prop="taskType">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_task_type" :value="scope.row.taskType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="浠诲姟鐘舵��" align="center" prop="taskStatus">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_task_status" :value="scope.row.taskStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="浠诲姟鎻忚堪" align="center" prop="taskDescription" show-overflow-tooltip />
+      <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="plannedStartTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.plannedStartTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="璁″垝缁撴潫鏃堕棿" align="center" prop="plannedEndTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.plannedEndTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <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>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleView(scope.row)"
+            v-hasPermi="['task:general:query']"
+          >鏌ョ湅</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
+            size="mini"
+            type="text"
+            icon="el-icon-user"
+            @click="handleAssign(scope.row)"
+            v-hasPermi="['task:general:assign']"
+          >鍒嗛厤</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
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['task:general:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀逛换鍔$鐞嗗璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="浠诲姟绫诲瀷" prop="taskType">
+          <el-select v-model="form.taskType" placeholder="璇烽�夋嫨浠诲姟绫诲瀷">
+            <el-option
+              v-for="dict in dict.type.sys_task_type"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="浠诲姟鎻忚堪" prop="taskDescription">
+          <el-input v-model="form.taskDescription" type="textarea" placeholder="璇疯緭鍏ヤ换鍔℃弿杩�" />
+        </el-form-item>
+        <el-form-item label="鍑哄彂鍦板潃" prop="departureAddress">
+          <el-input v-model="form.departureAddress" placeholder="璇疯緭鍏ュ嚭鍙戝湴鍧�" />
+        </el-form-item>
+        <el-form-item label="鐩殑鍦板潃" prop="destinationAddress">
+          <el-input v-model="form.destinationAddress" placeholder="璇疯緭鍏ョ洰鐨勫湴鍧�" />
+        </el-form-item>
+        <el-form-item label="璁″垝寮�濮嬫椂闂�" prop="plannedStartTime">
+          <el-date-picker clearable
+            v-model="form.plannedStartTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            placeholder="璇烽�夋嫨璁″垝寮�濮嬫椂闂�">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="璁″垝缁撴潫鏃堕棿" prop="plannedEndTime">
+          <el-date-picker clearable
+            v-model="form.plannedEndTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            placeholder="璇烽�夋嫨璁″垝缁撴潫鏃堕棿">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="鎵ц浜�" prop="assigneeId">
+          <el-select v-model="form.assigneeId" placeholder="璇烽�夋嫨鎵ц浜�" clearable>
+            <el-option
+              v-for="user in userList"
+              :key="user.userId"
+              :label="user.nickName"
+              :value="user.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+
+    <!-- 浠诲姟鍒嗛厤瀵硅瘽妗� -->
+    <el-dialog title="浠诲姟鍒嗛厤" :visible.sync="assignOpen" width="500px" append-to-body>
+      <el-form ref="assignForm" :model="assignForm" :rules="assignRules" label-width="80px">
+        <el-form-item label="鎵ц浜�" prop="assigneeId">
+          <el-select v-model="assignForm.assigneeId" placeholder="璇烽�夋嫨鎵ц浜�" clearable>
+            <el-option
+              v-for="user in userList"
+              :key="user.userId"
+              :label="user.nickName"
+              :value="user.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="assignForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitAssign">纭� 瀹�</el-button>
+        <el-button @click="cancelAssign">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 鐘舵�佸彉鏇村璇濇 -->
+    <el-dialog title="鐘舵�佸彉鏇�" :visible.sync="statusOpen" width="500px" append-to-body>
+      <el-form ref="statusForm" :model="statusForm" :rules="statusRules" label-width="80px">
+        <el-form-item label="浠诲姟鐘舵��" prop="taskStatus">
+          <el-select v-model="statusForm.taskStatus" placeholder="璇烽�夋嫨浠诲姟鐘舵��">
+            <el-option
+              v-for="dict in dict.type.sys_task_status"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="statusForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitStatusChange">纭� 瀹�</el-button>
+        <el-button @click="cancelStatusChange">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listTask, getTask, delTask, addTask, updateTask, assignTask, changeTaskStatus } from "@/api/task";
+import { listUser } from "@/api/system/user";
+
+export default {
+  name: "Task",
+  dicts: ['sys_task_type', 'sys_task_status'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 浠诲姟绠$悊琛ㄦ牸鏁版嵁
+      taskList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁鏄剧ず鍒嗛厤寮瑰嚭灞�
+      assignOpen: false,
+      // 鏄惁鏄剧ず鐘舵�佸彉鏇村脊鍑哄眰
+      statusOpen: false,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        taskCode: null,
+        taskType: null,
+        taskStatus: null,
+        plannedStartTimeBegin: null,
+        plannedStartTimeEnd: null,
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 鍒嗛厤琛ㄥ崟
+      assignForm: {},
+      // 鐘舵�佸彉鏇磋〃鍗�
+      statusForm: {},
+      // 鐢ㄦ埛鍒楄〃
+      userList: [],
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        taskType: [
+          { required: true, message: "浠诲姟绫诲瀷涓嶈兘涓虹┖", trigger: "change" }
+        ],
+        taskDescription: [
+          { required: true, message: "浠诲姟鎻忚堪涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        plannedStartTime: [
+          { required: true, message: "璁″垝寮�濮嬫椂闂翠笉鑳戒负绌�", trigger: "blur" }
+        ],
+        plannedEndTime: [
+          { required: true, message: "璁″垝缁撴潫鏃堕棿涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      },
+      // 鍒嗛厤琛ㄥ崟鏍¢獙
+      assignRules: {
+        assigneeId: [
+          { required: true, message: "鎵ц浜轰笉鑳戒负绌�", trigger: "change" }
+        ]
+      },
+      // 鐘舵�佸彉鏇磋〃鍗曟牎楠�
+      statusRules: {
+        taskStatus: [
+          { required: true, message: "浠诲姟鐘舵�佷笉鑳戒负绌�", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getUserList();
+  },
+  methods: {
+    /** 鏌ヨ浠诲姟绠$悊鍒楄〃 */
+    getList() {
+      this.loading = true;
+      if (this.dateRange != null && this.dateRange.length === 2) {
+        this.queryParams.plannedStartTimeBegin = this.dateRange[0];
+        this.queryParams.plannedStartTimeEnd = this.dateRange[1];
+      }
+      listTask(this.queryParams).then(response => {
+        this.taskList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 鏌ヨ鐢ㄦ埛鍒楄〃 */
+    getUserList() {
+      listUser().then(response => {
+        this.userList = response.rows;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        taskId: null,
+        taskType: null,
+        taskDescription: null,
+        departureAddress: null,
+        destinationAddress: null,
+        plannedStartTime: null,
+        plannedEndTime: null,
+        assigneeId: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.taskId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞浠诲姟绠$悊";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const taskId = row.taskId || this.ids
+      getTask(taskId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼浠诲姟绠$悊";
+      });
+    },
+    /** 鏌ョ湅鎸夐挳鎿嶄綔 */
+    handleView(row) {
+      this.$router.push('/task/general-detail/index/' + row.taskId);
+    },
+    /** 鍒嗛厤鎸夐挳鎿嶄綔 */
+    handleAssign(row) {
+      this.assignForm = {
+        taskId: row.taskId,
+        assigneeId: row.assigneeId,
+        remark: null
+      };
+      this.assignOpen = true;
+    },
+    /** 鐘舵�佸彉鏇存寜閽搷浣� */
+    handleStatusChange(row) {
+      this.statusForm = {
+        taskId: row.taskId,
+        taskStatus: row.taskStatus,
+        remark: null
+      };
+      this.statusOpen = true;
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.taskId != null) {
+            updateTask(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addTask(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鎻愪氦鍒嗛厤 */
+    submitAssign() {
+      this.$refs["assignForm"].validate(valid => {
+        if (valid) {
+          assignTask(this.assignForm.taskId, this.assignForm).then(response => {
+            this.$modal.msgSuccess("鍒嗛厤鎴愬姛");
+            this.assignOpen = false;
+            this.getList();
+          });
+        }
+      });
+    },
+    /** 鎻愪氦鐘舵�佸彉鏇� */
+    submitStatusChange() {
+      this.$refs["statusForm"].validate(valid => {
+        if (valid) {
+          changeTaskStatus(this.statusForm.taskId, this.statusForm).then(response => {
+            this.$modal.msgSuccess("鐘舵�佸彉鏇存垚鍔�");
+            this.statusOpen = false;
+            this.getList();
+          });
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const taskIds = row.taskId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎浠诲姟绠$悊缂栧彿涓�"' + taskIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delTask(taskIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('task/export', {
+        ...this.queryParams
+      }, `task_${new Date().getTime()}.xlsx`)
+    },
+    /** 鍙栨秷鍒嗛厤 */
+    cancelAssign() {
+      this.assignOpen = false;
+      this.assignForm = {};
+    },
+    /** 鍙栨秷鐘舵�佸彉鏇� */
+    cancelStatusChange() {
+      this.statusOpen = false;
+      this.statusForm = {};
+    }
+  }
+};
+</script>
diff --git a/sql/task_dict_data.sql b/sql/task_dict_data.sql
new file mode 100644
index 0000000..cad5c34
--- /dev/null
+++ b/sql/task_dict_data.sql
@@ -0,0 +1,39 @@
+-- ----------------------------
+-- 閫氱敤浠诲姟绠$悊鏁版嵁瀛楀吀
+-- ----------------------------
+
+-- 1. 浠诲姟绫诲瀷瀛楀吀
+-- ----------------------------
+INSERT INTO sys_dict_type VALUES ('sys_task_type', '浠诲姟绫诲瀷', '0', 'admin', sysdate(), '', null, '浠诲姟绫诲瀷鍒楄〃');
+INSERT INTO sys_dict_data VALUES (1, 1, '缁翠慨淇濆吇', 'MAINTENANCE', 'sys_task_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '缁翠慨淇濆吇浠诲姟');
+INSERT INTO sys_dict_data VALUES (2, 2, '鍔犳补浠诲姟', 'FUEL', 'sys_task_type', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '鍔犳补浠诲姟');
+INSERT INTO sys_dict_data VALUES (3, 3, '鍏朵粬', 'OTHER', 'sys_task_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '鍏朵粬绫诲瀷浠诲姟');
+
+-- 2. 浠诲姟鐘舵�佸瓧鍏�
+-- ----------------------------
+INSERT INTO sys_dict_type VALUES ('sys_task_status', '浠诲姟鐘舵��', '0', 'admin', sysdate(), '', null, '浠诲姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_data VALUES (4, 1, '寰呭紑濮�', 'PENDING', 'sys_task_status', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '浠诲姟宸插垱寤猴紝绛夊緟寮�濮�');
+INSERT INTO sys_dict_data VALUES (5, 2, '浠诲姟涓�', 'IN_PROGRESS', 'sys_task_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '浠诲姟宸茬粡寮�濮�');
+INSERT INTO sys_dict_data VALUES (6, 3, '宸插畬鎴�', 'COMPLETED', 'sys_task_status', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '浠诲姟宸插畬鎴�');
+INSERT INTO sys_dict_data VALUES (7, 4, '宸插彇娑�', 'CANCELLED', 'sys_task_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '浠诲姟宸插彇娑�');
+
+-- 3. 杞﹁締绫诲瀷瀛楀吀
+-- ----------------------------
+INSERT INTO sys_dict_type VALUES ('sys_vehicle_type', '杞﹁締绫诲瀷', '0', 'admin', sysdate(), '', null, '杞﹁締绫诲瀷鍒楄〃');
+INSERT INTO sys_dict_data VALUES (8, 1, '鏁戞姢杞�', 'AMBULANCE', 'sys_vehicle_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '鏁戞姢杞�');
+INSERT INTO sys_dict_data VALUES (9, 2, '杞繍杞�', 'TRANSFER', 'sys_vehicle_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '杞繍杞�');
+INSERT INTO sys_dict_data VALUES (10, 3, '缁翠慨杞�', 'MAINTENANCE', 'sys_vehicle_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '缁翠慨杞�');
+
+-- 4. 杞﹁締鐘舵�佸瓧鍏�
+-- ----------------------------
+INSERT INTO sys_dict_type VALUES ('sys_vehicle_status', '杞﹁締鐘舵��', '0', 'admin', sysdate(), '', null, '杞﹁締鐘舵�佸垪琛�');
+INSERT INTO sys_dict_data VALUES (11, 1, '姝e父', '0', 'sys_vehicle_status', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締姝e父浣跨敤');
+INSERT INTO sys_dict_data VALUES (12, 2, '鍋滅敤', '1', 'sys_vehicle_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締鍋滅敤');
+
+-- 5. 浠诲姟杞﹁締鍏宠仈鐘舵�佸瓧鍏�
+-- ----------------------------
+INSERT INTO sys_dict_type VALUES ('sys_task_vehicle_status', '浠诲姟杞﹁締鍏宠仈鐘舵��', '0', 'admin', sysdate(), '', null, '浠诲姟杞﹁締鍏宠仈鐘舵�佸垪琛�');
+INSERT INTO sys_dict_data VALUES (15, 1, '宸插垎閰�', 'ASSIGNED', 'sys_task_vehicle_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締宸插垎閰嶇粰浠诲姟');
+INSERT INTO sys_dict_data VALUES (16, 2, '鎵ц涓�', 'ACTIVE', 'sys_task_vehicle_status', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締姝e湪鎵ц浠诲姟');
+INSERT INTO sys_dict_data VALUES (17, 3, '宸插畬鎴�', 'COMPLETED', 'sys_task_vehicle_status', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締浠诲姟宸插畬鎴�');
+INSERT INTO sys_dict_data VALUES (18, 4, '宸插彇娑�', 'CANCELLED', 'sys_task_vehicle_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '杞﹁締浠诲姟宸插彇娑�');
diff --git a/sql/task_menu.sql b/sql/task_menu.sql
new file mode 100644
index 0000000..2c254b9
--- /dev/null
+++ b/sql/task_menu.sql
@@ -0,0 +1,27 @@
+-- ----------------------------
+-- 閫氱敤浠诲姟绠$悊鑿滃崟鏉冮檺閰嶇疆
+-- ----------------------------
+
+-- 浠诲姟绠$悊鑿滃崟
+INSERT INTO sys_menu VALUES (2000, '浠诲姟绠$悊', 0, 5, 'task', null, '', 1, 0, 'M', '0', '0', '', 'task', 'admin', sysdate(), '', null, '浠诲姟绠$悊鐩綍');
+
+-- 閫氱敤浠诲姟鑿滃崟
+INSERT INTO sys_menu VALUES (2001, '閫氱敤浠诲姟', 2000, 1, 'general', 'task/general/index', '', 1, 0, 'C', '0', '0', 'task:general:view', 'list', 'admin', sysdate(), '', null, '閫氱敤浠诲姟鑿滃崟');
+
+-- 浠诲姟绠$悊鎸夐挳鏉冮檺
+INSERT INTO sys_menu VALUES (2002, '浠诲姟鏌ヨ', 2001, 1, '', '', '', 1, 0, 'F', '0', '0', 'task:general:query', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2003, '浠诲姟鏂板', 2001, 2, '', '', '', 1, 0, 'F', '0', '0', 'task:general:add', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2004, '浠诲姟淇敼', 2001, 3, '', '', '', 1, 0, 'F', '0', '0', 'task:general:edit', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2005, '浠诲姟鍒犻櫎', 2001, 4, '', '', '', 1, 0, 'F', '0', '0', 'task:general:remove', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2006, '浠诲姟鍒嗛厤', 2001, 5, '', '', '', 1, 0, 'F', '0', '0', 'task:general:assign', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2007, '鐘舵�佸彉鏇�', 2001, 6, '', '', '', 1, 0, 'F', '0', '0', 'task:general:status', '#', 'admin', sysdate(), '', null, '');
+
+-- 杞﹁締绠$悊鑿滃崟
+INSERT INTO sys_menu VALUES (2008, '杞﹁締绠$悊', 2000, 2, 'vehicle', 'task/vehicle/index', '', 1, 0, 'C', '0', '0', 'task:vehicle:view', 'car', 'admin', sysdate(), '', null, '杞﹁締绠$悊鑿滃崟');
+
+-- 杞﹁締绠$悊鎸夐挳鏉冮檺
+INSERT INTO sys_menu VALUES (2009, '杞﹁締鏌ヨ', 2008, 1, '', '', '', 1, 0, 'F', '0', '0', 'task:vehicle:query', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2010, '杞﹁締鏂板', 2008, 2, '', '', '', 1, 0, 'F', '0', '0', 'task:vehicle:add', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2011, '杞﹁締淇敼', 2008, 3, '', '', '', 1, 0, 'F', '0', '0', 'task:vehicle:edit', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2012, '杞﹁締鍒犻櫎', 2008, 4, '', '', '', 1, 0, 'F', '0', '0', 'task:vehicle:remove', '#', 'admin', sysdate(), '', null, '');
+INSERT INTO sys_menu VALUES (2013, '杞﹁締鍒嗛厤', 2008, 5, '', '', '', 1, 0, 'F', '0', '0', 'task:vehicle:assign', '#', 'admin', sysdate(), '', null, '');
diff --git a/sql/task_tables.sql b/sql/task_tables.sql
new file mode 100644
index 0000000..4983473
--- /dev/null
+++ b/sql/task_tables.sql
@@ -0,0 +1,113 @@
+-- ----------------------------
+-- 閫氱敤浠诲姟绠$悊鐩稿叧琛ㄧ粨鏋�
+-- ----------------------------
+
+-- 1. 浠诲姟涓昏〃
+-- ----------------------------
+DROP TABLE IF EXISTS sys_task;
+CREATE TABLE sys_task (
+    task_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '浠诲姟ID',
+    task_code VARCHAR(50) NOT NULL UNIQUE COMMENT '浠诲姟缂栧彿',
+    task_type VARCHAR(20) NOT NULL COMMENT '浠诲姟绫诲瀷锛歁AINTENANCE-缁翠慨淇濆吇锛孎UEL-鍔犳补浠诲姟锛孫THER-鍏朵粬',
+    task_status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '浠诲姟鐘舵�侊細PENDING-寰呭紑濮嬶紝IN_PROGRESS-浠诲姟涓紝COMPLETED-宸插畬鎴愶紝CANCELLED-宸插彇娑�',    
+    task_description VARCHAR(1000) COMMENT '浠诲姟鎻忚堪',
+    
+    -- 鍦板潃淇℃伅
+    departure_address VARCHAR(500) COMMENT '鍑哄彂鍦板潃',
+    destination_address VARCHAR(500) COMMENT '鐩殑鍦板潃',
+    
+    -- 鏃堕棿淇℃伅
+    planned_start_time DATETIME COMMENT '璁″垝寮�濮嬫椂闂�',
+    planned_end_time DATETIME COMMENT '璁″垝缁撴潫鏃堕棿',
+    actual_start_time DATETIME COMMENT '瀹為檯寮�濮嬫椂闂�',
+    actual_end_time DATETIME COMMENT '瀹為檯缁撴潫鏃堕棿',
+    
+    -- 浜哄憳淇℃伅
+    creator_id BIGINT NOT NULL COMMENT '鍒涘缓浜篒D',
+    assignee_id BIGINT COMMENT '鎵ц浜篒D',
+    dept_id BIGINT NOT NULL COMMENT '褰掑睘閮ㄩ棬ID',
+    
+    -- 绯荤粺瀛楁
+    create_time DATETIME NOT NULL  COMMENT '鍒涘缓鏃堕棿',
+    update_time DATETIME NOT NULL  COMMENT '鏇存柊鏃堕棿',
+    create_by VARCHAR(64) NOT NULL COMMENT '鍒涘缓鑰�',
+    update_by VARCHAR(64) COMMENT '鏇存柊鑰�',
+    remark VARCHAR(500) COMMENT '澶囨敞',
+    del_flag CHAR(1) DEFAULT '0' COMMENT '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    
+    INDEX idx_task_code (task_code),
+    INDEX idx_task_type (task_type),
+    INDEX idx_task_status (task_status),
+    INDEX idx_creator_id (creator_id),
+    INDEX idx_assignee_id (assignee_id),
+    INDEX idx_dept_id (dept_id),
+    INDEX idx_planned_start_time (planned_start_time),
+    INDEX idx_create_time (create_time)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浠诲姟绠$悊琛�';
+
+-- 2. 浠诲姟杞﹁締鍏宠仈琛�
+-- ----------------------------
+DROP TABLE IF EXISTS sys_task_vehicle;
+CREATE TABLE sys_task_vehicle (
+    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '鍏宠仈ID',
+    task_id BIGINT NOT NULL COMMENT '浠诲姟ID',
+    vehicle_id BIGINT NOT NULL COMMENT '杞﹁締ID',
+    assign_time DATETIME NOT NULL  COMMENT '鍒嗛厤鏃堕棿',
+    assign_by VARCHAR(64) NOT NULL COMMENT '鍒嗛厤浜�',
+    status VARCHAR(20) DEFAULT 'ASSIGNED' COMMENT '鍏宠仈鐘舵�侊細ASSIGNED-宸插垎閰嶏紝ACTIVE-鎵ц涓紝COMPLETED-宸插畬鎴愶紝CANCELLED-宸插彇娑�',
+    remark VARCHAR(500) COMMENT '澶囨敞',
+    
+    INDEX idx_task_id (task_id),
+    INDEX idx_vehicle_id (vehicle_id),
+    INDEX idx_status (status),
+    INDEX idx_assign_time (assign_time),
+    
+    UNIQUE KEY uk_task_vehicle (task_id, vehicle_id),
+    FOREIGN KEY (task_id) REFERENCES sys_task(task_id) ON DELETE CASCADE,
+    FOREIGN KEY (vehicle_id) REFERENCES tb_vehicle_info(vehicle_id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浠诲姟杞﹁締鍏宠仈琛�';
+
+-- 3. 浠诲姟闄勪欢琛�
+-- ----------------------------
+DROP TABLE IF EXISTS sys_task_attachment;
+CREATE TABLE sys_task_attachment (
+    attachment_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '闄勪欢ID',
+    task_id BIGINT NOT NULL COMMENT '浠诲姟ID',
+    file_name VARCHAR(255) NOT NULL COMMENT '鏂囦欢鍚�',
+    file_path VARCHAR(500) NOT NULL COMMENT '鏂囦欢璺緞',
+    file_size BIGINT COMMENT '鏂囦欢澶у皬锛堝瓧鑺傦級',
+    file_type VARCHAR(50) COMMENT '鏂囦欢绫诲瀷',
+    upload_time DATETIME NOT NULL COMMENT '涓婁紶鏃堕棿',
+    upload_by VARCHAR(64) NOT NULL COMMENT '涓婁紶鑰�',
+    
+    INDEX idx_task_id (task_id),
+    FOREIGN KEY (task_id) REFERENCES sys_task(task_id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浠诲姟闄勪欢琛�';
+
+-- 4. 浠诲姟鎿嶄綔鏃ュ織琛�
+-- ----------------------------
+DROP TABLE IF EXISTS sys_task_log;
+CREATE TABLE sys_task_log (
+    log_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '鏃ュ織ID',
+    task_id BIGINT NOT NULL COMMENT '浠诲姟ID',
+    operation_type VARCHAR(20) NOT NULL COMMENT '鎿嶄綔绫诲瀷锛欳REATE-鍒涘缓锛孶PDATE-鏇存柊锛孉SSIGN-鍒嗛厤锛孲TATUS_CHANGE-鐘舵�佸彉鏇达紝DELETE-鍒犻櫎',
+    operation_desc VARCHAR(500) COMMENT '鎿嶄綔鎻忚堪',
+    old_value TEXT COMMENT '鎿嶄綔鍓嶅��',
+    new_value TEXT COMMENT '鎿嶄綔鍚庡��',
+    operator_id BIGINT NOT NULL COMMENT '鎿嶄綔浜篒D',
+    operator_name VARCHAR(64) NOT NULL COMMENT '鎿嶄綔浜哄鍚�',
+    operation_time DATETIME NOT NULL COMMENT '鎿嶄綔鏃堕棿',
+    ip_address VARCHAR(128) COMMENT 'IP鍦板潃',
+    
+    INDEX idx_task_id (task_id),
+    INDEX idx_operation_type (operation_type),
+    INDEX idx_operator_id (operator_id),
+    INDEX idx_operation_time (operation_time),
+    FOREIGN KEY (task_id) REFERENCES sys_task(task_id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='浠诲姟鎿嶄綔鏃ュ織琛�';
+
+-- 5. 鏇存柊杞﹁締淇℃伅琛紝娣诲姞鏈烘瀯鍏宠仈瀛楁
+-- ----------------------------
+ALTER TABLE tb_vehicle_info ADD COLUMN dept_id BIGINT(20) DEFAULT NULL COMMENT '褰掑睘鏈烘瀯ID';
+ALTER TABLE tb_vehicle_info ADD INDEX idx_dept_id (dept_id);
+ALTER TABLE tb_vehicle_info ADD FOREIGN KEY (dept_id) REFERENCES sys_dept(dept_id) ON DELETE SET NULL;
diff --git a/sql/vehicle_info.sql b/sql/vehicle_info.sql
index 6434538..cf24d47 100644
--- a/sql/vehicle_info.sql
+++ b/sql/vehicle_info.sql
@@ -19,5 +19,10 @@
 -- 鍦╰b_vehicle_info琛ㄤ腑娣诲姞device_id瀛楁
 ALTER TABLE tb_vehicle_info ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '璁惧ID';
 
+-- 鍦╰b_vehicle_info琛ㄤ腑娣诲姞褰掑睘鏈烘瀯瀛楁
+ALTER TABLE tb_vehicle_info ADD COLUMN dept_id BIGINT(20) DEFAULT NULL COMMENT '褰掑睘鏈烘瀯ID';
+ALTER TABLE tb_vehicle_info ADD INDEX idx_dept_id (dept_id);
+ALTER TABLE tb_vehicle_info ADD CONSTRAINT fk_vehicle_dept FOREIGN KEY (dept_id) REFERENCES sys_dept(dept_id) ON DELETE SET NULL;
+
 -- 鍦╰b_vehicle_gps琛ㄤ腑娣诲姞device_id瀛楁
 ALTER TABLE tb_vehicle_gps ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '璁惧ID';
\ No newline at end of file

--
Gitblit v1.9.1