diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java index f19ac1b5..de7c9e6c 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java @@ -227,6 +227,14 @@ public class PriceSetController extends BaseController return success(priceSetService.selectDetailListByProduct(psvId, productCode)); } + /** All detail rows for a version (no page); batch prefetch instead of N byProduct calls. */ + @PreAuthorize("@ss.hasPermi('price:set:list')") + @GetMapping("/detail/byVersion") + public AjaxResult detailByVersion(@RequestParam("psvId") Long psvId) + { + return success(priceSetService.selectDetailListByVersion(psvId)); + } + /** * 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 */ diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java index b022c9c4..40564b26 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java @@ -63,13 +63,13 @@ public class ProductController extends BaseController } /** - * 产品下拉选项(非分页)。 - * 供计费列表、客户绑定等场景选择产品;不做权限控制(仍需登录)。 + * Product dropdown (non-paged). Slim query, no list-page status refresh. + * Used by price-set / billing / customer bind; login required, no extra perm. */ @GetMapping("/optionselect") public AjaxResult optionselect(BmsProduct product) { - List list = productService.selectBmsProductList(product); + List list = productService.selectBmsProductOptions(product); return success(list); } diff --git a/bms-back/bms-admin/src/main/resources/i18n/messages.properties b/bms-back/bms-admin/src/main/resources/i18n/messages.properties index fe2ceafc..ce897e9c 100644 --- a/bms-back/bms-admin/src/main/resources/i18n/messages.properties +++ b/bms-back/bms-admin/src/main/resources/i18n/messages.properties @@ -122,6 +122,7 @@ price.product.import.sheetNotFound=未找到「产品目录」sheet,请上传 price.product.import.noData=产品目录无有效数据行 price.product.import.catalogHeaderMissing=「产品目录」未找到表头「对接代码」,请在标题行下补齐表头(对接代码、产品名称、时效、走货属性、国家等) price.product.import.countryCatalogHeaderMissing=「产品目录」未找到表头「产品名称」或「产品ID」,请确认是否为单国专线成本价表格式 +price.product.import.singleCountryAsMulti=当前选择的是「全部导入(多国家价表)」,但上传的文件更像单国专线成本价表(价表无「国家」列)。请改用「按国家导入」,并选择目的国家后再上传。 price.product.import.regionEmpty=region 无可用国家数据,请先同步/维护国家表后再导入 price.product.import.partialFail=导入完成但存在失败项:新增 {0},跳过 {1};失败明细:{2} price.product.import.effTooEarly=产品{0}({1})导入生效时间{2}早于该产品上一版生效时间{3},不允许导入 diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/BmsProductMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/BmsProductMapper.java index 9e0a79d9..18dc6d7e 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/mapper/BmsProductMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/BmsProductMapper.java @@ -30,6 +30,9 @@ public interface BmsProductMapper public List selectBmsProductList(BmsProduct product); + /** Dropdown options: slim columns, no country/surcharge count subqueries */ + public List selectBmsProductOptions(BmsProduct product); + public int insertBmsProduct(BmsProduct product); public int updateBmsProduct(BmsProduct product); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java index 003ceb4a..53c547b7 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java @@ -19,6 +19,9 @@ public interface IBmsProductService public List selectBmsProductList(BmsProduct product); + /** Product dropdown options (no status refresh, no count subqueries). */ + public List selectBmsProductOptions(BmsProduct product); + public int insertBmsProduct(BmsProduct product); public int updateBmsProduct(BmsProduct product); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java index 08a19764..698793f6 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java @@ -71,6 +71,11 @@ public interface IPrcPriceSetService */ public List selectDetailListByProduct(Long psvId, String productCode); + /** + * Load all detail rows for a version (no pagination). For batch prefetch vs N byProduct calls. + */ + public List selectDetailListByVersion(Long psvId); + /** * 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 列表。 * 返回 { products: [{code,name}], countries: [{code,name}], zones: [{code,name}] } 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 65174558..dfc53670 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 @@ -129,8 +129,7 @@ public class BmsProductServiceImpl implements IBmsProductService @Override public List selectBmsProductList(BmsProduct product) { - productMapper.refreshStatusByDates(); - countryMapper.refreshStatusByDates(); + // Status refresh is done on activate / scheduled task; skip UPDATE on every list read. if (product != null) { product.setStatus(normalizeStatusCode(product.getStatus())); @@ -139,6 +138,17 @@ public class BmsProductServiceImpl implements IBmsProductService return productMapper.selectBmsProductList(product); } + @Override + public List selectBmsProductOptions(BmsProduct product) + { + if (product != null) + { + product.setStatus(normalizeStatusCode(product.getStatus())); + product.setEffectStatus(normalizeStatusCode(product.getEffectStatus())); + } + return productMapper.selectBmsProductOptions(product); + } + @Override public int insertBmsProduct(BmsProduct product) { @@ -378,6 +388,7 @@ public class BmsProductServiceImpl implements IBmsProductService { throw new ServiceException(MessageUtils.message("price.product.import.sheetNotFound")); } + assertNotSingleCountryQuoteForMultiImport(workbook); List products = parseCatalog(catalog); if (products.isEmpty()) @@ -678,6 +689,7 @@ public class BmsProductServiceImpl implements IBmsProductService { throw new ServiceException(MessageUtils.message("price.product.import.sheetNotFound")); } + assertNotSingleCountryQuoteForMultiImport(workbook); List products = dedupeCatalogProducts(parseCatalog(catalog)); if (products.isEmpty()) { @@ -763,6 +775,7 @@ public class BmsProductServiceImpl implements IBmsProductService } if (out.isEmpty()) { + assertNotSingleCountryQuoteForMultiImport(workbook); throw new ServiceException(MessageUtils.message("price.set.import.noPriceRows")); } QuoteWorkbook parsed = new QuoteWorkbook(); @@ -778,6 +791,80 @@ public class BmsProductServiceImpl implements IBmsProductService private Map> byCode; } + /** + * Multi-country import expects price sheets with a "country" column. + * Single-country dedicated-line sheets use product-name + weight blocks instead. + */ + private void assertNotSingleCountryQuoteForMultiImport(Workbook workbook) + { + if (looksLikeSingleCountryQuote(workbook)) + { + throw new ServiceException(MessageUtils.message("price.product.import.singleCountryAsMulti")); + } + } + + /** Detect single-country cost-sheet layout (no country column on price sheets). */ + private boolean looksLikeSingleCountryQuote(Workbook workbook) + { + if (workbook == null) + { + return false; + } + boolean sawCountryCol = false; + boolean sawCountryPriceBlock = false; + for (int i = 0; i < workbook.getNumberOfSheets(); i++) + { + String sheetName = workbook.getSheetName(i); + if (shouldSkipCountryPriceSheet(sheetName)) + { + continue; + } + Sheet sheet = workbook.getSheetAt(i); + if (sheet == null) + { + continue; + } + if (findHeaderCell(sheet, "\u56fd\u5bb6") != null) + { + sawCountryCol = true; + break; + } + int[] nameHeader = findHeaderCell(sheet, "\u4ea7\u54c1\u540d\u79f0"); + if (nameHeader == null) + { + continue; + } + Row head = sheet.getRow(nameHeader[0]); + if (head == null) + { + continue; + } + if (findColByHeader(head, "\u91cd\u91cf", 0) >= 0) + { + sawCountryPriceBlock = true; + } + } + if (sawCountryCol) + { + return false; + } + if (sawCountryPriceBlock) + { + return true; + } + Sheet catalog = workbook.getSheet(CATALOG_SHEET); + if (catalog == null) + { + return false; + } + if (findHeaderCell(catalog, "\u5bf9\u63a5\u4ee3\u7801") != null) + { + return false; + } + return findHeaderCell(catalog, "\u4ea7\u54c1\u540d\u79f0") != null + || findHeaderCell(catalog, "\u4ea7\u54c1ID") != null; + } + @Override public Map> parseCountryQuoteExcelByProduct(byte[] bytes, String filename, String countryCode) throws Exception diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java index f4e1b740..59760922 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java @@ -881,6 +881,18 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService return selectDetailList(q); } + @Override + public List selectDetailListByVersion(Long psvId) + { + if (psvId == null) + { + return new ArrayList(); + } + PrcPriceSetDetail q = new PrcPriceSetDetail(); + q.setPsvId(psvId); + return selectDetailList(q); + } + @Override public Map selectDetailOptions(Long psvId) { diff --git a/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml index 24e368a6..27b253e5 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml @@ -45,14 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ifnull(p.is_del, '0') as is_del, p.source_sheet, null as remark, null as tms_id, v.created_by, p.create_time, v.updated_by, p.update_time, - (select count(distinct ifnull(c.country_code, c.country_name)) from prc_price_set_detail c - where ifnull(c.is_del, '0') = '0' - and (c.psp_id = p.psp_id or (c.psv_id = p.psv_id and c.product_code = p.product_code)) - ) as country_count, - (select count(*) from prc_surcharge_rel r - inner join prc_surcharge s on s.sc_id = r.sc_id and ifnull(s.is_del, '0') = '0' - where ifnull(r.is_del, '0') = '0' - and r.product_id = p.psp_id and r.price_type = 'PRODUCT') as surcharge_count + null as country_count, null as surcharge_count from prc_price_set_product p inner join prc_price_set_version v on v.psv_id = p.psv_id @@ -176,6 +169,66 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + insert into prc_price_set_product ( price_type, psv_id, product_code, product_name, service_level, cargo_attr, diff --git a/bms-front/src/api/price/set.js b/bms-front/src/api/price/set.js index 7bbe9b52..66adfbc3 100644 --- a/bms-front/src/api/price/set.js +++ b/bms-front/src/api/price/set.js @@ -198,6 +198,15 @@ export function listSetDetailByProduct(psvId, productCode) { }) } +/** All detail rows for a version (no pagination); one call instead of N byProduct. */ +export function listSetDetailByVersion(psvId) { + return request({ + url: '/price/set/detail/byVersion', + method: 'get', + params: { psvId } + }) +} + /** 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 */ export function listSetDetailOptions(psvId) { return request({ diff --git a/bms-front/src/views/price/billing/bill.vue b/bms-front/src/views/price/billing/bill.vue index 96b9de3a..2a957ccc 100644 --- a/bms-front/src/views/price/billing/bill.vue +++ b/bms-front/src/views/price/billing/bill.vue @@ -125,7 +125,7 @@ @click="openBatchFee" >批量增加费用 - +