From b247bc2fd249c5d0c53f9edbdd848a448977e53f Mon Sep 17 00:00:00 2001 From: wuweihua <88888888> Date: Mon, 28 Sep 2026 18:01:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=89=B9=E9=87=8F=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=BB=B7=E6=A0=BC=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/price/PriceSetController.java | 14 + .../main/resources/i18n/messages.properties | 4 + .../bms/price/domain/PrcPriceSetDetail.java | 4 + .../price/mapper/PrcPriceSetDetailMapper.java | 7 + .../bms/price/service/IBmsProductService.java | 9 + .../price/service/IPrcPriceSetService.java | 16 ++ .../service/impl/BmsProductServiceImpl.java | 68 +++++ .../service/impl/PrcPriceSetServiceImpl.java | 271 ++++++++++++++++++ .../task/PrcPriceSetSaveAsyncRunner.java | 24 ++ .../mapper/price/PrcPriceSetDetailMapper.xml | 58 ++-- bms-front/src/api/price/set.js | 45 +++ .../components/ExcelImportDialog/index.vue | 32 ++- .../set/components/create/PriceEditDrawer.vue | 19 +- .../set/components/create/PriceEditPanel.vue | 1 + .../set/components/create/StepDetails.vue | 149 +++++++++- .../set/components/detail/SetDetailTable.vue | 52 +++- .../detail/SetVersionDetailDrawer.vue | 52 +++- .../set/composables/usePriceSetRefData.js | 5 +- bms-front/src/views/price/set/create.vue | 1 + 19 files changed, 777 insertions(+), 54 deletions(-) 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 04294fc6..9b292323 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 @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; import com.bms.common.annotation.Log; import com.bms.common.core.controller.BaseController; import com.bms.common.core.domain.AjaxResult; @@ -218,6 +219,19 @@ public class PriceSetController extends BaseController return toAjax(priceSetService.updateDetail(detail)); } + @PreAuthorize("@ss.hasPermi('price:set:edit') or @ss.hasPermi('price:set:forceEdit')") + @Log(title = "\u5957\u9910\u4ef7\u683c\u5bfc\u5165", businessType = BusinessType.IMPORT) + @PostMapping("/detail/importPrices") + public AjaxResult importDetailPrices(MultipartFile file, + @RequestParam("priceSetId") Long priceSetId, + @RequestParam(value = "psvId", required = false) Long psvId) throws Exception + { + String taskId = priceSetService.submitImportDetailPricesAsync(priceSetId, psvId, file, getUsername()); + Map payload = new HashMap(); + payload.put("taskId", taskId); + return success(payload); + } + /** * Async batch write of detail surcharge snapshots. Returns taskId; poll /save/task/{taskId}. */ 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 c7f38421..8a70c6e6 100644 --- a/bms-back/bms-admin/src/main/resources/i18n/messages.properties +++ b/bms-back/bms-admin/src/main/resources/i18n/messages.properties @@ -75,6 +75,10 @@ price.set.detail.registration.empty=固定价明细必须填写挂号费 price.set.detail.zone.empty=固定价明细必须选择分区 price.set.detail.roundMode.invalid=取值方式仅支持 UP / DOWN / HALF_UP price.set.detail.freight.belowBase=套餐运费不能低于导入基准价 {0} +price.set.import.fixedOnly=\u4ec5\u56fa\u5b9a\u4ef7\u5957\u9910\u652f\u6301\u5bfc\u5165\u4fee\u6539\u4ef7\u683c +price.set.import.noDetails=\u5957\u9910\u6682\u65e0\u4ef7\u683c\u660e\u7ec6\uff0c\u8bf7\u5148\u62c9\u53d6\u4ea7\u54c1\u4ef7 +price.set.import.noPriceRows=\u4ef7\u8868\u672a\u89e3\u6790\u5230\u6709\u6548\u4ef7\u683c\u884c +price.set.import.success=\u5bfc\u5165\u5b8c\u6210\uff1a\u66f4\u65b0 {0} \u6761\uff0c\u672a\u5339\u914d {1} \u6761\uff0c\u5957\u9910\u65e0\u5bf9\u5e94\u4ea7\u54c1 {2} \u4e2a price.set.customer.notExists=客户绑定不存在 price.set.customer.unbindAudit=审核中的套餐不允许解绑客户 price.set.customer.customerId.empty=客户ID不能为空 diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetDetail.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetDetail.java index e9869ad1..652a2705 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetDetail.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetDetail.java @@ -37,6 +37,10 @@ public class PrcPriceSetDetail implements Serializable private Long productCountryId; private BigDecimal fvValue; private BigDecimal fvRegistrationFee; + /** product base freight from bms_product_country (display only) */ + private BigDecimal baseFreightPrice; + /** product base registration from bms_product_country (display only) */ + private BigDecimal baseRegistrationFee; private BigDecimal discountValue; /** UP / DOWN / HALF_UP */ private String roundMode; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceSetDetailMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceSetDetailMapper.java index 42817419..3695a93d 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceSetDetailMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceSetDetailMapper.java @@ -1,5 +1,6 @@ package com.bms.price.mapper; +import java.math.BigDecimal; import java.util.Date; import java.util.List; import org.apache.ibatis.annotations.Param; @@ -75,4 +76,10 @@ public interface PrcPriceSetDetailMapper @Param("priceSetId") Long priceSetId, @Param("psvId") Long psvId, @Param("productCode") String productCode); + + /** Update package freight / registration only */ + public int updateDetailPrices( + @Param("psdId") Long psdId, + @Param("fvValue") BigDecimal fvValue, + @Param("fvRegistrationFee") BigDecimal fvRegistrationFee); } 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 4c7218a6..a47b51f8 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 @@ -58,4 +58,13 @@ public interface IBmsProductService /** Distinct base-price version options (by effective_date desc) for package create */ public List selectPriceVersionOptions(); + + /** + * Parse Weishi B2C quote Excel into productCode -> country/zone/weight price rows (no persist). + * Used by price-set detail price import. + */ + public java.util.Map> parseQuoteExcelByProduct(MultipartFile file) throws Exception; + + /** Parse quote Excel from in-memory bytes (async import). */ + public java.util.Map> parseQuoteExcelByProduct(byte[] bytes, String filename) throws Exception; } 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 d71ae487..29df6fa8 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 @@ -1,6 +1,7 @@ package com.bms.price.service; import java.util.Date; +import org.springframework.web.multipart.MultipartFile; import java.util.List; import java.util.Map; import com.bms.price.domain.PrcCustomerPriceSet; @@ -96,4 +97,19 @@ public interface IPrcPriceSetService /** poll async save progress */ public PrcPriceSetSaveTask getSaveTask(String taskId); + + /** + * Submit async import of Weishi B2C quote Excel into FIXED package detail prices. + * @return taskId for polling getSaveTask + */ + public String submitImportDetailPricesAsync(Long priceSetId, Long psvId, MultipartFile file, String operName) throws Exception; + + /** + * Sync worker: parse bytes and update FIXED detail prices matched by + * product + country + zone(if any) + weight band. + */ + public String importDetailPrices(Long priceSetId, Long psvId, byte[] bytes, String filename, String operName) throws Exception; + + /** Sync worker with optional taskId for progress reporting. */ + public String importDetailPrices(Long priceSetId, Long psvId, byte[] bytes, String filename, String operName, String taskId) throws Exception; } 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 eeb9cab2..f4a77a6b 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 @@ -8,6 +8,7 @@ import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -421,6 +422,73 @@ public class BmsProductServiceImpl implements IBmsProductService } } + @Override + public Map> parseQuoteExcelByProduct(MultipartFile file) throws Exception + { + if (file == null || file.isEmpty()) + { + throw new ServiceException(MessageUtils.message("price.product.import.fileEmpty")); + } + return parseQuoteExcelByProduct(file.getBytes(), file.getOriginalFilename()); + } + + @Override + public Map> parseQuoteExcelByProduct(byte[] bytes, String filename) throws Exception + { + if (bytes == null || bytes.length == 0) + { + throw new ServiceException(MessageUtils.message("price.product.import.fileEmpty")); + } + if (filename == null || !(filename.toLowerCase(Locale.ROOT).endsWith(".xlsx") + || filename.toLowerCase(Locale.ROOT).endsWith(".xls"))) + { + throw new ServiceException(MessageUtils.message("price.product.import.fileType")); + } + try (InputStream is = new java.io.ByteArrayInputStream(bytes); Workbook workbook = WorkbookFactory.create(is)) + { + Sheet catalog = workbook.getSheet(CATALOG_SHEET); + if (catalog == null) + { + throw new ServiceException(MessageUtils.message("price.product.import.sheetNotFound")); + } + List products = dedupeCatalogProducts(parseCatalog(catalog)); + if (products.isEmpty()) + { + throw new ServiceException(MessageUtils.message("price.product.import.noData")); + } + Map regionByNameCn = loadRegionByNameCn(); + List euRegions = loadEuRegions(regionByNameCn); + Map zoneByCountryAndCode = loadZoneByCountryAndCode(); + Set unmatchedCountries = new HashSet<>(); + Map> out = new LinkedHashMap<>(); + for (BmsProduct product : products) + { + if (product == null || StringUtils.isEmpty(product.getProductCode())) + { + continue; + } + Sheet productSheet = findProductSheet(workbook, product); + if (productSheet == null) + { + continue; + } + List rows = parseProductSheet(productSheet, product, + regionByNameCn, euRegions, zoneByCountryAndCode, unmatchedCountries); + if (rows == null || rows.isEmpty()) + { + continue; + } + String code = product.getProductCode().trim().toUpperCase(Locale.ROOT); + out.put(code, rows); + } + if (out.isEmpty()) + { + throw new ServiceException(MessageUtils.message("price.set.import.noPriceRows")); + } + return out; + } + } + @Override public List selectPriceVersionOptions() { 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 cc8198f0..1c9d0fb3 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 @@ -9,12 +9,14 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Locale; import java.util.Set; import java.util.zip.CRC32; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import com.bms.common.exception.ServiceException; import com.bms.common.utils.DateUtils; import com.bms.common.utils.MessageUtils; @@ -38,6 +40,7 @@ import com.bms.price.mapper.PrcPriceSetVersionMapper; import com.bms.price.mapper.PrcPriceSetVersionSurchargeMapper; import com.bms.price.mapper.PrcSurchargeMapper; import com.bms.price.mapper.PrcSurchargeRelMapper; +import com.bms.price.service.IBmsProductService; import com.bms.price.service.IPrcPriceSetService; import com.bms.price.task.PrcPriceSetSaveAsyncRunner; @@ -87,6 +90,10 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService @Autowired private BmsProductCountryMapper productCountryMapper; + @Lazy + @Autowired + private IBmsProductService productService; + @Lazy @Autowired private PrcPriceSetSaveAsyncRunner saveAsyncRunner; @@ -797,6 +804,270 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService return rows; } + + @Override + public String submitImportDetailPricesAsync(Long priceSetId, Long psvId, MultipartFile file, String operName) throws Exception + { + PrcPriceSet db = requireSet(priceSetId); + assertChildEditable(db); + if (!TYPE_FIXED.equals(db.getSetType())) + { + throw new ServiceException(MessageUtils.message("price.set.import.fixedOnly")); + } + if (file == null || file.isEmpty()) + { + throw new ServiceException(MessageUtils.message("price.product.import.fileEmpty")); + } + String filename = file.getOriginalFilename(); + if (filename == null || !(filename.toLowerCase(Locale.ROOT).endsWith(".xlsx") + || filename.toLowerCase(Locale.ROOT).endsWith(".xls"))) + { + throw new ServiceException(MessageUtils.message("price.product.import.fileType")); + } + byte[] bytes = file.getBytes(); + if (psvId == null) + { + psvId = resolveCurrentPsvId(db); + } + String taskId = IdUtils.fastSimpleUUID(); + saveAsyncRunner.put(taskId, PrcPriceSetSaveTask.STATUS_PENDING, 0, "queued", priceSetId, null); + saveAsyncRunner.runImportPrices(taskId, priceSetId, psvId, bytes, filename, operName); + return taskId; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String importDetailPrices(Long priceSetId, Long psvId, byte[] bytes, String filename, String operName) throws Exception + { + return importDetailPrices(priceSetId, psvId, bytes, filename, operName, null); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String importDetailPrices(Long priceSetId, Long psvId, byte[] bytes, String filename, String operName, String taskId) throws Exception + { + PrcPriceSet db = requireSet(priceSetId); + assertChildEditable(db); + if (!TYPE_FIXED.equals(db.getSetType())) + { + throw new ServiceException(MessageUtils.message("price.set.import.fixedOnly")); + } + if (psvId == null) + { + psvId = resolveCurrentPsvId(db); + } + reportImportProgress(taskId, priceSetId, 20, "parsing excel"); + Map> byProduct = productService.parseQuoteExcelByProduct(bytes, filename); + reportImportProgress(taskId, priceSetId, 50, "matching details"); + PrcPriceSetDetail q = new PrcPriceSetDetail(); + q.setPriceSetId(priceSetId); + if (psvId != null) + { + q.setPsvId(psvId); + } + List details = detailMapper.selectPrcPriceSetDetailList(q); + if (details == null || details.isEmpty()) + { + throw new ServiceException(MessageUtils.message("price.set.import.noDetails")); + } + Map> detailIndex = new HashMap>(); + for (PrcPriceSetDetail d : details) + { + if (d == null || StringUtils.isEmpty(d.getProductCode())) + { + continue; + } + String pc = d.getProductCode().trim().toUpperCase(Locale.ROOT); + List list = detailIndex.get(pc); + if (list == null) + { + list = new ArrayList(); + detailIndex.put(pc, list); + } + list.add(d); + } + int updated = 0; + int unmatched = 0; + int skippedProduct = 0; + Set touched = new HashSet(); + for (Map.Entry> e : byProduct.entrySet()) + { + String productCode = e.getKey(); + List candidates = detailIndex.get(productCode); + if (candidates == null || candidates.isEmpty()) + { + skippedProduct++; + continue; + } + for (BmsProductCountry row : e.getValue()) + { + if (row == null) + { + continue; + } + List hits = matchImportDetails(candidates, row); + if (hits.isEmpty()) + { + unmatched++; + continue; + } + for (PrcPriceSetDetail hit : hits) + { + if (hit.getPsdId() == null || touched.contains(hit.getPsdId())) + { + continue; + } + detailMapper.updateDetailPrices(hit.getPsdId(), row.getFreightPrice(), row.getRegistrationFee()); + hit.setFvValue(row.getFreightPrice()); + hit.setFvRegistrationFee(row.getRegistrationFee()); + touched.add(hit.getPsdId()); + updated++; + } + } + } + reportImportProgress(taskId, priceSetId, 95, "finishing"); + return MessageUtils.message("price.set.import.success", + Integer.valueOf(updated), Integer.valueOf(unmatched), Integer.valueOf(skippedProduct)); + } + + private void reportImportProgress(String taskId, Long priceSetId, int percent, String message) + { + if (StringUtils.isEmpty(taskId) || saveAsyncRunner == null) + { + return; + } + saveAsyncRunner.put(taskId, PrcPriceSetSaveTask.STATUS_RUNNING, percent, message, priceSetId, null); + } + + /** Resolve editable version id: draft > pending > effect > first version. */ + private Long resolveCurrentPsvId(PrcPriceSet set) + { + if (set == null) + { + return null; + } + if (set.getVersion() != null && set.getVersion().getPsvId() != null) + { + return set.getVersion().getPsvId(); + } + List versions = set.getVersions(); + if (versions == null || versions.isEmpty()) + { + PrcPriceSetVersion q = new PrcPriceSetVersion(); + q.setPriceSetId(set.getPriceSetId()); + versions = versionMapper.selectPrcPriceSetVersionList(q); + } + if (versions == null || versions.isEmpty()) + { + return null; + } + PrcPriceSetVersion draft = null; + PrcPriceSetVersion pending = null; + PrcPriceSetVersion effect = null; + for (PrcPriceSetVersion v : versions) + { + if (v == null) + { + continue; + } + if (VER_DRAFT.equals(v.getStatus()) && draft == null) + { + draft = v; + } + else if (VER_PENDING.equals(v.getStatus()) && pending == null) + { + pending = v; + } + else if (VER_EFFECT.equals(v.getStatus()) && effect == null) + { + effect = v; + } + } + PrcPriceSetVersion pick = draft != null ? draft : (pending != null ? pending : (effect != null ? effect : versions.get(0))); + return pick == null ? null : pick.getPsvId(); + } + + private List matchImportDetails(List candidates, BmsProductCountry row) + { + List hits = new ArrayList(); + if (candidates == null || row == null) + { + return hits; + } + String importZone = normZone(row.getZoneCode()); + for (PrcPriceSetDetail d : candidates) + { + if (!sameCountry(d, row)) + { + continue; + } + if (!sameWeight(d.getWeightMin(), d.getWeightMax(), row.getWeightMin(), row.getWeightMax())) + { + continue; + } + String detailZone = normZone(d.getZoneCode()); + if (StringUtils.isNotEmpty(importZone)) + { + if (!importZone.equals(detailZone)) + { + continue; + } + } + else if (StringUtils.isNotEmpty(detailZone)) + { + // Excel has no zone: only match non-zone details + continue; + } + hits.add(d); + } + return hits; + } + + private boolean sameCountry(PrcPriceSetDetail d, BmsProductCountry row) + { + if (d == null || row == null) + { + return false; + } + if (StringUtils.isNotEmpty(d.getCountryCode()) && StringUtils.isNotEmpty(row.getCountryCode())) + { + return d.getCountryCode().trim().equalsIgnoreCase(row.getCountryCode().trim()); + } + if (StringUtils.isNotEmpty(d.getCountryName()) && StringUtils.isNotEmpty(row.getCountryName())) + { + return d.getCountryName().trim().equals(row.getCountryName().trim()); + } + return false; + } + + private boolean sameWeight(BigDecimal aMin, BigDecimal aMax, BigDecimal bMin, BigDecimal bMax) + { + return decimalEq(aMin, bMin) && decimalEq(aMax, bMax); + } + + private boolean decimalEq(BigDecimal a, BigDecimal b) + { + if (a == null && b == null) + { + return true; + } + if (a == null || b == null) + { + return false; + } + return a.compareTo(b) == 0; + } + + private String normZone(String zone) + { + if (StringUtils.isEmpty(zone)) + { + return ""; + } + return zone.trim().toUpperCase(Locale.ROOT); + } + + @Override public int updateDetail(PrcPriceSetDetail detail) { diff --git a/bms-back/bms-system/src/main/java/com/bms/price/task/PrcPriceSetSaveAsyncRunner.java b/bms-back/bms-system/src/main/java/com/bms/price/task/PrcPriceSetSaveAsyncRunner.java index 5bc75eaf..9e54f37e 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/task/PrcPriceSetSaveAsyncRunner.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/task/PrcPriceSetSaveAsyncRunner.java @@ -76,6 +76,30 @@ public class PrcPriceSetSaveAsyncRunner } } + + /** Background import of quote Excel into package detail prices. */ + @Async("threadPoolTaskExecutor") + public void runImportPrices(String taskId, Long priceSetId, Long psvId, byte[] bytes, String filename, String operName) + { + try + { + put(taskId, PrcPriceSetSaveTask.STATUS_RUNNING, 10, "parsing excel", priceSetId, null); + String message = priceSetService.importDetailPrices(priceSetId, psvId, bytes, filename, operName, taskId); + put(taskId, PrcPriceSetSaveTask.STATUS_SUCCESS, 100, message, priceSetId, null); + log.info("async import prices done, taskId={}, priceSetId={}", taskId, priceSetId); + } + catch (Exception e) + { + log.error("async import prices failed, taskId={}, priceSetId={}", taskId, priceSetId, e); + String msg = e.getMessage(); + if (StringUtils.isEmpty(msg)) + { + msg = e.getClass().getSimpleName(); + } + put(taskId, PrcPriceSetSaveTask.STATUS_FAIL, 100, "failed", priceSetId, msg); + } + } + public void put(String taskId, String status, int percent, String message, Long priceSetId, String error) { PrcPriceSetSaveTask task = new PrcPriceSetSaveTask(); diff --git a/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceSetDetailMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceSetDetailMapper.xml index 2bb8c55a..c0fa26ca 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceSetDetailMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceSetDetailMapper.xml @@ -23,6 +23,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -46,54 +48,62 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"