diff --git a/admin/src/App.vue b/admin/src/App.vue
index 9ad6de5..6baff72 100644
--- a/admin/src/App.vue
+++ b/admin/src/App.vue
@@ -138,6 +138,7 @@
@reject="handleReject"
@reject-many="handleRejectMany"
@exempt="handleExempt"
+ @exempt-many="handleExemptMany"
@reclaim="handleReclaim"
/>
@@ -542,6 +543,15 @@ async function handleExempt(input: { taskId: string; note?: string }) {
}, '宸叉爣璁板厤娓呮磥');
}
+async function handleExemptMany(input: { taskIds: string[]; note?: string }) {
+ await runAction(async () => {
+ for (const taskId of input.taskIds) {
+ await exemptCleaningTask(session.value, taskId, input.note);
+ }
+ await Promise.all([loadTasks(), loadStatistics()]);
+ }, `\u5df2\u6279\u91cf\u6807\u8bb0\u514d\u6e05\u6d01 ${input.taskIds.length} \u4e2a\u4efb\u52a1`);
+}
+
async function handleReclaim(input: { olderThanMinutes: number; limit: number }) {
await runAction(async () => {
await reclaimCleaningTimeouts(session.value, input);
diff --git a/admin/src/components/CleaningTasksPanel.vue b/admin/src/components/CleaningTasksPanel.vue
index e48c7cd..d2a1799 100644
--- a/admin/src/components/CleaningTasksPanel.vue
+++ b/admin/src/components/CleaningTasksPanel.vue
@@ -53,6 +53,14 @@
>
批量驳回
+
+ {{ '\u6279\u91cf\u514d\u6e05\u6d01' }}
+
回收
@@ -478,6 +486,7 @@ const emit = defineEmits<{
reject: [{ taskId: string; reason: string }];
'reject-many': [{ taskIds: string[]; reason: string }];
exempt: [{ taskId: string; note?: string }];
+ 'exempt-many': [{ taskIds: string[]; note?: string }];
reclaim: [{ olderThanMinutes: number; limit: number }];
}>();
@@ -526,6 +535,9 @@ const memberDialog = reactive({
const selectedSubmittedTasks = computed(() => selectedTasks.value
.filter((task) => task.status === 'SUBMITTED'));
const selectedSubmittedCount = computed(() => selectedSubmittedTasks.value.length);
+const selectedExemptableTasks = computed(() => selectedTasks.value
+ .filter((task) => canExempt(task.status)));
+const selectedExemptableCount = computed(() => selectedExemptableTasks.value.length);
watch(
() => props.filters,
@@ -541,7 +553,7 @@ function taskTag(status: TaskStatus) {
}
function canSelectTask(row: CleaningTask) {
- return row.status === 'SUBMITTED';
+ return row.status === 'SUBMITTED' || canExempt(row.status);
}
function canExempt(status: TaskStatus) {
@@ -648,6 +660,18 @@ function submitBatchReject() {
batchRejectDialog.open = false;
}
+function submitBatchExempt() {
+ const taskIds = selectedExemptableTasks.value.map((task) => task.id);
+ if (!taskIds.length) {
+ ElMessage.warning('\u8bf7\u9009\u62e9\u53ef\u514d\u6e05\u6d01\u4efb\u52a1');
+ return;
+ }
+ emit('exempt-many', {
+ taskIds,
+ note: '\u540e\u53f0\u6279\u91cf\u6807\u8bb0\u514d\u6e05\u6d01'
+ });
+}
+
async function loadMembers() {
memberDialog.loading = true;
try {
diff --git a/scripts/check-admin-m08-b.mjs b/scripts/check-admin-m08-b.mjs
index 7b35f7e..6c4e8de 100644
--- a/scripts/check-admin-m08-b.mjs
+++ b/scripts/check-admin-m08-b.mjs
@@ -34,6 +34,7 @@ for (const pattern of [
'handleCompleteMany',
'handleRejectMany',
'handleExempt',
+ 'handleExemptMany',
'运营待处理',
'jumpToTaskStatus',
'jumpToSettlementStatus',
@@ -94,10 +95,14 @@ for (const pattern of [
'批量验收',
'批量驳回',
'selectedSubmittedTasks',
+ 'selectedExemptableTasks',
+ 'selectedExemptableCount',
'complete-many',
'reject-many',
+ 'exempt-many',
'exempt',
'canExempt',
+ '\\u6279\\u91cf\\u514d\\u6e05\\u6d01',
'EXEMPT',
'photo-grid',
'timeline-grid',