From c5ac97682e3b4ca748541ace97cb37a2295bd81e Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期四, 19 三月 2026 22:46:29 +0800
Subject: [PATCH] feat: 增加GPS清理后台任务
---
ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml | 18
app/pages/index.vue | 177 ++++++-----
ruoyi-system/src/main/java/com/ruoyi/system/domain/enums/TaskStatus.java | 15 +
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CleanVehicleGpsTask.java | 34 ++
GPS 分段里程重复插入问题修复说明.md | 114 ++++++++
ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleGpsService.java | 13
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleGpsMapper.java | 13
app/pages/task/index.vue | 83 ++++-
ruoyi-admin/src/main/resources/application.yml | 2
remark.md | 6
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java | 16 +
app/utils/TaskUtil.js | 201 ++++++++++++++
sql/clean_gps.sql | 37 +-
app/pagesTask/detail.vue | 59 +--
ruoyi-system/src/main/resources/mapper/system/VehicleGpsSegmentMileageMapper.xml | 15 +
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusConverter.java | 37 ++
16 files changed, 666 insertions(+), 174 deletions(-)
diff --git "a/GPS \345\210\206\346\256\265\351\207\214\347\250\213\351\207\215\345\244\215\346\217\222\345\205\245\351\227\256\351\242\230\344\277\256\345\244\215\350\257\264\346\230\216.md" "b/GPS \345\210\206\346\256\265\351\207\214\347\250\213\351\207\215\345\244\215\346\217\222\345\205\245\351\227\256\351\242\230\344\277\256\345\244\215\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..9427c41
--- /dev/null
+++ "b/GPS \345\210\206\346\256\265\351\207\214\347\250\213\351\207\215\345\244\215\346\217\222\345\205\245\351\227\256\351\242\230\344\277\256\345\244\215\350\257\264\346\230\216.md"
@@ -0,0 +1,114 @@
+# GPS 鍒嗘閲岀▼閲嶅鎻掑叆闂淇璇存槑
+
+## 闂鎻忚堪
+
+鍦ㄦ墽琛� GPS 鍒嗘閲岀▼璁$畻鏃讹紝绯荤粺鎶涘嚭浠ヤ笅寮傚父锛�
+
+```
+org.springframework.jdbc.UncategorizedSQLException:
+### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '9-2026-03-15 06:10:00' for key 'tb_vehicle_gps_segment_mileage.uk_vehicle_time'
+```
+
+## 鏍规湰鍘熷洜
+
+鏁版嵁搴撹〃 `tb_vehicle_gps_segment_mileage` 瀹氫箟浜嗗敮涓�绱㈠紩 `uk_vehicle_time (vehicle_id, segment_start_time)`锛岀敤浜庣‘淇濆悓涓�杞﹁締鍦ㄥ悓涓�鏃堕棿娈电殑鍒嗘閲岀▼璁板綍鍙湁涓�鏉°��
+
+铏界劧鍦ㄤ唬鐮佸眰闈紙`VehicleGpsSegmentMileageServiceImpl.java` 绗� 390 琛岋級宸茬粡鏈夋鏌ラ�昏緫锛�
+
+```java
+if (isSegmentAlreadyCalculated(vehicleId, segmentStartTime, segmentGpsList)) {
+ previousSegmentLastPoint = segmentGpsList.get(segmentGpsList.size() - 1);
+ continue;
+}
+```
+
+浣嗗湪**骞跺彂鍦烘櫙**涓嬶紝浠嶅彲鑳藉嚭鐜扮珵鎬佹潯浠讹紙Race Condition锛夛細
+
+1. **绾跨▼ A** 妫�鏌ユ椂闂存 2026-03-15 06:10:00锛屽彂鐜颁笉瀛樺湪
+2. **绾跨▼ B** 鍚屾椂妫�鏌ュ悓涓�鏃堕棿娈碉紝涔熷彂鐜颁笉瀛樺湪
+3. **绾跨▼ A** 鎵ц INSERT
+4. **绾跨▼ B** 灏濊瘯鎵ц INSERT锛岃繚鍙嶅敮涓�绱㈠紩绾︽潫锛屾姏鍑哄紓甯�
+
+## 瑙e喅鏂规
+
+淇敼 MyBatis Mapper XML 鏂囦欢涓殑 INSERT 璇彞锛屼娇鐢� MySQL 鐨� `ON DUPLICATE KEY UPDATE` 璇硶锛�
+
+### 淇敼鏂囦欢
+- `ruoyi-system/src/main/resources/mapper/system/VehicleGpsSegmentMileageMapper.xml`
+
+### 淇敼鍐呭
+
+鍦ㄥ師鏈夌殑 `insertVehicleGpsSegmentMileage` 鏂规硶涓坊鍔� `ON DUPLICATE KEY UPDATE` 瀛愬彞锛�
+
+```xml
+<insert id="insertVehicleGpsSegmentMileage" parameterType="VehicleGpsSegmentMileage">
+ INSERT INTO tb_vehicle_gps_segment_mileage
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <!-- 瀛楁鍒楄〃 -->
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <!-- 鍊煎垪琛� -->
+ </trim>
+ ON DUPLICATE KEY UPDATE
+ vehicle_no = VALUES(vehicle_no),
+ segment_end_time = VALUES(segment_end_time),
+ start_longitude = VALUES(start_longitude),
+ start_latitude = VALUES(start_latitude),
+ end_longitude = VALUES(end_longitude),
+ end_latitude = VALUES(end_latitude),
+ segment_distance = VALUES(segment_distance),
+ gps_point_count = VALUES(gps_point_count),
+ gps_ids = VALUES(gps_ids),
+ task_id = VALUES(task_id),
+ task_code = VALUES(task_code),
+ calculate_method = VALUES(calculate_method),
+ update_time = NOW()
+</insert>
+```
+
+## 鎶�鏈紭鍔�
+
+浣跨敤 `ON DUPLICATE KEY UPDATE` 鐨勫ソ澶勶細
+
+1. **鍘熷瓙鎬ф搷浣�**锛氭暟鎹簱灞傞潰淇濊瘉鎻掑叆鎴栨洿鏂扮殑鍘熷瓙鎬э紝閬垮厤骞跺彂鍐茬獊
+2. **鏃犻渶棰濆鏌ヨ**锛氫笉闇�瑕佸厛 SELECT 鍐嶅喅瀹� INSERT 杩樻槸 UPDATE
+3. **鎬ц兘鏇翠紭**锛氬噺灏戜竴娆℃暟鎹簱鏌ヨ寮�閿�
+4. **浠g爜绠�娲�**锛氫笉闇�瑕佸鏉傜殑寮傚父鎹曡幏鍜岄噸璇曢�昏緫
+5. **鏁版嵁涓�鑷存��**锛氬鏋滃彂鐢熼噸澶嶏紝鑷姩鏇存柊宸叉湁璁板綍鑰屼笉鏄姤閿�
+
+## 褰卞搷鑼冨洿
+
+- **鍙楀奖鍝嶇殑鍔熻兘**锛欸PS 鍒嗘閲岀▼璁$畻
+- **鍙楀奖鍝嶇殑琛�**锛歚tb_vehicle_gps_segment_mileage`
+- **鍙楀奖鍝嶇殑鎺ュ彛**锛氭墍鏈夎皟鐢� `insertVehicleGpsSegmentMileage` 鐨勬柟娉�
+
+## 娴嬭瘯寤鸿
+
+1. **骞跺彂娴嬭瘯**锛氭ā鎷熷涓嚎绋嬪悓鏃惰绠楀悓涓�杞﹁締鐨� GPS 鍒嗘閲岀▼
+2. **閲嶅鏁版嵁娴嬭瘯**锛氭墜鍔ㄦ瀯閫犻噸澶嶇殑杞﹁締 ID + 鏃堕棿娈靛紑濮嬫椂闂达紝楠岃瘉鏄惁鑳芥纭洿鏂�
+3. **鍥炲綊娴嬭瘯**锛氱‘淇濇甯哥殑鎻掑叆鍔熻兘涓嶅彈褰卞搷
+
+## 閮ㄧ讲姝ラ
+
+1. 閲嶅惎搴旂敤鏈嶅姟鍣ㄥ嵆鍙敓鏁�
+2. 鏃犻渶鎵ц浠讳綍 SQL 鑴氭湰
+3. 鏃犻渶淇敼鏁版嵁搴撹〃缁撴瀯
+
+## 鍚庣画浼樺寲寤鸿
+
+1. **鐩戞帶鏃ュ織**锛氳瀵熸槸鍚﹁繕鏈夊叾浠栧苟鍙戝満鏅鑷寸殑绫讳技闂
+2. **浜嬪姟浼樺寲**锛氬浜庢壒澶勭悊鎿嶄綔锛岃�冭檻娣诲姞閫傚綋鐨勪簨鍔¢殧绂荤骇鍒�
+3. **閿佹満鍒�**锛氬鏋滈棶棰樹粛鐒跺瓨鍦紝鍙互鑰冭檻浣跨敤鏁版嵁搴撹閿佹垨鍒嗗竷寮忛攣
+
+## 鐩稿叧鏂囦欢
+
+- `ruoyi-system/src/main/resources/mapper/system/VehicleGpsSegmentMileageMapper.xml`
+- `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsSegmentMileageServiceImpl.java`
+- `ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGpsSegmentMileage.java`
+- `sql/vehicle_gps_segment_mileage.sql`
+
+---
+
+**淇鏃ユ湡**: 2026-03-16
+**淇浜哄憳**: AI Assistant
+**闂绫诲瀷**: 骞跺彂鏁版嵁涓�鑷存��
diff --git a/app/pages/index.vue b/app/pages/index.vue
index ce9d0b4..8d6dd2f 100644
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -107,24 +107,30 @@
<view
class="task-status"
:class="
- task.taskStatus === 'PENDING'
+ task.taskStatus === TaskStatus.PENDING
? 'status-pending'
- : task.taskStatus === 'DEPARTING'
+ : task.taskStatus === TaskStatus.NOT_CONFIRMED
+ ? 'status-not-confirmed'
+ : task.taskStatus === TaskStatus.NOT_DEPARTED
+ ? 'status-not-departed'
+ : task.taskStatus === TaskStatus.PARTIALLY_CONFIRMED
+ ? 'status-partially-confirmed'
+ : task.taskStatus === TaskStatus.DEPARTING
? 'status-departing'
- : task.taskStatus === 'ARRIVED'
+ : task.taskStatus === TaskStatus.ARRIVED
? 'status-arrived'
- : task.taskStatus === 'RETURNING'
+ : task.taskStatus === TaskStatus.RETURNING
? 'status-returning'
- : task.taskStatus === 'COMPLETED'
+ : task.taskStatus === TaskStatus.COMPLETED
? 'status-completed'
- : task.taskStatus === 'CANCELLED'
+ : task.taskStatus === TaskStatus.CANCELLED
? 'status-cancelled'
- : task.taskStatus === 'IN_PROGRESS'
+ : task.taskStatus === TaskStatus.IN_PROGRESS
? 'status-in-progress'
- : 'status-default'
+ : 'status-pending'
"
>
- {{ getStatusText(task.status) }}
+ {{ getStatusText(task.taskStatus) }}
</view>
</view>
@@ -161,8 +167,8 @@
<!-- 鎿嶄綔鎸夐挳 -->
<view class="task-actions">
- <!-- 寰呭鐞嗙姸鎬�: 鏄剧ず鍑哄彂銆佸彇娑� -->
- <template v-if="task.taskStatus === 'PENDING'">
+ <!-- 寰呭鐞嗙姸鎬侊細鏄剧ず鍑哄彂銆佸彇娑� -->
+ <template v-if="task.taskStatus === TaskStatus.PENDING || task.taskStatus === TaskStatus.NOT_DEPARTED || task.taskStatus === TaskStatus.NOT_CONFIRMED || task.taskStatus === TaskStatus.PARTIALLY_CONFIRMED">
<button
class="action-btn primary"
@click="handleTaskAction(task, 'depart')"
@@ -177,8 +183,8 @@
</button>
</template>
- <!-- 鍑哄彂涓姸鎬�: 鏄剧ず宸插埌杈俱�佸己鍒剁粨鏉� -->
- <template v-else-if="task.taskStatus === 'DEPARTING'">
+ <!-- 鍑哄彂涓姸鎬侊細鏄剧ず宸插埌杈俱�佸己鍒剁粨鏉� -->
+ <template v-else-if="task.taskStatus === TaskStatus.DEPARTING">
<button
class="action-btn primary"
@click="handleTaskAction(task, 'arrive')"
@@ -193,8 +199,8 @@
</button>
</template>
- <!-- 宸插埌杈剧姸鎬�: 鏄剧ず宸茶繑绋� -->
- <template v-else-if="task.taskStatus === 'ARRIVED'">
+ <!-- 宸插埌杈剧姸鎬侊細鏄剧ず宸茶繑绋� -->
+ <template v-else-if="task.taskStatus === TaskStatus.ARRIVED">
<button
class="action-btn primary"
@click="handleTaskAction(task, 'return')"
@@ -203,8 +209,8 @@
</button>
</template>
- <!-- 杩旂▼涓姸鎬�: 鏄剧ず宸插畬鎴� -->
- <template v-else-if="task.taskStatus === 'RETURNING'">
+ <!-- 杩旂▼涓姸鎬侊細鏄剧ず宸插畬鎴� -->
+ <template v-else-if="task.taskStatus === TaskStatus.RETURNING">
<button
class="action-btn primary"
@click="handleTaskAction(task, 'complete')"
@@ -265,10 +271,40 @@
import { formatDateTime } from "@/utils/common";
import subscribeManager from "@/utils/subscribe";
import { checkTaskCanDepart } from "@/utils/taskValidator";
+import { getStatusText as getTaskStatusText, TaskStatus } from "@/utils/TaskUtil";
+
+// 浠诲姟绫诲瀷鏄犲皠锛堜复鏃跺畾涔夛紝閬垮厤瀵煎叆闂锛�
+const TASK_TYPE_MAP = {
+ MAINTENANCE: "缁翠慨淇濆吇",
+ FUEL: "鍔犳补",
+ OTHER: "鍏朵粬",
+ EMERGENCY_TRANSFER: "杞繍浠诲姟",
+ WELFARE: "绂忕杞�",
+ maintenance: "缁翠慨淇濆吇",
+ refuel: "鍔犳补",
+ inspection: "宸℃",
+ emergency: "杞繍浠诲姟",
+ welfare: "绂忕杞�"
+};
+
+// 浠诲姟鐘舵�佹槧灏勶紙涓存椂瀹氫箟锛岄伩鍏嶅鍏ラ棶棰橈級
+const TASK_STATUS_MAP = {
+ PENDING: "寰呭鐞�",
+ NOT_CONFIRMED: "瀹屽叏鏈‘璁�",
+ NOT_DEPARTED: "寰呭嚭鍙�",
+ PARTIALLY_CONFIRMED: "閮ㄥ垎纭",
+ DEPARTING: "鍑哄彂涓�",
+ ARRIVED: "宸插埌杈�",
+ RETURNING: "杩旂▼涓�",
+ COMPLETED: "宸插畬鎴�",
+ CANCELLED: "宸插彇娑�",
+ IN_PROGRESS: "浠诲姟涓�"
+};
export default {
data() {
return {
+ TaskStatus, // 鏆撮湶 TaskStatus 缁欐ā鏉夸娇鐢�
// 鐢ㄦ埛缁戝畾鐨勮溅杈嗕俊鎭�
boundVehicle: "",
boundVehicleId: null,
@@ -307,13 +343,17 @@
runningTasks() {
return this.displayedTaskList.filter((task) => {
// 鍖呭惈寰呭鐞嗐�佸嚭鍙戜腑銆佸凡鍒拌揪銆佽繑绋嬩腑绛夋墍鏈夋湭瀹屾垚鐨勭姸鎬�
- return [
- "PENDING",
- "DEPARTING",
- "ARRIVED",
- "RETURNING",
- "IN_PROGRESS",
- ].includes(task.taskStatus);
+ const activeStatuses = [
+ TaskStatus.NOT_CONFIRMED,
+ TaskStatus.NOT_DEPARTED,
+ TaskStatus.PARTIALLY_CONFIRMED,
+ TaskStatus.PENDING,
+ TaskStatus.DEPARTING,
+ TaskStatus.ARRIVED,
+ TaskStatus.RETURNING,
+ TaskStatus.IN_PROGRESS,
+ ];
+ return activeStatuses.includes(task.taskStatus);
});
},
@@ -651,6 +691,10 @@
convertStatus(dbStatus) {
const statusMap = {
PENDING: "pending",
+ NOT_CONFIRMED: "pending",
+ NOT_DEPARTED: "pending",
+ PARTIALLY_CONFIRMED: "pending",
+
DEPARTING: "processing",
ARRIVED: "processing",
RETURNING: "processing",
@@ -754,7 +798,7 @@
this.$modal
.confirm("纭畾瑕佸嚭鍙戝悧锛�")
.then(() => {
- this.updateTaskStatus(task.taskId, "DEPARTING", "浠诲姟宸插嚭鍙�");
+ this.updateTaskStatus(task.taskId, TaskStatus.DEPARTING, "浠诲姟宸插嚭鍙�");
})
.catch(() => {});
} catch (error) {
@@ -764,7 +808,7 @@
this.$modal
.confirm("妫�鏌ヤ换鍔$姸鎬佸け璐ワ紝鏄惁缁х画鍑哄彂锛�")
.then(() => {
- this.updateTaskStatus(task.taskId, "DEPARTING", "浠诲姟宸插嚭鍙�");
+ this.updateTaskStatus(task.taskId, TaskStatus.DEPARTING, "浠诲姟宸插嚭鍙�");
})
.catch(() => {});
}
@@ -781,7 +825,7 @@
this.$modal
.confirm("纭宸插埌杈剧洰鐨勫湴锛�")
.then(() => {
- this.updateTaskStatus(task.taskId, "ARRIVED", "宸插埌杈剧洰鐨勫湴");
+ this.updateTaskStatus(task.taskId, TaskStatus.ARRIVED, "宸插埌杈剧洰鐨勫湴");
})
.catch(() => {});
break;
@@ -791,7 +835,7 @@
this.$modal
.confirm("纭畾瑕佸己鍒剁粨鏉熸浠诲姟鍚楋紵")
.then(() => {
- this.updateTaskStatus(task.taskId, "CANCELLED", "浠诲姟宸插己鍒剁粨鏉�");
+ this.updateTaskStatus(task.taskId, TaskStatus.CANCELLED, "浠诲姟宸插己鍒剁粨鏉�");
})
.catch(() => {});
break;
@@ -801,7 +845,7 @@
this.$modal
.confirm("纭寮�濮嬭繑绋嬶紵")
.then(() => {
- this.updateTaskStatus(task.taskId, "RETURNING", "宸插紑濮嬭繑绋�");
+ this.updateTaskStatus(task.taskId, TaskStatus.RETURNING, "宸插紑濮嬭繑绋�");
})
.catch(() => {});
break;
@@ -809,7 +853,7 @@
case "complete":
// 宸插畬鎴� -> 鐘舵�佸彉涓哄凡瀹屾垚
// 闇�瑕佹鏌ユ槸鍚︿笂浼犱簡鐭ユ儏鍚屾剰涔�
- this.checkConsentAttachmentAndThen(task.taskId, "COMPLETED", "浠诲姟宸插畬鎴�");
+ this.checkConsentAttachmentAndThen(task.taskId, TaskStatus.COMPLETED, "浠诲姟宸插畬鎴�");
break;
}
},
@@ -919,14 +963,14 @@
getLocationAndUpdateStatus(taskId, status, remark, cancelReason) {
const that = this;
- // 浣跨敤uni.getLocation鑾峰彇GPS浣嶇疆
+ // 浣跨敤 uni.getLocation 鑾峰彇 GPS 浣嶇疆
uni.getLocation({
type: "gcj02",
geocode: true,
altitude: true,
success: function (res) {
- console.log("GPS瀹氫綅鎴愬姛:", res);
-
+ console.log("GPS 瀹氫綅鎴愬姛:", res);
+
const statusData = {
taskStatus: status,
remark: remark,
@@ -990,55 +1034,14 @@
});
},
- // 鑾峰彇鐘舵�佹牱寮忕被
- getStatusClass(status) {
- const statusClassMap = {
- PENDING: "status-pending",
- DEPARTING: "status-departing",
- ARRIVED: "status-arrived",
- RETURNING: "status-returning",
- COMPLETED: "status-completed",
- CANCELLED: "status-cancelled",
- IN_PROGRESS: "status-in-progress",
- };
- return statusClassMap[status] || "status-default";
- },
-
- getStatusText(status) {
- // 鏀寔鏂版棫涓ょ鐘舵�佹牸寮�
- const statusMap = {
- // 鏂版牸寮忥紙鏁版嵁搴撶姸鎬侊級
- PENDING: "寰呭鐞�",
- DEPARTING: "鍑哄彂涓�",
- ARRIVED: "宸插埌杈�",
- RETURNING: "杩旂▼涓�",
- COMPLETED: "宸插畬鎴�",
- CANCELLED: "宸插彇娑�",
- IN_PROGRESS: "澶勭悊涓�",
- // 鏃ф牸寮忥紙UI鐘舵�侊級
- pending: "寰呭鐞�",
- processing: "澶勭悊涓�",
- completed: "宸插畬鎴�",
- };
- return statusMap[status] || "鏈煡";
- },
-
+ // 鑾峰彇浠诲姟绫诲瀷鏂囨湰
getTaskTypeText(type) {
- const typeMap = {
- // 鏂版牸寮忥紙鏁版嵁搴撶被鍨嬶級
- MAINTENANCE: "缁翠慨淇濆吇",
- FUEL: "鍔犳补",
- OTHER: "鍏朵粬",
- EMERGENCY_TRANSFER: "杞繍浠诲姟",
- WELFARE: "绂忕杞�",
- // 鏃ф牸寮忥紙UI绫诲瀷锛�
- maintenance: "缁翠慨淇濆吇",
- refuel: "鍔犳补",
- inspection: "宸℃",
- emergency: "杞繍浠诲姟",
- welfare: "绂忕杞�",
- };
- return typeMap[type] || "鏈煡绫诲瀷";
+ return TASK_TYPE_MAP[type] || "鏈煡绫诲瀷";
+ },
+
+ // 鑾峰彇浠诲姟鐘舵�佹枃鏈�
+ getStatusText(status) {
+ return TASK_STATUS_MAP[status] || "鏈煡";
},
clickConfirmsubscribeTaskNotify() {
@@ -1328,6 +1331,18 @@
background-color: #fff3e0;
color: #ff9500;
}
+ &.status-not-confirmed {
+ background-color: #fff3e0;
+ color: #ff9500;
+ }
+ &.status-not-departed {
+ background-color: #fff3e0;
+ color: #ff9500;
+ }
+ &.status-partially-confirmed {
+ background-color: #fff3e0;
+ color: #ff9500;
+ }
// 鍑哄彂涓� - 钃濊壊
&.status-departing {
diff --git a/app/pages/task/index.vue b/app/pages/task/index.vue
index da47896..244207b 100644
--- a/app/pages/task/index.vue
+++ b/app/pages/task/index.vue
@@ -158,7 +158,7 @@
? 'status-cancelled'
: task.taskStatus === 'IN_PROGRESS'
? 'status-in-progress'
- : 'status-default'
+ : 'status-pending'
"
>
{{ getStatusText(task.taskStatus) }}
@@ -197,7 +197,10 @@
<!-- 鎿嶄綔鎸夐挳 -->
<view class="task-actions">
<!-- 寰呭鐞嗙姸鎬�: 鏄剧ず鍑哄彂銆佸彇娑� -->
- <template v-if="task.taskStatus === 'PENDING'">
+ <template v-if="task.taskStatus === 'PENDING'
+ || task.taskStatus === 'NOT_DEPARTED'
+ || task.taskStatus === 'NOT_CONFIRMED'
+ || task.taskStatus === 'PARTIALLY_CONFIRMED'">
<button
class="action-btn primary"
@click="handleTaskAction(task, 'depart')"
@@ -300,6 +303,35 @@
import { mapState } from "vuex";
import { formatDateTime } from "@/utils/common";
import { checkTaskCanDepart } from "@/utils/taskValidator";
+import { getStatusText as getTaskStatusText, getTaskStatusOptions, getTaskTypeText as getTaskTypeTextUtil } from "@/utils/TaskUtil";
+
+// 浠诲姟绫诲瀷鏄犲皠锛堜复鏃跺畾涔夛紝閬垮厤瀵煎叆闂锛�
+const TASK_TYPE_MAP = {
+ MAINTENANCE: "缁翠慨淇濆吇",
+ FUEL: "鍔犳补",
+ OTHER: "鍏朵粬",
+ EMERGENCY_TRANSFER: "杞繍浠诲姟",
+ WELFARE: "绂忕杞�",
+ maintenance: "缁翠慨淇濆吇",
+ refuel: "鍔犳补",
+ inspection: "宸℃",
+ emergency: "杞繍浠诲姟",
+ welfare: "绂忕杞�"
+};
+
+// 浠诲姟鐘舵�佹槧灏勶紙涓存椂瀹氫箟锛岄伩鍏嶅鍏ラ棶棰橈級
+const TASK_STATUS_MAP = {
+ PENDING: "寰呭鐞�",
+ NOT_CONFIRMED: "瀹屽叏鏈‘璁�",
+ NOT_DEPARTED: "寰呭嚭鍙�",
+ PARTIALLY_CONFIRMED: "閮ㄥ垎纭",
+ DEPARTING: "鍑哄彂涓�",
+ ARRIVED: "宸插埌杈�",
+ RETURNING: "杩旂▼涓�",
+ COMPLETED: "宸插畬鎴�",
+ CANCELLED: "宸插彇娑�",
+ IN_PROGRESS: "浠诲姟涓�"
+};
export default {
components: {
@@ -315,8 +347,8 @@
vehicle: "",
taskNo: "",
},
- statusOptions: ["鍏ㄩ儴鐘舵��", "寰呭鐞�", "澶勭悊涓�", "宸插畬鎴�", "宸插彇娑�"],
- statusValues: ["", "pending", "processing", "completed", "cancelled"],
+ statusOptions: ["鍏ㄩ儴鐘舵��", ...getTaskStatusOptions().map(opt => opt.label)],
+ statusValues: ["", ...getTaskStatusOptions().map(opt => opt.value)],
selectedStatus: "",
selectedStatusText: "",
startDate: "",
@@ -415,6 +447,9 @@
queryParams.taskStatus = "PENDING";
} else if (this.currentFilter === "processing") {
queryParams.taskStatusList = [
+ "NOT_CONFIRMED",
+ "NOT_DEPARTED",
+ "PARTIALLY_CONFIRMED",
"DEPARTING",
"ARRIVED",
"RETURNING",
@@ -429,6 +464,9 @@
const statusMap = {
pending: "PENDING",
processing: [
+ "NOT_CONFIRMED",
+ "NOT_DEPARTED",
+ "PARTIALLY_CONFIRMED",
"DEPARTING",
"ARRIVED",
"RETURNING",
@@ -533,6 +571,9 @@
queryParams.taskStatus = "PENDING";
} else if (this.currentFilter === "processing") {
queryParams.taskStatusList = [
+ "NOT_CONFIRMED",
+ "NOT_DEPARTED",
+ "PARTIALLY_CONFIRMED",
"DEPARTING",
"ARRIVED",
"RETURNING",
@@ -1080,19 +1121,9 @@
});
},
- getStatusText(status) {
- const statusMap = {
- PENDING: "寰呭鐞�",
- DEPARTING: "鍑哄彂涓�",
- ARRIVED: "宸插埌杈�",
- RETURNING: "杩旂▼涓�",
- COMPLETED: "宸插畬鎴�",
- CANCELLED: "宸插彇娑�",
- IN_PROGRESS: "澶勭悊涓�", // 鍏煎鏃ф暟鎹�
- };
- return statusMap[status] || "鏈煡";
- },
-
+ // 浣跨敤 TaskUtil 涓殑 getStatusText 鏂规硶
+ // getStatusText 宸插湪 utils/TaskUtil.js 涓畾涔�
+
// 鑾峰彇鐘舵�佹牱寮忕被
getStatusClass(status) {
const statusClassMap = {
@@ -1106,16 +1137,18 @@
};
return statusClassMap[status] || "status-default";
},
+
+ // 浣跨敤 TaskUtil 涓殑 getTaskTypeText 鏂规硶
+ // getTaskTypeText 宸插湪 utils/TaskUtil.js 涓畾涔�
+ // 鑾峰彇浠诲姟绫诲瀷鏂囨湰
getTaskTypeText(type) {
- const typeMap = {
- MAINTENANCE: "缁翠慨淇濆吇",
- FUEL: "鍔犳补",
- OTHER: "鍏朵粬",
- EMERGENCY_TRANSFER: "杞繍浠诲姟",
- WELFARE: "绂忕杞�",
- };
- return typeMap[type] || "鏈煡绫诲瀷";
+ return TASK_TYPE_MAP[type] || "鏈煡绫诲瀷";
+ },
+
+ // 鑾峰彇浠诲姟鐘舵�佹枃鏈�
+ getStatusText(status) {
+ return TASK_STATUS_MAP[status] || "鏈煡";
},
},
};
diff --git a/app/pagesTask/detail.vue b/app/pagesTask/detail.vue
index 4bd3c08..ca3c762 100644
--- a/app/pagesTask/detail.vue
+++ b/app/pagesTask/detail.vue
@@ -71,7 +71,7 @@
</view>
<!-- 褰撳墠鐧诲綍浜烘槸璇ユ墽琛屼汉涓旀湭灏辩华鏃舵樉绀哄氨缁寜閽� -->
<view
- v-if="showAssigneeReadyFeature() && isAssigneeSelf(assignee) && !isAssigneeReady(assignee) && taskDetail.taskStatus === 'PENDING'"
+ v-if="showAssigneeReadyFeature() && isAssigneeSelf(assignee) && !isAssigneeReady(assignee) && taskDetail.taskStatus === TaskStatus.PENDING"
class="assignee-ready-btn"
:data-user-id="assignee.userId || assignee.oaUserId"
:data-user-name="assignee.userName"
@@ -275,7 +275,7 @@
</view>
<!-- 鍙栨秷淇℃伅锛堜粎鍦ㄤ换鍔″凡鍙栨秷涓旀湁鍙栨秷鍘熷洜鏃舵樉绀猴級 -->
- <view class="detail-section" v-if="taskDetail.taskStatus === 'CANCELLED' && taskDetail.emergencyInfo && taskDetail.emergencyInfo.cancelReason">
+ <view class="detail-section" v-if="taskDetail.taskStatus === TaskStatus.CANCELLED && taskDetail.emergencyInfo && taskDetail.emergencyInfo.cancelReason">
<view class="section-title">鍙栨秷淇℃伅</view>
<view class="info-item">
<view class="label">鍙栨秷鍘熷洜</view>
@@ -465,8 +465,11 @@
<!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
<view class="action-buttons" v-if="taskDetail">
- <!-- 寰呭鐞嗙姸鎬�: 鏄剧ず鍑哄彂銆佸彇娑堛�佸己鍒跺畬鎴� -->
- <template v-if="taskDetail.taskStatus === 'PENDING' ">
+ <!-- 寰呭鐞嗙姸鎬侊細鏄剧ず鍑哄彂銆佸彇娑堛�佸己鍒跺畬鎴� -->
+ <template v-if="taskDetail.taskStatus === TaskStatus.PENDING
+ || taskDetail.taskStatus === TaskStatus.NOT_DEPARTED
+ || taskDetail.taskStatus === TaskStatus.NOT_CONFIRMED
+ || taskDetail.taskStatus === TaskStatus.PARTIALLY_CONFIRMED">
<button
v-if="canOperateTask()"
class="action-btn primary"
@@ -488,9 +491,9 @@
寮哄埗瀹屾垚
</button>
</template>
-
- <!-- 鍑哄彂涓姸鎬�: 鏄剧ず宸插埌杈俱�佸己鍒剁粨鏉熴�佸己鍒跺畬鎴� -->
- <template v-else-if="taskDetail.taskStatus === 'DEPARTING'">
+
+ <!-- 鍑哄彂涓姸鎬侊細鏄剧ず宸插埌杈俱�佸己鍒剁粨鏉熴�佸己鍒跺畬鎴� -->
+ <template v-else-if="taskDetail.taskStatus === TaskStatus.DEPARTING">
<template v-if="canOperateTask()">
<button
class="action-btn primary"
@@ -514,8 +517,8 @@
</template>
</template>
- <!-- 宸插埌杈剧姸鎬�: 鏄剧ず宸茶繑绋� -->
- <template v-else-if="taskDetail.taskStatus === 'ARRIVED'">
+ <!-- 宸插埌杈剧姸鎬侊細鏄剧ず宸茶繑绋� -->
+ <template v-else-if="taskDetail.taskStatus === TaskStatus.ARRIVED">
<template v-if="canOperateTask()">
<button
class="action-btn primary"
@@ -526,8 +529,8 @@
</template>
</template>
- <!-- 杩旂▼涓姸鎬�: 鏄剧ず宸插畬鎴� -->
- <template v-else-if="taskDetail.taskStatus === 'RETURNING'">
+ <!-- 杩旂▼涓姸鎬侊細鏄剧ず宸插畬鎴� -->
+ <template v-else-if="taskDetail.taskStatus === TaskStatus.RETURNING">
<template v-if="canOperateTask()">
<button
class="action-btn primary"
@@ -538,8 +541,8 @@
</template>
</template>
- <!-- 澶勭悊涓姸鎬�: 鏄剧ず寮哄埗瀹屾垚銆佸彇娑� -->
- <template v-else-if="taskDetail.taskStatus === 'IN_PROGRESS'">
+ <!-- 澶勭悊涓姸鎬侊細鏄剧ず寮哄埗瀹屾垚銆佸彇娑� -->
+ <template v-else-if="taskDetail.taskStatus === TaskStatus.IN_PROGRESS">
<template v-if="canOperateTask()">
<button
class="action-btn primary"
@@ -579,6 +582,7 @@
import { checkTaskInvoice } from '@/api/invoice'
import { formatDateTime } from '@/utils/common'
import { validateTaskForDepart, validateTaskForSettlement, getTaskVehicleId, checkTaskCanDepart } from '@/utils/taskValidator'
+ import { getStatusText as getTaskStatusText, getTaskTypeText as getTaskTypeTextUtil, TaskStatus } from '@/utils/TaskUtil'
import AttachmentUpload from './components/AttachmentUpload.vue'
import config from '@/config'
@@ -588,6 +592,7 @@
},
data() {
return {
+ TaskStatus, // 鏆撮湶 TaskStatus 缁欐ā鏉夸娇鐢�
taskDetail: null,
taskId: null,
paymentInfo: null, // 鏀粯淇℃伅
@@ -663,10 +668,10 @@
return ''
}
const status = this.taskDetail.taskStatus
- if (status === 'PENDING') return 'pending'
- if (['DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'].includes(status)) return 'in_progress'
- if (status === 'COMPLETED') return 'completed'
- if (status === 'CANCELLED') return 'cancelled'
+ if (status === TaskStatus.PENDING || status === TaskStatus.NOT_CONFIRMED || status === TaskStatus.NOT_DEPARTED || status === TaskStatus.PARTIALLY_CONFIRMED) return 'pending'
+ if ([TaskStatus.DEPARTING, TaskStatus.ARRIVED, TaskStatus.RETURNING, TaskStatus.IN_PROGRESS].includes(status)) return 'in_progress'
+ if (status === TaskStatus.COMPLETED) return 'completed'
+ if (status === TaskStatus.CANCELLED) return 'cancelled'
return ''
},
// 鏄剧ず璁″垝寮�濮嬫椂闂�
@@ -895,28 +900,12 @@
// 鑾峰彇鐘舵�佹枃鏈�
getStatusText(status) {
- const statusMap = {
- 'PENDING': '寰呭鐞�',
- 'DEPARTING': '鍑哄彂涓�',
- 'ARRIVED': '宸插埌杈�',
- 'RETURNING': '杩旂▼涓�',
- 'COMPLETED': '宸插畬鎴�',
- 'CANCELLED': '宸插彇娑�',
- 'IN_PROGRESS': '澶勭悊涓�' // 鍏煎鏃ф暟鎹�
- }
- return statusMap[status] || '鏈煡'
+ return getTaskStatusText(status)
},
// 鑾峰彇浠诲姟绫诲瀷鏂囨湰
getTaskTypeText(type) {
- const typeMap = {
- 'MAINTENANCE': '缁翠慨淇濆吇',
- 'FUEL': '鍔犳补',
- 'OTHER': '鍏朵粬',
- 'EMERGENCY_TRANSFER': '杞繍浠诲姟',
- 'WELFARE': '绂忕杞�'
- }
- return typeMap[type] || '鏈煡绫诲瀷'
+ return getTaskTypeTextUtil(type)
},
// 鑾峰彇鐢ㄦ埛绫诲瀷鏍囩
diff --git a/app/utils/TaskUtil.js b/app/utils/TaskUtil.js
new file mode 100644
index 0000000..8dd19dc
--- /dev/null
+++ b/app/utils/TaskUtil.js
@@ -0,0 +1,201 @@
+/**
+ * 浠诲姟宸ュ叿绫�
+ * 鎻愪緵浠诲姟鐩稿叧鐨勯�氱敤宸ュ叿鏂规硶
+ */
+
+/**
+ * 浠诲姟鐘舵�佹灇涓�
+ */
+export const TaskStatus = {
+ /** 寰呭鐞� */
+ PENDING: 'PENDING',
+
+ /** 閮ㄥ垎纭 */
+ PARTIALLY_CONFIRMED: 'PARTIALLY_CONFIRMED',
+
+ /** 瀹屽叏鏈‘璁� */
+ NOT_CONFIRMED: 'NOT_CONFIRMED',
+
+ /** 鏈嚭杞� */
+ NOT_DEPARTED: 'NOT_DEPARTED',
+
+ /** 鍑哄彂涓� */
+ DEPARTING: 'DEPARTING',
+
+ /** 宸插埌杈� */
+ ARRIVED: 'ARRIVED',
+
+ /** 杩旂▼涓� */
+ RETURNING: 'RETURNING',
+
+ /** 宸插畬鎴� */
+ COMPLETED: 'COMPLETED',
+
+ /** 宸插彇娑� */
+ CANCELLED: 'CANCELLED',
+
+ /** 浠诲姟涓� (鍏煎鏃ф暟鎹�) */
+ IN_PROGRESS: 'IN_PROGRESS'
+};
+
+/**
+ * 浠诲姟鐘舵�佹枃鏈槧灏�
+ */
+const STATUS_TEXT_MAP = {
+ [TaskStatus.PENDING]: '寰呭鐞�',
+ [TaskStatus.PARTIALLY_CONFIRMED]: '閮ㄥ垎纭',
+ [TaskStatus.NOT_CONFIRMED]: '瀹屽叏鏈‘璁�',
+ [TaskStatus.NOT_DEPARTED]: '鏈嚭杞�',
+ [TaskStatus.DEPARTING]: '鍑哄彂涓�',
+ [TaskStatus.ARRIVED]: '宸插埌杈�',
+ [TaskStatus.RETURNING]: '杩旂▼涓�',
+ [TaskStatus.COMPLETED]: '宸插畬鎴�',
+ [TaskStatus.CANCELLED]: '宸插彇娑�',
+ [TaskStatus.IN_PROGRESS]: '浠诲姟涓�' // 鍏煎鏃ф暟鎹�
+};
+
+/**
+ * 鑾峰彇浠诲姟鐘舵�佹枃鏈�
+ * @param {string} status - 浠诲姟鐘舵�佷唬鐮�
+ * @returns {string} 浠诲姟鐘舵�佹枃鏈�
+ */
+export function getStatusText(status) {
+ return STATUS_TEXT_MAP[status] || '鏈煡';
+}
+
+/**
+ * 鑾峰彇鎵�鏈変换鍔$姸鎬侀�夐」锛堥�傜敤浜庨�夋嫨鍣級
+ * @returns {Array} 鐘舵�侀�夐」鏁扮粍
+ */
+export function getTaskStatusOptions() {
+ return Object.keys(TaskStatus).map(key => ({
+ value: TaskStatus[key],
+ label: STATUS_TEXT_MAP[TaskStatus[key]]
+ }));
+}
+
+/**
+ * 鍒ゆ柇浠诲姟鏄惁宸插畬鎴�
+ * @param {string} status - 浠诲姟鐘舵�佷唬鐮�
+ * @returns {boolean} 鏄惁宸插畬鎴�
+ */
+export function isTaskCompleted(status) {
+ return status === TaskStatus.COMPLETED;
+}
+
+/**
+ * 鍒ゆ柇浠诲姟鏄惁宸插彇娑�
+ * @param {string} status - 浠诲姟鐘舵�佷唬鐮�
+ * @returns {boolean} 鏄惁宸插彇娑�
+ */
+export function isTaskCancelled(status) {
+ return status === TaskStatus.CANCELLED;
+}
+
+/**
+ * 鍒ゆ柇浠诲姟鏄惁澶勪簬杩涜涓姸鎬侊紙鍖呮嫭寰呭鐞嗐�佸嚭鍙戜腑銆佸凡鍒拌揪銆佽繑绋嬩腑绛夛級
+ * @param {string} status - 浠诲姟鐘舵�佷唬鐮�
+ * @returns {boolean} 鏄惁杩涜涓�
+ */
+export function isTaskInProgress(status) {
+ const activeStatuses = [
+ TaskStatus.PENDING,
+ TaskStatus.PARTIALLY_CONFIRMED,
+ TaskStatus.NOT_CONFIRMED,
+ TaskStatus.NOT_DEPARTED,
+ TaskStatus.DEPARTING,
+ TaskStatus.ARRIVED,
+ TaskStatus.RETURNING,
+ TaskStatus.IN_PROGRESS
+ ];
+ return activeStatuses.includes(status);
+}
+
+/**
+ * 浠诲姟绫诲瀷鏋氫妇
+ */
+export const TaskType = {
+ /** 缁翠慨淇濆吇 */
+ MAINTENANCE: 'MAINTENANCE',
+
+ /** 鍔犳补 */
+ FUEL: 'FUEL',
+
+ /** 鍏朵粬 */
+ OTHER: 'OTHER',
+
+ /** 杞繍浠诲姟 */
+ EMERGENCY_TRANSFER: 'EMERGENCY_TRANSFER',
+
+ /** 绂忕杞� */
+ WELFARE: 'WELFARE',
+
+ // 鏃ф牸寮忥紙鍏煎鐢級
+ /** 缁翠慨淇濆吇锛堟棫锛� */
+ maintenance: 'maintenance',
+
+ /** 鍔犳补锛堟棫锛� */
+ refuel: 'refuel',
+
+ /** 宸℃锛堟棫锛� */
+ inspection: 'inspection',
+
+ /** 杞繍浠诲姟锛堟棫锛� */
+ emergency: 'emergency',
+
+ /** 绂忕杞︼紙鏃э級 */
+ welfare: 'welfare'
+};
+
+/**
+ * 浠诲姟绫诲瀷鏂囨湰鏄犲皠
+ */
+const TYPE_TEXT_MAP = {
+ // 鏂版牸寮忥紙鏁版嵁搴撶被鍨嬶級
+ [TaskType.MAINTENANCE]: '缁翠慨淇濆吇',
+ [TaskType.FUEL]: '鍔犳补',
+ [TaskType.OTHER]: '鍏朵粬',
+ [TaskType.EMERGENCY_TRANSFER]: '杞繍浠诲姟',
+ [TaskType.WELFARE]: '绂忕杞�',
+ // 鏃ф牸寮忥紙UI 绫诲瀷锛�
+ [TaskType.maintenance]: '缁翠慨淇濆吇',
+ [TaskType.refuel]: '鍔犳补',
+ [TaskType.inspection]: '宸℃',
+ [TaskType.emergency]: '杞繍浠诲姟',
+ [TaskType.welfare]: '绂忕杞�'
+};
+
+/**
+ * 鑾峰彇浠诲姟绫诲瀷鏂囨湰
+ * @param {string} type - 浠诲姟绫诲瀷浠g爜
+ * @returns {string} 浠诲姟绫诲瀷鏂囨湰
+ */
+export function getTaskTypeText(type) {
+ return TYPE_TEXT_MAP[type] || '鏈煡绫诲瀷';
+}
+
+/**
+ * 鑾峰彇鎵�鏈変换鍔$被鍨嬮�夐」锛堥�傜敤浜庨�夋嫨鍣級
+ * @returns {Array} 绫诲瀷閫夐」鏁扮粍
+ */
+export function getTaskTypeOptions() {
+ return Object.keys(TaskType).map(key => ({
+ value: TaskType[key],
+ label: TYPE_TEXT_MAP[TaskType[key]]
+ }));
+}
+
+// 榛樿瀵煎嚭
+const TaskUtil = {
+ TaskStatus,
+ TaskType,
+ getStatusText,
+ getTaskStatusOptions,
+ getTaskTypeText,
+ getTaskTypeOptions,
+ isTaskCompleted,
+ isTaskCancelled,
+ isTaskInProgress
+};
+
+export default TaskUtil;
diff --git a/remark.md b/remark.md
new file mode 100644
index 0000000..9798db5
--- /dev/null
+++ b/remark.md
@@ -0,0 +1,6 @@
+鍒嗗叕鍙歌閰嶇疆鍑哄彂鍦板潃
+鏇存柊琛ㄦ暟鎹�
+select ServiceBranch,ServiceAddress,ServiceAddress_lat,ServiceAddress_lng,UnitName,UnitShort,ServiceMinPrice,ServiceUnitPrice,ServiceLong from IntroducerUnitData where UnitState>0 and ServiceAddress_lat is not null and ServiceAddress_lng is not null and ServiceBranch='SZ'
+
+
+update IntroducerUnitData set ServiceAddress='娣卞湷甯傞緳宀楀尯骞虫箹澶ц159鍙峰拰椋庡眳', ServiceAddress_lat=22.684596,ServiceAddress_lng=114.155988 where UnitID=80
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index ffcd5be..fed985b 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -58,7 +58,7 @@
basename: i18n/messages
profiles:
# 鐜 dev|test|prod
- active: prod
+ active: dev
# 鏂囦欢涓婁紶
servlet:
multipart:
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CleanVehicleGpsTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CleanVehicleGpsTask.java
index f177d1d..e089849 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CleanVehicleGpsTask.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CleanVehicleGpsTask.java
@@ -13,17 +13,43 @@
public class CleanVehicleGpsTask {
private static final Logger log = LoggerFactory.getLogger(CleanVehicleGpsTask.class);
+ /** 姣忔壒鍒犻櫎鏁伴噺 */
+ private static final int BATCH_SIZE = 10000;
+ /** 姣忔壒闂撮殧鏃堕棿锛堟绉掞級锛岄伩鍏嶈繛缁垹闄ゅ鏁版嵁搴撳帇鍔涜繃澶� */
+ private static final long BATCH_INTERVAL_MS = 500;
+
@Autowired
private IVehicleGpsService vehicleGpsService;
/**
- * 娓呯悊杞﹁締GPS鍘嗗彶鏁版嵁
+ * 娓呯悊杞﹁締GPS鍘嗗彶鏁版嵁锛堜繚鐣欐渶杩�2涓湀锛屽垎鎵瑰垹闄わ級
*/
public void cleanVehicleGpsData() {
try {
-// log.info("寮�濮嬫竻鐞嗚溅杈咷PS鍘嗗彶鏁版嵁");
- int count = vehicleGpsService.deleteVehicleGpsBeforeDate();
-// log.info("娓呯悊杞﹁締GPS鍘嗗彶鏁版嵁瀹屾垚锛屽叡娓呯悊{}鏉¤褰�", count);
+ log.info("寮�濮嬫竻鐞嗚溅杈咷PS鍘嗗彶鏁版嵁锛堜繚鐣欐渶杩�2涓湀锛屾瘡鎵� {} 鏉★級", BATCH_SIZE);
+ int totalCount = 0;
+ int batchCount;
+ int round = 0;
+ do {
+ batchCount = vehicleGpsService.deleteVehicleGpsBeforeDateBatch(BATCH_SIZE);
+ totalCount += batchCount;
+ round++;
+ log.info("绗� {} 鎵规竻鐞嗗畬鎴愶紝鏈壒鍒犻櫎 {} 鏉★紝宸插垹闄ゅ悎璁� {} 鏉�", round, batchCount, totalCount);
+ if (batchCount == BATCH_SIZE) {
+ // 杩樻湁鏁版嵁锛岀◢浣滀紤鐪犲啀缁х画
+ Thread.sleep(BATCH_INTERVAL_MS);
+ }
+ } while (batchCount == BATCH_SIZE);
+
+ log.info("娓呯悊杞﹁締GPS鍘嗗彶鏁版嵁瀹屾垚锛屽叡 {} 鎵癸紝鍒犻櫎 {} 鏉¤褰�", round, totalCount);
+
+ if (totalCount > 0) {
+ log.info("寮�濮嬫墽琛� OPTIMIZE TABLE锛屽洖鏀剁鐩樼┖闂达紙姝ゆ搷浣滆�楁椂杈冮暱锛岃鍕夸腑鏂級");
+ vehicleGpsService.optimizeVehicleGpsTable();
+ log.info("OPTIMIZE TABLE 鎵ц瀹屾垚");
+ } else {
+ log.info("鏈鏃犲彲娓呯悊鐨勮褰曪紝璺宠繃 OPTIMIZE TABLE");
+ }
} catch (Exception e) {
log.error("娓呯悊杞﹁締GPS鍘嗗彶鏁版嵁寮傚父", e);
}
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
index e16b50d..3f229ca 100644
--- 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
@@ -9,7 +9,20 @@
/** 寰呭鐞� */
PENDING("PENDING", "寰呭鐞�"),
-
+
+ /**
+ * 閮ㄥ垎纭
+ */
+ PARTIALLY_CONFIRMED("PARTIALLY_CONFIRMED", "閮ㄥ垎纭"),
+ /**
+ * 瀹屽叏鏈‘璁�
+ */
+ NOT_CONFIRMED("NOT_CONFIRMED", "瀹屽叏鏈‘璁�"),
+ /**
+ * 鏈嚭杞�
+ */
+ NOT_DEPARTED("NOT_DEPARTED", "鏈嚭杞�"),
+
/** 鍑哄彂涓� */
DEPARTING("DEPARTING", "鍑哄彂涓�"),
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleGpsMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleGpsMapper.java
index d8afe11..7fab119 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleGpsMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleGpsMapper.java
@@ -52,6 +52,19 @@
public int deleteVehicleGpsBeforeDate();
/**
+ * 鍒嗘壒鍒犻櫎鎸囧畾鏃ユ湡涔嬪墠鐨勮溅杈咷PS鏁版嵁锛堝甫 LIMIT锛�
+ *
+ * @param batchSize 姣忔壒鍒犻櫎鏉℃暟
+ * @return 鏈壒鍒犻櫎鐨勮褰曟暟
+ */
+ public int deleteVehicleGpsBeforeDateBatch(@Param("batchSize") int batchSize);
+
+ /**
+ * 浼樺寲琛紝鍥炴敹DELETE鍚庣殑纾佺洏纰庣墖绌洪棿
+ */
+ public void optimizeVehicleGpsTable();
+
+ /**
* 鏌ヨ杞﹁締鍦ㄦ寚瀹氭椂闂磋寖鍥村唴鐨凣PS鏁版嵁锛堟寜閲囬泦鏃堕棿鎺掑簭锛�
*
* @param vehicleId 杞﹁締ID
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleGpsService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleGpsService.java
index 970c3ac..6e07ff8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleGpsService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleGpsService.java
@@ -43,4 +43,17 @@
* @return 鍒犻櫎鐨勮褰曟暟
*/
public int deleteVehicleGpsBeforeDate();
+
+ /**
+ * 鍒嗘壒鍒犻櫎鎸囧畾鏃ユ湡涔嬪墠鐨勮溅杈咷PS鏁版嵁
+ *
+ * @param batchSize 姣忔壒鍒犻櫎鏉℃暟
+ * @return 鏈壒鍒犻櫎鐨勮褰曟暟
+ */
+ public int deleteVehicleGpsBeforeDateBatch(int batchSize);
+
+ /**
+ * 浼樺寲琛紝鍥炴敹DELETE鍚庣殑纾佺洏纰庣墖绌洪棿
+ */
+ public void optimizeVehicleGpsTable();
}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java
index ad9eb5a..96ce0d7 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java
@@ -79,4 +79,20 @@
public int deleteVehicleGpsBeforeDate() {
return vehicleGpsMapper.deleteVehicleGpsBeforeDate();
}
+
+ /**
+ * 鍒嗘壒鍒犻櫎鎸囧畾鏃ユ湡涔嬪墠鐨勮溅杈咷PS鏁版嵁
+ */
+ @Override
+ public int deleteVehicleGpsBeforeDateBatch(int batchSize) {
+ return vehicleGpsMapper.deleteVehicleGpsBeforeDateBatch(batchSize);
+ }
+
+ /**
+ * 浼樺寲琛紝鍥炴敹DELETE鍚庣殑纾佺洏纰庣墖绌洪棿
+ */
+ @Override
+ public void optimizeVehicleGpsTable() {
+ vehicleGpsMapper.optimizeVehicleGpsTable();
+ }
}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusConverter.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusConverter.java
index eb82fa1..593052e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusConverter.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusConverter.java
@@ -45,11 +45,13 @@
switch (legacyStatusCode) {
case 0: // 鏂拌皟搴﹀崟锛堟湭涓嬪彂锛�
- case 1: // 瀹屽叏鏈‘璁�
- case 2: // 閮ㄥ垎宸茬‘璁�
- case 3: // 鏈嚭杞�
return TaskStatus.PENDING;
-
+ case 1: // 瀹屽叏鏈‘璁�
+ return TaskStatus.NOT_CONFIRMED;
+ case 2: // 閮ㄥ垎宸茬‘璁�
+ return TaskStatus.PARTIALLY_CONFIRMED;
+ case 3: // 鏈嚭杞�
+ return TaskStatus.NOT_DEPARTED;
case 4: // 宸插嚭杞︼紙鍘绘帴鎮h�呴�斾腑锛�
return TaskStatus.DEPARTING;
@@ -85,11 +87,32 @@
log.warn("鏂扮郴缁熶换鍔$姸鎬佷负绌�");
return null;
}
-
+ /**
+ * 0 0 - 鏂拌皟搴﹀崟锛堟湭涓嬪彂锛�
+ * 1 1 - 瀹屽叏鏈‘璁�
+ * 2 2 - 閮ㄥ垎宸茬‘璁�
+ * 3 鏈嚭杞�
+ * 4 3 - 宸插嚭杞︼紙鍘绘帴鎮h�呴�斾腑锛�
+ * 5 宸插嚭杞︼紙绛夊緟鎮h�咃級
+ * 6 4 - 宸插嚭杞︼紙鏈嶅姟涓級
+ * 7 5 - 宸查�佽揪锛堝洖绋嬩腑锛�
+ * 8 宸茶繑鍥�
+ * 9 璺戠┖鍗曪紝宸茶繑鍥�
+ * 10 鍙栨秷
+ * 11 宸叉彁浜わ紝绛夊緟瀹℃牳
+ * 12 瀹℃牳瀹屾垚
+ * 13 瀹℃牳涓嶉�氳繃
+ * 14 宸查┗鐐�
+ */
switch (taskStatus) {
- case PENDING:
+ case NOT_DEPARTED:
return 3; // 鏈嚭杞�
-
+ case NOT_CONFIRMED:
+ return 1; // 瀹屽叏鏈‘璁�
+ case PARTIALLY_CONFIRMED:
+ return 2; // 閮ㄥ垎纭
+ case PENDING:
+ return 0; // 鏈嚭杞�
case DEPARTING:
return 4; // 宸插嚭杞︼紙鍘绘帴鎮h�呴�斾腑锛�
diff --git a/ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml b/ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml
index 0aa55dd..984d7f1 100644
--- a/ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml
@@ -112,14 +112,20 @@
</select>
<delete id="deleteVehicleGpsBeforeDate">
- delete g from tb_vehicle_gps g
- where g.collect_time < (
- select date_sub(max(collect_time), interval 2 day)
- from tb_vehicle_gps g2
- where g2.vehicle_id = g.vehicle_id
- )
+ delete from tb_vehicle_gps
+ where collect_time < DATE_SUB(NOW(), INTERVAL 2 MONTH)
</delete>
+ <delete id="deleteVehicleGpsBeforeDateBatch">
+ delete from tb_vehicle_gps
+ where collect_time < DATE_SUB(NOW(), INTERVAL 2 MONTH)
+ LIMIT #{batchSize}
+ </delete>
+
+ <update id="optimizeVehicleGpsTable">
+ OPTIMIZE TABLE tb_vehicle_gps
+ </update>
+
<select id="selectGpsDataByTimeRange" resultMap="VehicleGpsResult">
select gps_id, vehicle_id, device_id, longitude, latitude, altitude, speed, direction,
collect_time, device_report_time, platform_process_time, create_time
diff --git a/ruoyi-system/src/main/resources/mapper/system/VehicleGpsSegmentMileageMapper.xml b/ruoyi-system/src/main/resources/mapper/system/VehicleGpsSegmentMileageMapper.xml
index c56d5d6..8b6f6c8 100644
--- a/ruoyi-system/src/main/resources/mapper/system/VehicleGpsSegmentMileageMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/VehicleGpsSegmentMileageMapper.xml
@@ -99,6 +99,7 @@
WHERE task_id = #{taskId}
</select>
+ <!-- 鎻掑叆鎴栨洿鏂板垎娈甸噷绋嬭褰曪紙閬垮厤閲嶅鎻掑叆锛� -->
<insert id="insertVehicleGpsSegmentMileage" parameterType="VehicleGpsSegmentMileage">
INSERT INTO tb_vehicle_gps_segment_mileage
<trim prefix="(" suffix=")" suffixOverrides=",">
@@ -133,6 +134,20 @@
<if test="taskCode != null">#{taskCode},</if>
<if test="calculateMethod != null">#{calculateMethod},</if>
</trim>
+ ON DUPLICATE KEY UPDATE
+ vehicle_no = VALUES(vehicle_no),
+ segment_end_time = VALUES(segment_end_time),
+ start_longitude = VALUES(start_longitude),
+ start_latitude = VALUES(start_latitude),
+ end_longitude = VALUES(end_longitude),
+ end_latitude = VALUES(end_latitude),
+ segment_distance = VALUES(segment_distance),
+ gps_point_count = VALUES(gps_point_count),
+ gps_ids = VALUES(gps_ids),
+ task_id = VALUES(task_id),
+ task_code = VALUES(task_code),
+ calculate_method = VALUES(calculate_method),
+ update_time = NOW()
</insert>
<update id="updateVehicleGpsSegmentMileage" parameterType="VehicleGpsSegmentMileage">
diff --git a/sql/clean_gps.sql b/sql/clean_gps.sql
index 692b8e8..1ec063b 100644
--- a/sql/clean_gps.sql
+++ b/sql/clean_gps.sql
@@ -1,27 +1,36 @@
+-- ----------------------------
+-- 娓呯悊杞﹁締GPS鍘嗗彶鏁版嵁瀹氭椂浠诲姟閰嶇疆
+-- 璇存槑锛氭瘡澶╁噷鏅�2鐐规墽琛岋紝淇濈暀鏈�杩�2涓湀鏁版嵁锛岃秴鍑洪儴鍒嗗垎鎵瑰垹闄わ紙姣忔壒1涓囨潯锛�
+-- ----------------------------
+
+-- 濡傛灉宸插瓨鍦ㄥ悓鍚嶄换鍔″厛鍒犻櫎锛岄伩鍏嶉噸澶嶆彃鍏�
+DELETE FROM sys_job
+WHERE job_name = '娓呯悊杞﹁締GPS鍘嗗彶鏁版嵁' AND job_group = 'DEFAULT';
+
INSERT INTO sys_job (
- job_name,
- job_group,
- invoke_target,
- cron_expression,
- misfire_policy,
- concurrent,
- status,
- create_by,
- create_time,
- update_by,
- update_time,
+ job_name,
+ job_group,
+ invoke_target,
+ cron_expression,
+ misfire_policy,
+ concurrent,
+ status,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
remark
) VALUES (
'娓呯悊杞﹁締GPS鍘嗗彶鏁版嵁',
'DEFAULT',
'cleanVehicleGpsTask.cleanVehicleGpsData()',
- '0 0 1 * * ?',
- '1',
+ '0 0 2 * * ?',
+ '3',
'1',
'0',
'admin',
sysdate(),
'admin',
sysdate(),
- '姣忓ぉ鍑屾櫒1鐐规竻鐞嗚溅杈咷PS鍘嗗彶鏁版嵁锛屽彧淇濈暀姣忓彴杞︽渶鍚�2澶╃殑鏁版嵁'
+ '姣忓ぉ鍑屾櫒2鐐规墽琛岋紝鍒嗘壒鍒犻櫎tb_vehicle_gps涓秴杩�2涓湀鐨勫巻鍙叉暟鎹紙姣忔壒1涓囨潯锛屾壒娆¢棿闅�500ms锛夛紝鍒犻櫎瀹屾垚鍚庢墽琛孫PTIMIZE TABLE鍥炴敹纾佺洏绌洪棿'
);
\ No newline at end of file
--
Gitblit v1.9.1