From 3f8f3a824def2e4a40f20e0f2d954a5de5f8bdb0 Mon Sep 17 00:00:00 2001 From: wuweihua <88888888> Date: Tue, 29 Sep 2026 19:27:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AF=BC=E5=85=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/BmsProductServiceImpl.java | 49 ++++++++++++++----- .../impl/TmsPriceQuoteServiceImpl.java | 12 ++++- bms-front/src/views/price/billing/bill.vue | 14 +++++- .../price/billing/components/BillDetail.vue | 24 +++++++-- bms-front/src/views/price/billing/quote.vue | 37 +++++++++++--- 5 files changed, 108 insertions(+), 28 deletions(-) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java index a86ea4c7..9cf9ebdc 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java @@ -797,24 +797,40 @@ public class BmsProductServiceImpl implements IBmsProductService private List parseCatalog(Sheet sheet) { List list = new ArrayList<>(); - // Weishi workbook often starts data at column B (A empty); locate by header. - int[] header = findHeaderCell(sheet, "\u4ea7\u54c1\u5bf9\u63a5\u4ee3\u7801"); + // Header is "\u5bf9\u63a5\u4ee3\u7801" or legacy "\u4ea7\u54c1\u5bf9\u63a5\u4ee3\u7801". Column A is often empty. + // 20260928 layout inserts "\u8ba1\u6ce1\u89c4\u5219" before country, so map by header name. + int[] header = findHeaderCell(sheet, "\u5bf9\u63a5\u4ee3\u7801"); if (header == null) { return list; } - int headerRow = header[0]; - int baseCol = header[1]; + int headerRowIdx = header[0]; + int colCode = header[1]; + Row head = sheet.getRow(headerRowIdx); + int colName = catalogColumn(head, "\u4ea7\u54c1\u540d\u79f0", colCode + 1); + int colLevel = catalogColumn(head, "\u65f6\u6548", colCode + 2); + int colCargo = catalogColumn(head, "\u8d70\u8d27\u5c5e\u6027", colCode + 3); + int colDest = findColByHeader(head, "\u56fd\u5bb6", colCode); + if (colDest < 0) + { + colDest = findColByHeader(head, "\u76ee\u7684", colCode); + } + if (colDest < 0) + { + colDest = colCode + 4; + } + int colNote = catalogColumn(head, "\u66f4\u65b0\u5185\u5bb9", colCode + 5); + int colDate = catalogColumn(head, "\u751f\u6548", colCode + 6); int lastRow = sheet.getLastRowNum(); - for (int i = headerRow + 1; i <= lastRow; i++) + for (int i = headerRowIdx + 1; i <= lastRow; i++) { Row row = sheet.getRow(i); if (row == null) { continue; } - String code = cellString(row.getCell(baseCol)); - if (StringUtils.isEmpty(code) || "\u4ea7\u54c1\u5bf9\u63a5\u4ee3\u7801".equals(code)) + String code = cellString(row.getCell(colCode)); + if (StringUtils.isEmpty(code) || code.contains("\u5bf9\u63a5\u4ee3\u7801")) { continue; } @@ -824,12 +840,12 @@ public class BmsProductServiceImpl implements IBmsProductService } BmsProduct p = new BmsProduct(); p.setProductCode(code.trim()); - p.setProductName(cellString(row.getCell(baseCol + 1))); - p.setServiceLevel(cellString(row.getCell(baseCol + 2))); - p.setCargoAttr(cellString(row.getCell(baseCol + 3))); - p.setDestRegion(cellString(row.getCell(baseCol + 4))); - p.setUpdateNote(cellString(row.getCell(baseCol + 5))); - p.setEffectiveDate(cellDate(row.getCell(baseCol + 6))); + p.setProductName(cellString(row.getCell(colName))); + p.setServiceLevel(cellString(row.getCell(colLevel))); + p.setCargoAttr(cellString(row.getCell(colCargo))); + p.setDestRegion(cellString(row.getCell(colDest))); + p.setUpdateNote(cellString(row.getCell(colNote))); + p.setEffectiveDate(cellDate(row.getCell(colDate))); p.setTaxMode(resolveTaxMode(p.getProductName())); if (StringUtils.isEmpty(p.getProductName())) { @@ -840,6 +856,13 @@ public class BmsProductServiceImpl implements IBmsProductService return list; } + /** Header column, or the legacy fixed offset when the title is absent. */ + private static int catalogColumn(Row headerRow, String keyword, int fallback) + { + int col = findColByHeader(headerRow, keyword, 0); + return col >= 0 ? col : fallback; + } + /** Keep first row per product_code (catalog often repeats code across country rows). */ private List dedupeCatalogProducts(List products) { diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/TmsPriceQuoteServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/TmsPriceQuoteServiceImpl.java index ebc12184..fa9e9ec4 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/TmsPriceQuoteServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/TmsPriceQuoteServiceImpl.java @@ -204,7 +204,8 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService { countryCode = countryCode.toUpperCase(); } - BigDecimal weight = request.getWeight(); + // Charge weight keeps 3 decimals; freight unit price keeps 2 (see buildFromRates). + BigDecimal weight = request.getWeight().setScale(3, RoundingMode.HALF_UP); String destPostcode = emptyToNull(request.getDestPostcode()); String zoneCode = null; @@ -564,7 +565,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService BigDecimal baseRate = base.getFreightPrice(); RoundingMode rm = resolveRoundingMode(roundMode); BigDecimal rate = baseRate.multiply(discount) - .divide(new BigDecimal("100"), 4, rm); + .divide(new BigDecimal("100"), 2, rm); TmsPriceQuoteResult r = buildFromRates(SRC_DISCOUNT, rate, baseRate, discount, base.getRegistrationFee(), base, productCode, productName, weight, roundMode); fillPackage(r, bind, set); @@ -616,6 +617,13 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService } RoundingMode rm = resolveRoundingMode(roundMode); String mode = normalizeRoundMode(roundMode); + weight = weight.setScale(3, RoundingMode.HALF_UP); + freightRate = freightRate.setScale(2, rm); + if (baseFreightRate != null) + { + baseFreightRate = baseFreightRate.setScale(2, rm); + } + registrationFee = registrationFee.setScale(2, rm); BigDecimal freightAmount = freightRate.multiply(weight).setScale(2, rm); BigDecimal payable = freightAmount.add(registrationFee).setScale(2, rm); diff --git a/bms-front/src/views/price/billing/bill.vue b/bms-front/src/views/price/billing/bill.vue index c1f6ac74..df8f6516 100644 --- a/bms-front/src/views/price/billing/bill.vue +++ b/bms-front/src/views/price/billing/bill.vue @@ -52,6 +52,9 @@ + @@ -133,7 +136,7 @@ const columns = [ { label: '产品', prop: 'product', minWidth: 160, slot: 'product' }, { label: '国家', prop: 'country', minWidth: 130, slot: 'country' }, { label: '件数', prop: 'pieces', align: 'center', width: 70 }, - { label: '计费重', prop: 'chargeWeight', align: 'center', width: 90 }, + { label: '计费重', prop: 'chargeWeight', align: 'center', width: 90, slot: 'chargeWeight' }, { label: '应收总额', prop: 'incomeTotal', align: 'right', width: 120, slot: 'incomeTotal' }, { label: '应付总额', prop: 'payTotal', align: 'right', width: 120, slot: 'payTotal' }, { label: '计价来源', prop: 'matchSource', align: 'center', width: 130, slot: 'matchSource' }, @@ -214,7 +217,14 @@ function formatMoney(val) { if (val === null || val === undefined || val === '') return '-' const num = Number(val) if (Number.isNaN(num)) return val - return num.toFixed(4) + return num.toFixed(2) +} + +function formatWeight(val) { + if (val === null || val === undefined || val === '') return '-' + const num = Number(val) + if (Number.isNaN(num)) return val + return num.toFixed(3) } function sourceLabel(source) { diff --git a/bms-front/src/views/price/billing/components/BillDetail.vue b/bms-front/src/views/price/billing/components/BillDetail.vue index c69f2f7a..bf008438 100644 --- a/bms-front/src/views/price/billing/components/BillDetail.vue +++ b/bms-front/src/views/price/billing/components/BillDetail.vue @@ -30,8 +30,8 @@ {{ detail.destPostcode || '-' }} {{ detail.pieces != null ? detail.pieces : '-' }} {{ dimLabel(detail) }} - {{ formatMoney(detail.actualWeight) }} - {{ formatMoney(detail.volumeWeight) }} + {{ formatWeight(detail.actualWeight) }} + {{ formatWeight(detail.volumeWeight) }} {{ formatMoney(detail.volume) }} {{ formatDateTime(detail.orderTime) }} {{ detail.orderRemark || '-' }} @@ -64,7 +64,7 @@ {{ productLabel(detail) }} - {{ detail.chargeWeight ?? detail.weight ?? '-' }} + {{ formatWeight(detail.chargeWeight ?? detail.weight) }} {{ detail.weightLabel || '-' }} {{ formatDate(detail.bizDate) }} @@ -77,7 +77,7 @@ {{ roundModeLabel(detail.roundMode) }} - {{ formatMoney(detail.freightRate) }} + {{ formatRate(detail.freightRate) }} {{ formatMoney(detail.registrationFee) }}
@@ -276,7 +276,21 @@ function formatMoney(val) { if (val === null || val === undefined || val === '') return '-' const num = Number(val) if (Number.isNaN(num)) return val - return num.toFixed(4) + return num.toFixed(2) +} + +function formatWeight(val) { + if (val === null || val === undefined || val === '') return '-' + const num = Number(val) + if (Number.isNaN(num)) return val + return num.toFixed(3) +} + +function formatRate(val) { + if (val === null || val === undefined || val === '') return '-' + const num = Number(val) + if (Number.isNaN(num)) return val + return num.toFixed(2) } function formatDate(val) { diff --git a/bms-front/src/views/price/billing/quote.vue b/bms-front/src/views/price/billing/quote.vue index af2fbedb..37c020c8 100644 --- a/bms-front/src/views/price/billing/quote.vue +++ b/bms-front/src/views/price/billing/quote.vue @@ -93,7 +93,7 @@ {{ result.countryName || '-' }} ({{ result.countryCode }}) {{ result.destPostcode || '-' }} {{ result.zoneName || result.zoneCode || '-' }} - {{ result.chargeWeight ?? result.weight }} + {{ formatWeight(result.chargeWeight ?? result.weight) }} {{ result.weightLabel || '-' }} {{ formatDate(result.effectiveDate) }} @@ -106,8 +106,8 @@ - {{ formatMoney(result.freightRate) }} - {{ formatMoney(result.baseFreightRate) }} + {{ formatRate(result.freightRate) }} + {{ formatRate(result.baseFreightRate) }} {{ result.discountPercent != null ? result.discountPercent : '-' }} {{ roundModeLabel(result.roundMode) }} {{ formatMoney(result.freightAmount) }} @@ -180,6 +180,9 @@ + @@ -206,7 +209,7 @@ {{ viewResult.countryName || '-' }} ({{ viewResult.countryCode }}) {{ viewResult.destPostcode || '-' }} {{ viewResult.zoneName || viewResult.zoneCode || '-' }} - {{ viewResult.chargeWeight ?? viewResult.weight }} + {{ formatWeight(viewResult.chargeWeight ?? viewResult.weight) }} {{ viewResult.weightLabel || '-' }} {{ sourceLabel(viewResult.matchSource) }} @@ -282,7 +285,7 @@ const historyColumns = [ { label: '客户ID', prop: 'customerId', align: 'center', width: 90 }, { label: '产品', prop: 'product', minWidth: 160, slot: 'product' }, { label: '国家', prop: 'country', minWidth: 130, slot: 'country' }, - { label: '计费重量', prop: 'weight', align: 'center', width: 100 }, + { label: '计费重量', prop: 'weight', align: 'center', width: 100, slot: 'weight' }, { label: '计费日期', prop: 'bizDate', align: 'center', width: 120 }, { label: '计价来源', prop: 'matchSource', align: 'center', width: 140, slot: 'matchSource' }, { label: '套餐', prop: 'priceSetName', minWidth: 120, showOverflowTooltip: true }, @@ -444,7 +447,29 @@ function formatMoney(val) { if (Number.isNaN(num)) { return val } - return num.toFixed(4) + return num.toFixed(2) +} + +function formatWeight(val) { + if (val === null || val === undefined || val === '') { + return '-' + } + const num = Number(val) + if (Number.isNaN(num)) { + return val + } + return num.toFixed(3) +} + +function formatRate(val) { + if (val === null || val === undefined || val === '') { + return '-' + } + const num = Number(val) + if (Number.isNaN(num)) { + return val + } + return num.toFixed(2) } function formatDate(val) {