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 >= #{plannedStartTimeBegin}</if> + <if test="plannedStartTimeEnd != null "> and t.planned_start_time <= #{plannedStartTimeEnd}</if> + <if test="plannedEndTimeBegin != null "> and t.planned_end_time >= #{plannedEndTimeBegin}</if> + <if test="plannedEndTimeEnd != null "> and t.planned_end_time <= #{plannedEndTimeEnd}</if> + <if test="overdue != null and overdue == true"> and t.planned_end_time < 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 < 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 < 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