增加产品价和红线价重计费功能

This commit is contained in:
wuweihua
2026-10-15 16:09:05 +08:00
parent 41ce05a08a
commit 071e7f0c55
9 changed files with 615 additions and 25 deletions
+125 -2
View File
@@ -8,6 +8,7 @@
search-action-align="center"
:search-per-row="4"
row-key="billId"
selection
>
<template #search-orderNos="{ model }">
<multi-value-input v-model="model.orderNos" placeholder="订单号" width="100%" :search-method="searchOrderNoOptions" />
@@ -104,6 +105,15 @@
@click="openChargeWeightImportAttach"
>导入记录</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Refresh"
v-hasPermi="['price:billing:recalc']"
@click="openRecalcDialog"
>重计费</el-button>
</el-col>
</template>
<template #col-action="{ row }">
<el-button link type="primary" icon="View" @click="handleView(row)">查看</el-button>
@@ -161,9 +171,36 @@
</template>
</excel-import-dialog>
<charge-weight-import-attach-drawer ref="cwImportAttachRef" />
<el-dialog
v-model="recalcDialogOpen"
title="重计费"
width="420px"
append-to-body
destroy-on-close
>
<el-form label-width="90px">
<el-form-item label="计费类型" required>
<el-radio-group v-model="recalcMode">
<el-radio value="PRODUCT">产品价</el-radio>
<el-radio value="REDLINE">红线价</el-radio>
</el-radio-group>
</el-form-item>
<el-alert
type="info"
:closable="false"
show-icon
title="仅更新所选类型对应字段;有勾选按勾选,否则按当前筛选。已出账也可重算。"
/>
</el-form>
<template #footer>
<el-button @click="recalcDialogOpen = false">取消</el-button>
<el-button type="primary" :disabled="!recalcMode" @click="confirmRecalc">开始重计费</el-button>
</template>
</el-dialog>
<el-dialog
v-model="cwImportProgressVisible"
title="正在导入修改计费重"
:title="cwImportProgressTitle"
width="420px"
:close-on-click-modal="false"
:close-on-press-escape="false"
@@ -184,7 +221,7 @@
</template>
<script setup name="BillingBill">
import { listBill, getBill, refundBill, listOrderNoOptions, listTrackingNoOptions, listTransferNoOptions, updateCreditArrears, importChargeWeightAsync, downloadChargeWeightTemplate } from '@/api/price/billing'
import { listBill, getBill, refundBill, listOrderNoOptions, listTrackingNoOptions, listTransferNoOptions, updateCreditArrears, importChargeWeightAsync, downloadChargeWeightTemplate, recalcBillPriceAsync } from '@/api/price/billing'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useProducts } from '@/components/ProductSelect/useProducts'
import BillDetail from './components/BillDetail.vue'
@@ -242,6 +279,9 @@ const cwImportProgressPercent = ref(0)
const cwImportProgressMessage = ref('')
const cwImportProgressStatus = ref(undefined)
const cwImportProgressIndeterminate = ref(false)
const cwImportProgressTitle = ref('正在导入修改计费重')
const recalcDialogOpen = ref(false)
const recalcMode = ref('PRODUCT')
const columns = [
{ label: '订单号', prop: 'orderNo', minWidth: 140, showOverflowTooltip: true },
@@ -411,6 +451,88 @@ function onBatchFeeSuccess() {
tableRef.value?.refresh?.()
}
function buildRecalcPayload() {
const q = tableRef.value?.getQueryParams?.() || {}
const { pageNum, pageSize, bizDateRange, ...rest } = q
if (!hasBatchFeeQuery({ ...rest, bizDateRange })) {
ElMessage.warning('请先设置列表查询条件')
return null
}
const selectedIds = (tableRef.value?.getSelectionIds?.() || []).filter(Boolean)
const payload = {
scopeMode: selectedIds.length ? 'SELECTED' : 'ALL',
billIds: selectedIds,
orderNos: rest.orderNos || [],
trackingNos: rest.trackingNos || [],
transferNos: rest.transferNos || [],
customerCodes: rest.customerCodes || [],
productCodes: rest.productCodes || [],
creditArrearsStatus: rest.creditArrearsStatus || undefined
}
if (Array.isArray(bizDateRange) && (bizDateRange[0] || bizDateRange[1])) {
payload.beginBizDate = bizDateRange[0] || null
payload.endBizDate = bizDateRange[1] || null
}
return payload
}
function openRecalcDialog() {
const payload = buildRecalcPayload()
if (!payload) return
recalcMode.value = 'PRODUCT'
recalcDialogOpen.value = true
}
function confirmRecalc() {
if (!recalcMode.value) {
ElMessage.warning('请选择计费类型')
return
}
recalcDialogOpen.value = false
runRecalc(recalcMode.value)
}
async function runRecalc(mode) {
const payload = buildRecalcPayload()
if (!payload) return
const label = mode === 'REDLINE' ? '红线价' : '产品价'
cwImportProgressTitle.value = '正在重算' + label
cwImportProgressVisible.value = true
cwImportProgressPercent.value = 0
cwImportProgressIndeterminate.value = false
cwImportProgressStatus.value = undefined
cwImportProgressMessage.value = '任务提交中…'
try {
const { task } = await recalcBillPriceAsync(mode, payload, (t) => {
cwImportProgressPercent.value = Math.min(100, Number(t.percent) || 0)
const total = Number(t.total) || 0
const success = Number(t.success) || 0
const fail = Number(t.fail) || 0
if (t.status === 'PENDING') cwImportProgressMessage.value = '排队中…'
else if (t.status === 'RUNNING') {
cwImportProgressMessage.value = '正在处理 ' + success + '/' + total +
(fail ? ('(失败 ' + fail + ')') : '')
}
})
const success = Number(task && task.success) || 0
const fail = Number(task && task.fail) || 0
const tip = label + '重算完成:成功 ' + success + ',失败 ' + fail
cwImportProgressPercent.value = 100
cwImportProgressStatus.value = fail > 0 ? 'warning' : 'success'
cwImportProgressMessage.value = tip + (fail && task.error ? (';' + task.error) : '')
if (fail > 0) ElMessage.warning(cwImportProgressMessage.value)
else ElMessage.success(tip)
tableRef.value?.refresh?.()
} catch (e) {
cwImportProgressStatus.value = 'exception'
const tip = (e && e.task && e.task.error) || (e && e.message) || '重算失败'
cwImportProgressMessage.value = tip
ElMessage.error(tip)
} finally {
setTimeout(() => { cwImportProgressVisible.value = false }, 800)
}
}
function openEditChargeWeight(row) {
if (!row || !row.billId) return
if (row.refundStatus === 'REFUNDED') {
@@ -490,6 +612,7 @@ async function runChargeWeightImportAsync(uploadFile) {
if (!raw) throw new Error('\u8bf7\u5148\u9009\u62e9\u6587\u4ef6')
// Close import dialog so progress dialog is the only visible wait UI
chargeWeightImportRef.value?.close?.()
cwImportProgressTitle.value = '正在导入修改计费重'
cwImportProgressVisible.value = true
cwImportProgressPercent.value = 0
cwImportProgressIndeterminate.value = true