This commit is contained in:
2026-08-17 18:00:42 +08:00
parent c7334b2cf8
commit ec3dbb3fe4
23 changed files with 407 additions and 999 deletions
@@ -1,7 +1,8 @@
<script setup lang="ts">
import { computed, onActivated, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { Eye, Ruler, SearchCheck } from '@lucide/vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { CircleCheckBig, Eye, Ruler, SearchCheck } from '@lucide/vue'
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { listPlatformTenants, type PlatformTenantResource } from '@/modules/iam'
import { listPlatformWarehouses } from '@/modules/warehouses'
@@ -16,6 +17,7 @@ import { listPlatformInbounds } from '../core/api'
import type { InboundOrderSummary } from '../core/types'
import InboundMeasurementDialog from '../measurement/InboundMeasurementDialog.vue'
import MeasurementReviewPanel from '../review/MeasurementReviewPanel.vue'
import { approveMeasurement, getMeasurementReviewDetail } from '../review/api'
import { inboundProcessStatusLabels, inboundReviewStatusLabels, inboundStatusLabel } from '../status'
import { buildInboundTaskQuery, loadAllActiveCustomers, type InboundTaskMode } from '../task-list'
@@ -42,6 +44,8 @@ const warehouseOptions = ref<Array<{ label: string; value: string }>>([])
const selectedInbound = ref<InboundOrderSummary | null>(null)
const measurementDialogOpen = ref(false)
const reviewDialogOpen = ref(false)
const batchReviewLoading = ref(false)
const selectedReviewRows = ref<InboundOrderSummary[]>([])
let requestSerial = 0
let optionsRequestSerial = 0
let disposed = false
@@ -73,8 +77,12 @@ const queryFields = computed<QueryField[]>(() => [
{ key: 'expectedArrivalRange', type: 'daterange', label: '预计到达时间', width: 320, placeholder: '请选择日期范围' },
])
const columns: DataTableColumn[] = [
const columns = computed<DataTableColumn[]>(() => [
{ key: 'actions', label: '操作', width: 190, fixed: 'left', slotName: 'actions' },
...(isReview.value && access.can(actionPermission.value) ? [{
key: 'selection', type: 'selection', width: 48, fixed: 'left',
selectable: (row: InboundOrderSummary) => row.measureReviewStatus === 'PENDING' && !batchReviewLoading.value,
} satisfies DataTableColumn] : []),
{ key: 'inboundCode', label: '入仓码', minWidth: 170, slotName: 'inboundCode' },
{ key: 'processStatus', label: '流程状态', minWidth: 132, slotName: 'processStatus' },
{ key: 'measureReviewStatus', label: '测量审核状态', minWidth: 142, slotName: 'measureReviewStatus' },
@@ -88,7 +96,7 @@ const columns: DataTableColumn[] = [
{ key: 'actualGrossWeightKg', label: '实测毛重(kg)', minWidth: 128, slotName: 'actualGrossWeightKg' },
{ key: 'actualVolumeCbm', label: '实测体积(m³)', minWidth: 128, slotName: 'actualVolumeCbm' },
{ key: 'measureCompletedAt', label: '测量完成时间', minWidth: 164, slotName: 'measureCompletedAt' },
]
])
function text(value: unknown) {
return value === null || value === undefined || value === '' ? '—' : String(value)
@@ -129,6 +137,7 @@ async function loadOptions() {
}
async function loadTasks() {
selectedReviewRows.value = []
const serial = ++requestSerial
loading.value = true
loadError.value = null
@@ -182,6 +191,48 @@ function handleTaskChanged() {
void loadTasks()
}
function handleReviewSelectionChange(rows: InboundOrderSummary[]) {
selectedReviewRows.value = rows.filter((row) => row.measureReviewStatus === 'PENDING')
}
async function batchApproveMeasurements() {
const selected = [...selectedReviewRows.value]
if (!selected.length || batchReviewLoading.value) return
batchReviewLoading.value = true
try {
await ElMessageBox.confirm(
`确认批量审核通过已勾选的 ${selected.length} 条测量数据吗?通过后将进入待分柜。`,
'批量审核测量数据',
{ confirmButtonText: '确认批量审核', cancelButtonText: '取消', type: 'warning' },
)
let successCount = 0
let failureCount = 0
const failures: string[] = []
for (const row of selected) {
try {
const detail = await getMeasurementReviewDetail(String(row.tenantId), String(row.id))
await approveMeasurement(String(row.tenantId), String(row.id), {
measurementId: detail.measurementId,
expectedVersion: detail.version,
})
successCount += 1
} catch (error) {
failureCount += 1
failures.push(getApiErrorDetails(error, `${row.inboundCode || row.id} 审核失败`).message)
}
}
await loadTasks()
const reason = [...new Set(failures.filter(Boolean))].slice(0, 3).join(';')
if (!failureCount) ElMessage.success(`已批量审核通过 ${successCount} 条测量数据`)
else if (successCount) ElMessage.warning(`批量审核完成:成功 ${successCount} 条,失败 ${failureCount} 条${reason ? `。${reason}` : ''}`)
else ElMessage.error(`批量审核失败:${failureCount} 条测量数据未通过${reason ? `。${reason}` : ''}`)
} catch (error) {
if (error !== 'cancel' && error !== 'close') ElMessage.error(getApiErrorDetails(error, '批量审核失败').message)
} finally {
batchReviewLoading.value = false
}
}
function handleMeasurementUpdated() {
void loadTasks()
}
@@ -246,7 +297,11 @@ onBeforeUnmount(() => { disposed = true; requestSerial += 1; optionsRequestSeria
row-key="id"
:empty-text="emptyText"
:aria-label="`${taskLabel}待办列表`"
@selection-change="handleReviewSelectionChange"
>
<template v-if="isReview && access.can(actionPermission)" #toolbar-actions>
<el-button type="success" :loading="batchReviewLoading" :disabled="loading || !selectedReviewRows.length" @click="batchApproveMeasurements"><CircleCheckBig :size="16" />批量审核通过<span v-if="selectedReviewRows.length">({{ selectedReviewRows.length }})</span></el-button>
</template>
<template #pagination-left>当前显示 {{ result.records.length }} 条 · 共 {{ result.total }} 条</template>
<template #actions="{ row }">
<div class="row-actions">