修改订单列表重新计费
This commit is contained in:
+84
-7
@@ -28,11 +28,14 @@ import com.bms.price.config.BillingProperties;
|
||||
import com.bms.price.domain.BatchAddIncomeBillFeeTask;
|
||||
import com.bms.price.domain.PrcOrderBill;
|
||||
import com.bms.price.domain.vo.LocalRebillRequest;
|
||||
import com.bms.price.domain.vo.TmsPriceQuoteResult;
|
||||
import com.bms.price.enums.BillBillingFailStatus;
|
||||
import com.bms.price.mapper.PrcOrderBillMapper;
|
||||
import com.bms.price.search.EsBizLogSupport;
|
||||
import com.bms.price.search.IBillSearchStore;
|
||||
import com.bms.price.search.TabOrderSyncEsLog;
|
||||
import com.bms.price.service.IPrcOrderBillService;
|
||||
import com.bms.price.service.support.OrderBillExportSupport;
|
||||
|
||||
/**
|
||||
* Async local rebill from prc_order_bill only (no Oracle / MQ).
|
||||
@@ -122,16 +125,33 @@ public class PrcOrderBillLocalRebillAsyncRunner
|
||||
String one = ids.get(i);
|
||||
try
|
||||
{
|
||||
orderBillService.rebillLocalByBillId(one);
|
||||
TmsPriceQuoteResult result = orderBillService.rebillLocalByBillId(one);
|
||||
// Soft-fail still persists the order bill; count as fail in progress.
|
||||
if (BillBillingFailStatus.isFail(result == null ? null : result.getBillingFailStatus()))
|
||||
{
|
||||
fail.incrementAndGet();
|
||||
String tip = softFailMessage(result);
|
||||
String transferLabel = failTransferLabel(one,
|
||||
result == null ? null : result.getTransferNo());
|
||||
appendFail(failTips, transferLabel, tip);
|
||||
collectFailDetail(failDetails, one, tip);
|
||||
log.warn("local rebill soft-fail taskId={} billId={} transferNo={} status={} msg={}",
|
||||
taskId, one, transferLabel,
|
||||
result == null ? null : result.getBillingFailStatus(), tip);
|
||||
}
|
||||
else
|
||||
{
|
||||
success.incrementAndGet();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
fail.incrementAndGet();
|
||||
appendFail(failTips, one, e);
|
||||
String transferLabel = failTransferLabel(one, null);
|
||||
appendFail(failTips, transferLabel, e);
|
||||
collectFailDetail(failDetails, one, e);
|
||||
log.warn("local rebill failed taskId={} billId={} msg={}",
|
||||
taskId, one, e.getMessage());
|
||||
log.warn("local rebill failed taskId={} billId={} transferNo={} msg={}",
|
||||
taskId, one, transferLabel, e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -250,6 +270,11 @@ public class PrcOrderBillLocalRebillAsyncRunner
|
||||
}
|
||||
|
||||
private void collectFailDetail(List<Map<String, Object>> failDetails, String billId, Exception e)
|
||||
{
|
||||
collectFailDetail(failDetails, billId, errorMessage(e));
|
||||
}
|
||||
|
||||
private void collectFailDetail(List<Map<String, Object>> failDetails, String billId, String message)
|
||||
{
|
||||
if (failDetails == null)
|
||||
{
|
||||
@@ -284,7 +309,7 @@ public class PrcOrderBillLocalRebillAsyncRunner
|
||||
item.put("orderId", StringUtils.isEmpty(orderNo) ? billId : orderNo);
|
||||
item.put("transferOrderId", transferNo);
|
||||
item.put("trackingNo", trackingNo);
|
||||
item.put("errorMessage", errorMessage(e));
|
||||
item.put("errorMessage", StringUtils.isEmpty(message) ? "fail" : message);
|
||||
failDetails.add(item);
|
||||
}
|
||||
}
|
||||
@@ -427,7 +452,12 @@ public class PrcOrderBillLocalRebillAsyncRunner
|
||||
return v;
|
||||
}
|
||||
|
||||
private static void appendFail(StringBuilder failTips, String billId, Exception e)
|
||||
private static void appendFail(StringBuilder failTips, String orderLabel, Exception e)
|
||||
{
|
||||
appendFail(failTips, orderLabel, errorMessage(e));
|
||||
}
|
||||
|
||||
private static void appendFail(StringBuilder failTips, String orderLabel, String message)
|
||||
{
|
||||
synchronized (failTips)
|
||||
{
|
||||
@@ -439,10 +469,57 @@ public class PrcOrderBillLocalRebillAsyncRunner
|
||||
{
|
||||
failTips.append("; ");
|
||||
}
|
||||
failTips.append(billId).append(":").append(errorMessage(e));
|
||||
failTips.append(StringUtils.isEmpty(orderLabel) ? "-" : orderLabel)
|
||||
.append(":").append(StringUtils.isEmpty(message) ? "fail" : message);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer transferNo in UI tips; fall back to orderNo, then billId. */
|
||||
private String failTransferLabel(String billId, String transferNoHint)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(transferNoHint))
|
||||
{
|
||||
return transferNoHint.trim();
|
||||
}
|
||||
if (StringUtils.isEmpty(billId) || orderBillMapper == null)
|
||||
{
|
||||
return billId;
|
||||
}
|
||||
try
|
||||
{
|
||||
PrcOrderBill bill = orderBillMapper.selectPrcOrderBillById(billId.trim());
|
||||
if (bill != null)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(bill.getTransferNo()))
|
||||
{
|
||||
return bill.getTransferNo().trim();
|
||||
}
|
||||
if (StringUtils.isNotEmpty(bill.getOrderNo()))
|
||||
{
|
||||
return bill.getOrderNo().trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ignore)
|
||||
{
|
||||
// tip label is best-effort
|
||||
}
|
||||
return billId;
|
||||
}
|
||||
|
||||
private static String softFailMessage(TmsPriceQuoteResult result)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
return "billing fail";
|
||||
}
|
||||
if (StringUtils.isNotEmpty(result.getMatchMessage()))
|
||||
{
|
||||
return result.getMatchMessage();
|
||||
}
|
||||
return OrderBillExportSupport.billingFailStatusLabel(result.getBillingFailStatus());
|
||||
}
|
||||
|
||||
private static String errorMessage(Exception e)
|
||||
{
|
||||
return StringUtils.isEmpty(e.getMessage()) ? e.getClass().getSimpleName() : e.getMessage();
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
<el-dialog
|
||||
v-model="rebillProgressVisible"
|
||||
:title="rebillDialogTitle"
|
||||
width="480px"
|
||||
width="560px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="true"
|
||||
@@ -206,11 +206,33 @@
|
||||
:striped-flow="batchLoading"
|
||||
/>
|
||||
<div class="rebill-progress__msg">{{ rebillProgressMessage }}</div>
|
||||
<div class="rebill-progress__text">
|
||||
<div v-if="!batchLoading && rebillFinished" class="rebill-result-stats">
|
||||
<div class="rebill-result-stats__item">
|
||||
<span class="rebill-result-stats__label">总数</span>
|
||||
<strong>{{ rebillProgressTotal }}</strong>
|
||||
</div>
|
||||
<div class="rebill-result-stats__item is-success">
|
||||
<span class="rebill-result-stats__label">成功</span>
|
||||
<strong>{{ rebillProgressSuccess }}</strong>
|
||||
</div>
|
||||
<div class="rebill-result-stats__item is-fail">
|
||||
<span class="rebill-result-stats__label">失败</span>
|
||||
<strong>{{ rebillProgressFail }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="rebill-progress__text">
|
||||
总数 {{ rebillProgressTotal }}
|
||||
/ 成功 {{ rebillProgressSuccess }}
|
||||
/ 失败 {{ rebillProgressFail }}
|
||||
</div>
|
||||
<el-alert
|
||||
v-if="!batchLoading && rebillFailDetail"
|
||||
:title="rebillFailDetail"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="rebill-progress__error"
|
||||
/>
|
||||
<p v-if="batchLoading" class="rebill-progress__hint">计费在后台进行,可收起弹窗继续操作;请勿关闭或刷新本页</p>
|
||||
<template #footer>
|
||||
<el-button v-if="batchLoading" @click="rebillProgressVisible = false">收起</el-button>
|
||||
@@ -221,7 +243,21 @@
|
||||
:loading="rebillCancelLoading"
|
||||
@click="handleCancelRebill"
|
||||
>取消计费</el-button>
|
||||
<el-button v-else type="primary" @click="rebillProgressVisible = false">关闭</el-button>
|
||||
<template v-else>
|
||||
<el-button
|
||||
v-if="rebillProgressFail > 0"
|
||||
type="warning"
|
||||
plain
|
||||
@click="viewRebillFailedOrders"
|
||||
>查看失败订单</el-button>
|
||||
<el-button
|
||||
v-if="rebillProgressFail > 0"
|
||||
type="warning"
|
||||
:loading="exportLoading"
|
||||
@click="exportRebillFailedOrders"
|
||||
>导出失败订单</el-button>
|
||||
<el-button type="primary" @click="rebillProgressVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
@@ -356,6 +392,7 @@ const rebillProgressStatus = ref(undefined)
|
||||
const rebillProgressTotal = ref(0)
|
||||
const rebillProgressSuccess = ref(0)
|
||||
const rebillProgressFail = ref(0)
|
||||
const rebillFailDetail = ref('')
|
||||
const rebillTaskId = ref('')
|
||||
const rebillCancelLoading = ref(false)
|
||||
let rebillFloatHideTimer = null
|
||||
@@ -429,6 +466,7 @@ const defaultParams = {
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{ label: '计费状态', prop: 'billingFailStatus', align: 'center', width: 160, fixed: 'left', slot: 'billingFailStatus' },
|
||||
{ label: '订单号', prop: 'orderNo', width: 160, fixed: 'left', showOverflowTooltip: true },
|
||||
{ label: '运单号', prop: 'trackingNo', minWidth: 140, showOverflowTooltip: true },
|
||||
{ label: '转单号', prop: 'transferNo', minWidth: 140, showOverflowTooltip: true },
|
||||
@@ -442,7 +480,6 @@ const columns = [
|
||||
{ label: '实重', prop: 'receiveWeight', align: 'center', width: 90, slot: 'receiveWeight' },
|
||||
{ label: '收件人邮编', prop: 'destPostcode', minWidth: 120, showOverflowTooltip: true },
|
||||
{ label: '订单状态', prop: 'orderStatus', align: 'center', width: 110, slot: 'orderStatus' },
|
||||
{ label: '计费状态', prop: 'billingFailStatus', align: 'center', width: 140, slot: 'billingFailStatus' },
|
||||
{ label: '计费时间', prop: 'bizDate', align: 'center', width: 170, parseTime: true },
|
||||
// { label: '下单时间', prop: 'orderTime', align: 'center', width: 170, parseTime: true },
|
||||
{ label: '提货时间', prop: 'pickupDate', align: 'center', width: 170, parseTime: true },
|
||||
@@ -767,21 +804,52 @@ function applyRebillProgress(t) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function billingFailOnlyStatuses() {
|
||||
// All statuses except success(0).
|
||||
return billingFailStatusOptions.map(o => o.value).filter(v => v !== 0)
|
||||
}
|
||||
|
||||
function viewRebillFailedOrders() {
|
||||
rebillProgressVisible.value = false
|
||||
const fails = billingFailOnlyStatuses()
|
||||
tableRef.value?.setQueryParams?.({ billingFailStatuses: fails })
|
||||
tableRef.value?.handleQuery?.()
|
||||
}
|
||||
|
||||
async function exportRebillFailedOrders() {
|
||||
if (exportLoading.value) return
|
||||
const fails = billingFailOnlyStatuses()
|
||||
// Keep current list filters, force fail statuses for export.
|
||||
tableRef.value?.setQueryParams?.({ billingFailStatuses: fails })
|
||||
rebillProgressVisible.value = false
|
||||
await handleExport()
|
||||
}
|
||||
|
||||
function finishRebillFromTask(task, cancelled) {
|
||||
const success = Number(task && task.success) || 0
|
||||
const fail = Number(task && task.fail) || 0
|
||||
const total = Number(task && task.total) || rebillProgressTotal.value || 0
|
||||
rebillProgressPercent.value = Math.min(100, Number(task && task.percent) || 100)
|
||||
rebillProgressStatus.value = cancelled ? 'warning' : (fail > 0 ? 'warning' : 'success')
|
||||
rebillProgressTotal.value = Number(task && task.total) || rebillProgressTotal.value
|
||||
rebillProgressTotal.value = total
|
||||
rebillProgressSuccess.value = success
|
||||
rebillProgressFail.value = fail
|
||||
rebillProgressMessage.value = cancelled
|
||||
? ('已取消:成功 ' + success + ' / 失败 ' + fail)
|
||||
: ('完成:成功 ' + success + ' / 失败 ' + fail)
|
||||
rebillFailDetail.value = fail > 0 ? String((task && (task.error || task.message)) || '').trim() : ''
|
||||
if (cancelled) {
|
||||
rebillProgressMessage.value = '重新计费已取消:成功 ' + success + ' / 失败 ' + fail + ' / 总数 ' + total
|
||||
} else if (fail > 0) {
|
||||
rebillProgressMessage.value = '重新计费完成(含失败):成功 ' + success + ' / 失败 ' + fail + ' / 总数 ' + total
|
||||
} else {
|
||||
rebillProgressMessage.value = '重新计费完成:成功 ' + success + ' / 失败 ' + fail + ' / 总数 ' + total
|
||||
}
|
||||
rebillFinished.value = true
|
||||
clearRebillTaskId()
|
||||
tableRef.value?.refresh?.()
|
||||
// Always popup result dialog when billing finishes (even if progress was collapsed).
|
||||
rebillProgressVisible.value = true
|
||||
if (cancelled) ElMessage.warning(rebillProgressMessage.value)
|
||||
else if (fail > 0) ElMessage.warning(rebillProgressMessage.value)
|
||||
else ElMessage.success(rebillProgressMessage.value)
|
||||
scheduleHideRebillFloat()
|
||||
}
|
||||
@@ -799,6 +867,7 @@ async function resumeRebillTask(taskId) {
|
||||
rebillProgressTotal.value = 0
|
||||
rebillProgressSuccess.value = 0
|
||||
rebillProgressFail.value = 0
|
||||
rebillFailDetail.value = ''
|
||||
let superseded = false
|
||||
try {
|
||||
const result = await pollLocalRebillTask(taskId, applyRebillProgress)
|
||||
@@ -811,6 +880,7 @@ async function resumeRebillTask(taskId) {
|
||||
const task = e && e.task
|
||||
rebillProgressStatus.value = 'exception'
|
||||
rebillProgressMessage.value = (e && e.message) || '重新计费失败'
|
||||
rebillFailDetail.value = String((task && task.error) || (e && e.message) || '').trim()
|
||||
rebillFinished.value = true
|
||||
if (task) {
|
||||
rebillProgressPercent.value = Math.min(100, Number(task.percent) || 100)
|
||||
@@ -875,6 +945,7 @@ async function runLocalRebill(payload, confirmText) {
|
||||
rebillProgressTotal.value = 0
|
||||
rebillProgressSuccess.value = 0
|
||||
rebillProgressFail.value = 0
|
||||
rebillFailDetail.value = ''
|
||||
window.setTimeout(() => {
|
||||
if (batchLoading.value) rebillProgressVisible.value = false
|
||||
}, 600)
|
||||
@@ -894,6 +965,7 @@ async function runLocalRebill(payload, confirmText) {
|
||||
const task = e && e.task
|
||||
rebillProgressStatus.value = 'exception'
|
||||
rebillProgressMessage.value = (e && e.message) || '重新计费失败'
|
||||
rebillFailDetail.value = String((task && task.error) || (e && e.message) || '').trim()
|
||||
rebillFinished.value = true
|
||||
if (task) {
|
||||
rebillProgressPercent.value = Math.min(100, Number(task.percent) || 100)
|
||||
@@ -1049,6 +1121,39 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
.order-identifier-search { width: 100%; }
|
||||
.rebill-progress__msg { margin-top: 12px; color: var(--el-text-color-regular); }
|
||||
.rebill-result-stats {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
.rebill-result-stats__item {
|
||||
flex: 1;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: var(--el-fill-color-light);
|
||||
text-align: center;
|
||||
}
|
||||
.rebill-result-stats__item.is-success {
|
||||
background: var(--el-color-success-light-9);
|
||||
}
|
||||
.rebill-result-stats__item.is-fail {
|
||||
background: var(--el-color-warning-light-9);
|
||||
}
|
||||
.rebill-result-stats__label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.rebill-result-stats__item strong {
|
||||
font-size: 20px;
|
||||
line-height: 1.2;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
.rebill-progress__error {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.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); }
|
||||
.order-bill-query .export-status-float {
|
||||
|
||||
Reference in New Issue
Block a user