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清理后台任务
---
app/pagesTask/detail.vue | 248 ++++++++++++++++++++++++++++++++++++-------------
1 files changed, 183 insertions(+), 65 deletions(-)
diff --git a/app/pagesTask/detail.vue b/app/pagesTask/detail.vue
index 9077526..ca3c762 100644
--- a/app/pagesTask/detail.vue
+++ b/app/pagesTask/detail.vue
@@ -7,6 +7,7 @@
<view class="title">浠诲姟璇︽儏</view>
<view class="edit-btn" @click="handleEdit" v-if="taskDetail && !isTaskFinished">
<uni-icons type="compose" size="20" color="#007AFF"></uni-icons>
+ <text class="edit-text">淇敼</text>
</view>
</view>
@@ -70,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"
@@ -236,7 +237,17 @@
<!-- 杞繍 - 璐圭敤淇℃伅 -->
<view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo">
- <view class="section-title">璐圭敤淇℃伅</view>
+ <view class="section-title">
+ 璐圭敤淇℃伅
+ <!-- 宸插畬鎴愪笖鏈敵璇峰彂绁ㄦ椂鏄剧ず鐢宠鍙戠エ鎸夐挳 -->
+ <button
+ v-if="canApplyInvoice"
+ class="apply-invoice-btn"
+ @click="handleApplyInvoice"
+ >
+ <text class="cuIcon-form"></text> 鐢宠鍙戠エ
+ </button>
+ </view>
<view class="info-item" v-if="taskDetail.emergencyInfo.transferDistance">
<view class="label">杞繍鍏噷鏁�</view>
<view class="value">{{ taskDetail.emergencyInfo.transferDistance }}鍏噷</view>
@@ -264,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>
@@ -454,34 +465,36 @@
<!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
<view class="action-buttons" v-if="taskDetail">
- <!-- 寰呭鐞嗙姸鎬�: 鏄剧ず鍑哄彂銆佸彇娑堛�佸己鍒跺畬鎴� -->
- <template v-if="taskDetail.taskStatus === 'PENDING'">
- <template v-if="isCurrentUserAssignee()">
- <button
- class="action-btn primary"
- @click="handleDepartAction()"
- >
- 鍑哄彂
- </button>
- <button
- class="action-btn cancel"
- @click="handleTaskAction('cancel')"
- >
- 鍙栨秷
- </button>
- <button
- v-if="showForceCompleteFeature() && taskDetail.taskStatus === 'PENDING'"
- class="action-btn force-complete"
- @click="showForceCompleteTimeDialog()"
- >
- 寮哄埗瀹屾垚
- </button>
- </template>
+ <!-- 寰呭鐞嗙姸鎬侊細鏄剧ず鍑哄彂銆佸彇娑堛�佸己鍒跺畬鎴� -->
+ <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"
+ @click="handleDepartAction()"
+ >
+ 鍑哄彂
+ </button>
+ <button
+ class="action-btn cancel"
+ @click="handleTaskAction('cancel')"
+ >
+ 鍙栨秷
+ </button>
+ <button
+ v-if="canOperateTask() && showForceCompleteFeature()"
+ class="action-btn force-complete"
+ @click="showForceCompleteTimeDialog()"
+ >
+ 寮哄埗瀹屾垚
+ </button>
</template>
-
- <!-- 鍑哄彂涓姸鎬�: 鏄剧ず宸插埌杈俱�佸己鍒剁粨鏉� -->
- <template v-else-if="taskDetail.taskStatus === 'DEPARTING'">
- <template v-if="isCurrentUserAssignee()">
+
+ <!-- 鍑哄彂涓姸鎬侊細鏄剧ず宸插埌杈俱�佸己鍒剁粨鏉熴�佸己鍒跺畬鎴� -->
+ <template v-else-if="taskDetail.taskStatus === TaskStatus.DEPARTING">
+ <template v-if="canOperateTask()">
<button
class="action-btn primary"
@click="handleTaskAction('arrive')"
@@ -494,12 +507,19 @@
>
寮哄埗缁撴潫
</button>
+ <button
+ v-if="showForceCompleteFeature()"
+ class="action-btn force-complete"
+ @click="showForceCompleteTimeDialog()"
+ >
+ 寮哄埗瀹屾垚
+ </button>
</template>
</template>
- <!-- 宸插埌杈剧姸鎬�: 鏄剧ず宸茶繑绋� -->
- <template v-else-if="taskDetail.taskStatus === 'ARRIVED'">
- <template v-if="isCurrentUserAssignee()">
+ <!-- 宸插埌杈剧姸鎬侊細鏄剧ず宸茶繑绋� -->
+ <template v-else-if="taskDetail.taskStatus === TaskStatus.ARRIVED">
+ <template v-if="canOperateTask()">
<button
class="action-btn primary"
@click="handleTaskAction('return')"
@@ -509,15 +529,34 @@
</template>
</template>
- <!-- 杩旂▼涓姸鎬�: 鏄剧ず宸插畬鎴� -->
- <template v-else-if="taskDetail.taskStatus === 'RETURNING'">
- <template v-if="isCurrentUserAssignee()">
+ <!-- 杩旂▼涓姸鎬侊細鏄剧ず宸插畬鎴� -->
+ <template v-else-if="taskDetail.taskStatus === TaskStatus.RETURNING">
+ <template v-if="canOperateTask()">
<button
class="action-btn primary"
@click="handleTaskAction('complete')"
>
宸插畬鎴�
</button>
+ </template>
+ </template>
+
+ <!-- 澶勭悊涓姸鎬侊細鏄剧ず寮哄埗瀹屾垚銆佸彇娑� -->
+ <template v-else-if="taskDetail.taskStatus === TaskStatus.IN_PROGRESS">
+ <template v-if="canOperateTask()">
+ <button
+ class="action-btn primary"
+ @click="handleTaskAction('arrive')"
+ >
+ 宸插埌杈�
+ </button>
+ <button
+ v-if="showForceCompleteFeature()"
+ class="action-btn force-complete"
+ @click="showForceCompleteTimeDialog()"
+ >
+ 寮哄埗瀹屾垚
+ </button>
</template>
</template>
@@ -540,8 +579,10 @@
import { checkVehicleActiveTasks } from '@/api/task'
import { getPaymentInfo } from '@/api/payment'
import { getDicts } from '@/api/dict'
+ 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'
@@ -551,6 +592,7 @@
},
data() {
return {
+ TaskStatus, // 鏆撮湶 TaskStatus 缁欐ā鏉夸娇鐢�
taskDetail: null,
taskId: null,
paymentInfo: null, // 鏀粯淇℃伅
@@ -561,7 +603,9 @@
forceCompleteForm: {
actualStartTime: '',
actualEndTime: ''
- }
+ },
+ hasInvoiceApplied: false, // 鏄惁宸茬敵璇峰彂绁�
+ invoiceStatus: null // 鍙戠エ鐘舵�侊細0-寰呭鏍�, 1-宸查�氳繃, 2-宸查┏鍥�
}
},
computed: {
@@ -571,6 +615,16 @@
return false
}
return ['COMPLETED', 'CANCELLED'].includes(this.taskDetail.taskStatus)
+ },
+
+ // 鏄惁鍙互鐢宠鍙戠エ
+ canApplyInvoice() {
+ // 浠呮�ユ晳杞繍浠诲姟
+ if (this.taskDetail?.taskType !== 'EMERGENCY_TRANSFER') return false
+ // 浠诲姟蹇呴』宸插畬鎴�
+ if (this.taskDetail?.taskStatus !== 'COMPLETED') return false
+ // 鏈敵璇疯繃鍙戠エ锛屾垨鏇捐椹冲洖
+ return !this.hasInvoiceApplied || this.invoiceStatus === 2
},
// 鐢熸垚鎵ц浜哄憳瑙掕壊鏍囩鐨勭被鍚�
@@ -614,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 ''
},
// 鏄剧ず璁″垝寮�濮嬫椂闂�
@@ -673,6 +727,8 @@
this.taskId = options.id
this.loadTaskDetail()
this.loadCancelReasonDict() // 鍔犺浇鍙栨秷鍘熷洜瀛楀吀
+ // 妫�鏌ュ彂绁ㄧ敵璇风姸鎬�
+ this.checkInvoiceStatus()
},
onShow() {
// 姣忔椤甸潰鏄剧ず鏃堕噸鏂板姞杞芥暟鎹紝纭繚浠庣紪杈戦〉闈㈣繑鍥炲悗鑳界湅鍒版渶鏂版暟鎹�
@@ -844,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)
},
// 鑾峰彇鐢ㄦ埛绫诲瀷鏍囩
@@ -914,10 +954,8 @@
break;
case 'forceCancel':
- // 寮哄埗缁撴潫 -> 鐘舵�佸彉涓哄凡鍙栨秷
- this.$modal.confirm('纭畾瑕佸己鍒剁粨鏉熸浠诲姟鍚楋紵').then(() => {
- this.updateTaskStatus('CANCELLED', '浠诲姟宸插己鍒剁粨鏉�')
- }).catch(() => {});
+ // 寮哄埗缁撴潫 -> 鏄剧ず鍙栨秷鍘熷洜閫夋嫨瀵硅瘽妗�
+ this.showCancelReasonDialog();
break;
case 'return':
@@ -1034,6 +1072,45 @@
}
return null;
+ },
+
+ // 妫�鏌ュ彂绁ㄧ敵璇风姸鎬�
+ checkInvoiceStatus() {
+ if (!this.taskId) return;
+
+ // 璋冪敤鍚庣鎺ュ彛妫�鏌ヨ浠诲姟鏄惁宸茬敵璇峰彂绁�
+ checkTaskInvoice(this.taskId).then(response => {
+ if (response.code === 200 && response.data) {
+ this.hasInvoiceApplied = true;
+ this.invoiceStatus = response.data.status;
+ }
+ }).catch(error => {
+ console.error('妫�鏌ュ彂绁ㄧ敵璇风姸鎬佸け璐�:', error);
+ // 蹇界暐閿欒锛岄粯璁ゆ湭鐢宠
+ });
+ },
+
+ // 鐢宠鍙戠エ
+ handleApplyInvoice() {
+ // 鍑嗗浠诲姟淇℃伅
+ const taskInfo = {
+ taskId: this.taskDetail.taskId,
+ taskCode: this.taskDetail.showTaskCode || this.taskDetail.taskCode,
+ legacyServiceOrderId: this.taskDetail.emergencyInfo?.legacyServiceOrdId,
+ serviceCode: this.taskDetail.emergencyInfo?.serviceCode,
+ departure: this.taskDetail.departureAddress,
+ destination: this.taskDetail.destinationAddress,
+ completionTime: this.formatTime(this.taskDetail.actualEndTime),
+ transferPrice: this.paymentInfo?.transferPrice || this.paymentInfo?.totalAmount
+ };
+
+ // 灏嗕换鍔′俊鎭簭鍒楀寲涓� URL 鍙傛暟
+ const taskInfoParam = encodeURIComponent(JSON.stringify(taskInfo));
+
+ // 璺宠浆鍒板彂绁ㄧ敵璇烽〉闈紝浼犻�掍换鍔′俊鎭�
+ uni.navigateTo({
+ url: `/pages/mine/invoice/apply?taskInfo=${taskInfoParam}`
+ });
},
// 鏇存柊浠诲姟鐘舵��
@@ -1504,6 +1581,19 @@
const list = (this.taskDetail && Array.isArray(this.taskDetail.assignees)) ? this.taskDetail.assignees : []
return list.some(a => a && (a.userId === userId || a.oaUserId === userId))
},
+
+ // 鏄惁褰撳墠鐢ㄦ埛鍙互鎿嶄綔浠诲姟锛堟墽琛屼汉鎴栫鐞嗗憳锛�
+ canOperateTask() {
+ // 妫�鏌ユ槸鍚︽槸绠$悊鍛橈紙canViewAllConsult === '1'锛�
+
+ const canViewAllConsult = this.$store && this.$store.state && this.$store.state.user && this.$store.state.user.canViewAllConsult
+ console.log("褰撳墠鐢ㄦ埛鏄惁鏄鐞嗗憳:", canViewAllConsult)
+ if (canViewAllConsult === '1') {
+ return true
+ }
+ // 妫�鏌ユ槸鍚︽槸浠诲姟鎵ц浜�
+ return this.isCurrentUserAssignee()
+ },
// 鏄惁澶氫汉鎵ц
isMultipleAssignees() {
@@ -1877,12 +1967,18 @@
}
.edit-btn {
- width: 60rpx;
+ width: 120rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
+
+ .edit-text {
+ margin-left: 8rpx;
+ font-size: 28rpx;
+ color: #007AFF;
+ }
}
}
@@ -2198,10 +2294,13 @@
flex: 1;
height: 80rpx;
border-radius: 10rpx;
- font-size: 30rpx;
+ font-size: 28rpx;
margin: 0 10rpx;
background-color: #f0f0f0;
color: #333;
+ white-space: nowrap;
+ padding: 0 10rpx;
+ min-width: 0;
&.edit {
background-color: #ff9500;
@@ -2215,6 +2314,11 @@
&.cancel {
background-color: #ff3b30;
+ color: white;
+ }
+
+ &.force-end {
+ background-color: #ff6b22;
color: white;
}
@@ -2259,6 +2363,20 @@
margin-left: 10rpx;
vertical-align: middle;
}
+
+ .apply-invoice-btn {
+ padding: 8rpx 16rpx;
+ font-size: 24rpx;
+ color: #fff;
+ background-color: #34C759;
+ border: none;
+ border-radius: 6rpx;
+ margin-left: 20rpx;
+ }
+
+ .apply-invoice-btn::after {
+ border: none;
+ }
// 鍙栨秷鍘熷洜瀵硅瘽妗嗘牱寮�
.cancel-dialog {
--
Gitblit v1.9.1