订单列表重新计费优化

This commit is contained in:
wuweihua
2026-10-21 10:13:01 +08:00
parent be3856a59c
commit d7f7ebd981
9 changed files with 659 additions and 41 deletions
+116 -38
View File
@@ -20,6 +20,7 @@
type="primary"
plain
icon="Refresh"
:loading="batchLoading"
v-hasPermi="['price:orderBill:rebill']"
@click="openFilterRebill()"
>重新计费</el-button>
@@ -91,7 +92,35 @@
<el-tag size="small" :type="billingFailTagType(row.billingFailStatus)">{{ billingFailLabel(row.billingFailStatus) }}</el-tag>
</template>
</basic-table>
<order-source-sync-dialog ref="syncDialogRef" @success="onRebillSuccess" />
<el-dialog
v-model="rebillProgressVisible"
title="本地重新计费"
width="480px"
append-to-body
destroy-on-close
:close-on-click-modal="!batchLoading"
:close-on-press-escape="!batchLoading"
:show-close="!batchLoading"
>
<el-progress
:percentage="rebillProgressPercent"
:status="rebillProgressStatus"
:stroke-width="14"
striped
:striped-flow="batchLoading"
/>
<div class="rebill-progress__msg">{{ rebillProgressMessage }}</div>
<div class="rebill-progress__text">
总数 {{ rebillProgressTotal }}
/ 成功 {{ rebillProgressSuccess }}
/ 失败 {{ rebillProgressFail }}
</div>
<p v-if="batchLoading" class="rebill-progress__hint">请勿关闭页面,大量订单重新计费可能需要一些时间</p>
<template #footer>
<el-button v-if="!batchLoading" type="primary" @click="rebillProgressVisible = false">关闭</el-button>
<el-button v-else disabled>执行中...</el-button>
</template>
</el-dialog>
<order-source-sync-log-drawer ref="logDrawerRef" />
<order-bill-product-check-drawer ref="productCheckDrawerRef" />
</div>
@@ -99,18 +128,22 @@
<script setup name="OrderBillQuery">
import { ElMessage, ElMessageBox } from 'element-plus'
import { listOrderBill, listOrderNoOptions, listTrackingNoOptions, listTransferNoOptions } from '@/api/price/billing'
import { syncOrderSourceSelected } from '@/api/monitor/orderSource'
import OrderSourceSyncDialog from '../../monitor/orderSource/components/OrderSourceSyncDialog.vue'
import { listOrderBill, listOrderNoOptions, listTrackingNoOptions, listTransferNoOptions, localRebillAsync } from '@/api/price/billing'
import OrderSourceSyncLogDrawer from '../../monitor/orderSource/components/OrderSourceSyncLogDrawer.vue'
import OrderBillProductCheckDrawer from './components/OrderBillProductCheckDrawer.vue'
const tableRef = ref()
const syncDialogRef = ref()
const logDrawerRef = ref()
const productCheckDrawerRef = ref()
const checkLoading = ref(false)
const batchLoading = ref(false)
const rebillProgressVisible = ref(false)
const rebillProgressPercent = ref(0)
const rebillProgressMessage = ref('')
const rebillProgressStatus = ref(undefined)
const rebillProgressTotal = ref(0)
const rebillProgressSuccess = ref(0)
const rebillProgressFail = ref(0)
const tableHeight = ref(480)
let tableResizeObserver = null
@@ -293,6 +326,62 @@ function handleCheckProducts() {
}
}
async function runLocalRebill(payload, confirmText) {
try {
await ElMessageBox.confirm(confirmText, '二次确认', { type: 'warning' })
} catch (e) {
return
}
batchLoading.value = true
rebillProgressVisible.value = true
rebillProgressPercent.value = 0
rebillProgressStatus.value = undefined
rebillProgressMessage.value = '任务提交中…'
rebillProgressTotal.value = 0
rebillProgressSuccess.value = 0
rebillProgressFail.value = 0
try {
const { task } = await localRebillAsync(payload, (t) => {
const total = Number(t.total) || 0
const success = Number(t.success) || 0
const fail = Number(t.fail) || 0
rebillProgressPercent.value = Math.min(100, Number(t.percent) || 0)
rebillProgressTotal.value = total
rebillProgressSuccess.value = success
rebillProgressFail.value = fail
if (t.status === 'PENDING') {
rebillProgressMessage.value = '排队中…'
} else if (t.status === 'RUNNING') {
rebillProgressMessage.value = '正在重新计费 ' + success + '/' + total +
(fail ? ('(失败 ' + fail + ')') : '')
}
})
const success = Number(task && task.success) || 0
const fail = Number(task && task.fail) || 0
rebillProgressPercent.value = 100
rebillProgressStatus.value = fail > 0 ? 'warning' : 'success'
rebillProgressTotal.value = Number(task && task.total) || rebillProgressTotal.value
rebillProgressSuccess.value = success
rebillProgressFail.value = fail
rebillProgressMessage.value = '完成:成功 ' + success + ' / 失败 ' + fail +
(fail && task.error ? (';' + task.error) : '')
tableRef.value?.refresh?.()
} catch (e) {
const task = e && e.task
rebillProgressStatus.value = 'exception'
rebillProgressMessage.value = (e && e.message) || '重新计费失败'
if (task) {
rebillProgressPercent.value = Math.min(100, Number(task.percent) || 100)
rebillProgressTotal.value = Number(task.total) || 0
rebillProgressSuccess.value = Number(task.success) || 0
rebillProgressFail.value = Number(task.fail) || 0
tableRef.value?.refresh?.()
}
} finally {
batchLoading.value = false
}
}
function openFilterRebill() {
const identifiers = currentIdentifiers()
if (!identifiers.length) {
@@ -303,30 +392,21 @@ function openFilterRebill() {
ElMessage.warning('单次最多重新计费 ' + MAX_REBILL + ' 个单号')
return
}
ElMessageBox.confirm(
'将按 ' + identifiers.length + ' 个单号查上游订单并重新计费,确认继续?',
'二次确认',
{ type: 'warning' }
).then(() => {
syncDialogRef.value?.open(buildRebillFilter(), true)
}).catch(() => {})
const filter = buildRebillFilter()
runLocalRebill(
{
scopeMode: 'ALL',
orderIdentifiers: filter.orderIdentifiers || identifiers,
customerCodes: filter.customerCodes || []
},
'将按 ' + identifiers.length + ' 个单号从本地订单表重新计费(不查上游),确认继续?'
)
}
function toSyncRow(row) {
return {
orderId: row.orderNo,
orgOrderId: row.trackingNo,
transferOrderId: row.transferNo,
customerCode: row.customerCode,
pickupDate: row.bizDate || row.pickupDate || row.orderTime || null
}
}
function handleBatchRebill(selection) {
const rows = selection || []
if (!rows.length) return
const missingTime = rows.filter(row => !toSyncRow(row).pickupDate).length
const missingTime = rows.filter(row => !(row.bizDate || row.pickupDate || row.orderTime)).length
if (missingTime) {
ElMessage.warning(missingTime + ' 条没有计费时间,无法重新计费')
return
@@ -335,20 +415,15 @@ function handleBatchRebill(selection) {
ElMessage.warning('选中重新计费最多 200 条')
return
}
ElMessageBox.confirm('确认重新计费选中的 ' + rows.length + ' 条订单?', '二次确认', { type: 'warning' }).then(() => {
batchLoading.value = true
return syncOrderSourceSelected(rows.map(toSyncRow))
}).then(res => {
const data = (res && res.data) || {}
ElMessage.success('完成:成功 ' + (data.ok || 0) + ' / 失败 ' + (data.fail || 0))
tableRef.value?.refresh?.()
}).catch(() => {}).finally(() => {
batchLoading.value = false
})
}
function onRebillSuccess() {
tableRef.value?.refresh?.()
const billIds = rows.map(r => r.billId).filter(Boolean)
if (!billIds.length) {
ElMessage.warning('选中行缺少 billId,无法重新计费')
return
}
runLocalRebill(
{ scopeMode: 'SELECTED', billIds },
'确认用本地订单数据重新计费选中的 ' + rows.length + ' 条订单?'
)
}
function searchOrderIdentifiers(keyword) {
@@ -418,4 +493,7 @@ onBeforeUnmount(() => {
.order-bill-query :deep(.basic-form .el-form-item .el-date-editor) {
width: 100%;
}
.rebill-progress__msg { margin-top: 12px; color: var(--el-text-color-regular); }
.rebill-progress__text { margin-top: 8px; font-size: 13px; color: var(--el-text-color-secondary); }
.rebill-progress__hint { margin-top: 12px; font-size: 12px; color: var(--el-color-warning); }
</style>