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 bf2bcd4e..b458ab6c 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 @@ -27,7 +27,9 @@ import com.bms.common.utils.MessageUtils; import com.bms.price.domain.BmsProduct; import com.bms.price.domain.BmsProductCountry; import com.bms.price.domain.BmsProductImportTask; +import com.bms.price.domain.PrcPriceExcelFile; import com.bms.price.service.IBmsProductService; +import com.bms.price.service.IPrcPriceExcelFileService; /** * Product list (async Excel import) @@ -41,6 +43,9 @@ public class ProductController extends BaseController @Autowired private IBmsProductService productService; + @Autowired + private IPrcPriceExcelFileService priceExcelFileService; + @PreAuthorize("@ss.hasPermi('price:product:list')") @GetMapping("/list") public TableDataInfo list(BmsProduct product) @@ -50,6 +55,15 @@ public class ProductController extends BaseController return getDataTable(list); } + /** Imported quote Excel attachments for this product_code (via product.pef_id). */ + @PreAuthorize("@ss.hasPermi('price:product:query')") + @GetMapping("/{productCode}/excelFiles") + public AjaxResult excelFiles(@PathVariable String productCode) + { + List list = priceExcelFileService.selectByProductCode(productCode); + return success(list); + } + /** * 产品下拉选项(非分页)。 * 供计费列表、客户绑定等场景选择产品;不做权限控制(仍需登录)。 diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProduct.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProduct.java index ea6c0d22..1d69272a 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProduct.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProduct.java @@ -33,6 +33,8 @@ public class BmsProduct extends BaseEntity public static final String STATUS_EXPIRED = "2"; private String status; private String sourceSheet; + /** FK prc_price_excel_file.pef_id */ + private Long pefId; private Long tmsId; private Integer countryCount; private Integer surchargeCount; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceExcelFile.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceExcelFile.java new file mode 100644 index 00000000..aa0bfbc5 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceExcelFile.java @@ -0,0 +1,35 @@ +package com.bms.price.domain; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.bms.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * Import quote Excel attachment: prc_price_excel_file + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class PrcPriceExcelFile extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + public static final String TYPE_PRODUCT = "PRODUCT"; + public static final String TYPE_REDLINE = "REDLINE"; + public static final String TYPE_SALES = "SALES"; + + private Long pefId; + /** PRODUCT / REDLINE / SALES */ + private String excelType; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date effectiveTime; + private String fileName; + private String filePath; + private Long fileSize; + private String contentType; + private String fileExtension; + private String ossId; + /** Comma-separated sheet names (optional) */ + private String sheetNames; +} diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSet.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSet.java index 661693b3..fc0209c6 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSet.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSet.java @@ -48,4 +48,9 @@ public class PrcPriceSet extends BaseEntity private String pullFromLibrary; /** Y: even if version already has details, delete+re-pull from library */ private String forcePullLibrary; + /** + * Request-only: stamp this Excel attachment id onto prc_price_set_product.pef_id + * when saving IMPORT details (not a column on prc_price_set). + */ + private Long pefId; } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetProduct.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetProduct.java index e87e10e4..c73066ca 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetProduct.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetProduct.java @@ -37,6 +37,8 @@ public class PrcPriceSetProduct implements Serializable private Long sourceProductId; /** 来源Excel sheet */ private String sourceSheet; + /** 关联导入价表Excel附件 prc_price_excel_file.pef_id */ + private Long pefId; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceExcelFileMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceExcelFileMapper.java new file mode 100644 index 00000000..bc16572b --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceExcelFileMapper.java @@ -0,0 +1,24 @@ +package com.bms.price.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.bms.price.domain.PrcPriceExcelFile; + +/** + * Import quote Excel attachment mapper + */ +public interface PrcPriceExcelFileMapper +{ + public PrcPriceExcelFile selectPrcPriceExcelFileById(Long pefId); + + public List selectPrcPriceExcelFileList(PrcPriceExcelFile query); + + /** Distinct PRODUCT excel files linked by product.pef_id for this product_code */ + public List selectByProductCode(@Param("productCode") String productCode); + + public int insertPrcPriceExcelFile(PrcPriceExcelFile row); + + public int updatePrcPriceExcelFile(PrcPriceExcelFile row); + + public int deletePrcPriceExcelFileByIds(Long[] pefIds); +} diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceSetProductMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceSetProductMapper.java index 10efa5ba..fc4a685a 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceSetProductMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcPriceSetProductMapper.java @@ -34,4 +34,8 @@ public interface PrcPriceSetProductMapper /** Bind detail.psp_id from set product by psv + product_code. */ public int bindDetailPspByPsvId(@Param("psvId") Long psvId); + + /** Stamp Excel attachment id on set products under this version (optional code filter). */ + public int updatePefIdByPsvId(@Param("psvId") Long psvId, @Param("pefId") Long pefId, + @Param("productCodes") List productCodes); } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceExcelFileService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceExcelFileService.java new file mode 100644 index 00000000..98433644 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceExcelFileService.java @@ -0,0 +1,25 @@ +package com.bms.price.service; + +import java.util.Date; +import java.util.List; +import com.bms.price.domain.PrcPriceExcelFile; + +/** + * Import quote Excel attachment service + */ +public interface IPrcPriceExcelFileService +{ + public PrcPriceExcelFile selectPrcPriceExcelFileById(Long pefId); + + /** Import Excel attachments linked to this product_code via product.pef_id */ + public List selectByProductCode(String productCode); + + /** + * Persist uploaded Excel under upload/price/excel and insert metadata row. + * + * @param excelType PRODUCT / REDLINE / SALES + * @return inserted row with pefId + */ + public PrcPriceExcelFile saveImportExcel(String excelType, Date effectiveTime, byte[] bytes, + String filename, String operName) 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 9436d5a5..f0904e82 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 @@ -41,7 +41,9 @@ import com.bms.price.domain.PrcZone; import com.bms.price.mapper.BmsProductCountryMapper; import com.bms.price.mapper.BmsProductMapper; import com.bms.price.mapper.PrcZoneMapper; +import com.bms.price.domain.PrcPriceExcelFile; import com.bms.price.service.IBmsProductService; +import com.bms.price.service.IPrcPriceExcelFileService; import com.bms.price.service.IPrcSurchargeRelService; import com.bms.price.task.BmsProductImportAsyncRunner; import com.bms.price.util.ZoneCodeAbbrevs; @@ -94,6 +96,9 @@ public class BmsProductServiceImpl implements IBmsProductService @Autowired private BmsProductImportAsyncRunner importAsyncRunner; + @Autowired + private IPrcPriceExcelFileService priceExcelFileService; + @Override public BmsProduct selectBmsProductById(Long productId) { @@ -313,6 +318,10 @@ public class BmsProductServiceImpl implements IBmsProductService assertImportProductsNoDupCountryWeight(workbook, products, regionByNameCn, euRegions, zoneByCountryAndCode); + PrcPriceExcelFile excelFile = priceExcelFileService.saveImportExcel( + PrcPriceExcelFile.TYPE_PRODUCT, forcedEff, bytes, filename, operName); + Long pefId = excelFile != null ? excelFile.getPefId() : null; + int successNum = 0; int skipNum = 0; int countryNum = 0; @@ -331,6 +340,7 @@ public class BmsProductServiceImpl implements IBmsProductService try { product.setEffectiveDate(forcedEff); + product.setPefId(pefId); int[] nums = importOneProduct(workbook, product, operName, regionByNameCn, euRegions, zoneByCountryAndCode, unmatchedCountries, forcedEff); transactionManager.commit(tx); @@ -431,6 +441,10 @@ public class BmsProductServiceImpl implements IBmsProductService // Pre-check all products: reject whole import before any write if any is earlier than prev version assertImportProductsEffectiveNotBeforePrev(products, forcedEff); + PrcPriceExcelFile excelFile = priceExcelFileService.saveImportExcel( + PrcPriceExcelFile.TYPE_PRODUCT, forcedEff, bytes, filename, operName); + Long pefId = excelFile != null ? excelFile.getPefId() : null; + int successNum = 0; int skipNum = 0; int countryNum = 0; @@ -458,6 +472,7 @@ public class BmsProductServiceImpl implements IBmsProductService product.setDestRegion(countryLabel); product.setSourceSheet(block.sheetName); product.setEffectiveDate(forcedEff); + product.setPefId(pefId); if (StringUtils.isEmpty(product.getTaxMode())) { product.setTaxMode(resolveTaxMode(product.getProductName())); @@ -649,6 +664,7 @@ public class BmsProductServiceImpl implements IBmsProductService if (existing != null) { product.setProductId(existing.getProductId()); + patchProductPefId(product, operName); int countryRows = saveCountries(product, countries); return new int[] { 0, 1, countryRows }; } @@ -672,6 +688,19 @@ public class BmsProductServiceImpl implements IBmsProductService return new int[] { 1, 0, countryRows }; } + private void patchProductPefId(BmsProduct product, String operName) + { + if (product == null || product.getProductId() == null || product.getPefId() == null) + { + return; + } + BmsProduct pefPatch = new BmsProduct(); + pefPatch.setProductId(product.getProductId()); + pefPatch.setPefId(product.getPefId()); + pefPatch.setUpdateBy(operName); + productMapper.updateBmsProduct(pefPatch); + } + /** * Save country rows by effective_date. @@ -2159,6 +2188,7 @@ public class BmsProductServiceImpl implements IBmsProductService if (existing != null) { product.setProductId(existing.getProductId()); + patchProductPefId(product, operName); int countryRows = saveCountries(product, countries); return new int[] { 0, 1, countryRows }; } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceExcelFileServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceExcelFileServiceImpl.java new file mode 100644 index 00000000..5ea440a9 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceExcelFileServiceImpl.java @@ -0,0 +1,115 @@ +package com.bms.price.service.impl; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.bms.common.config.BmsConfig; +import com.bms.common.exception.ServiceException; +import com.bms.common.utils.DateUtils; +import com.bms.common.utils.StringUtils; +import com.bms.common.utils.file.FileUploadUtils; +import com.bms.common.utils.uuid.IdUtils; +import com.bms.price.domain.PrcPriceExcelFile; +import com.bms.price.mapper.PrcPriceExcelFileMapper; +import com.bms.price.service.IPrcPriceExcelFileService; + +/** + * Persist import Excel bytes and metadata + */ +@Service +public class PrcPriceExcelFileServiceImpl implements IPrcPriceExcelFileService +{ + private static final String SUB_DIR = "price/excel"; + + @Autowired + private PrcPriceExcelFileMapper excelFileMapper; + + @Override + public PrcPriceExcelFile selectPrcPriceExcelFileById(Long pefId) + { + return excelFileMapper.selectPrcPriceExcelFileById(pefId); + } + + @Override + public List selectByProductCode(String productCode) + { + if (StringUtils.isEmpty(productCode)) + { + return Collections.emptyList(); + } + List list = excelFileMapper.selectByProductCode(productCode.trim()); + return list == null ? Collections.emptyList() : list; + } + + @Override + public PrcPriceExcelFile saveImportExcel(String excelType, Date effectiveTime, byte[] bytes, + String filename, String operName) throws Exception + { + if (StringUtils.isEmpty(excelType)) + { + throw new ServiceException("excelType required"); + } + if (bytes == null || bytes.length == 0) + { + throw new ServiceException("excel empty"); + } + if (effectiveTime == null) + { + effectiveTime = new Date(); + } + String originalName = StringUtils.isNotEmpty(filename) ? filename : "import.xlsx"; + String ext = FilenameUtils.getExtension(originalName); + if (StringUtils.isEmpty(ext)) + { + ext = "xlsx"; + } + ext = ext.toLowerCase(Locale.ROOT); + + String uploadDir = BmsConfig.getUploadPath() + File.separator + SUB_DIR; + String pathName = DateUtils.datePath() + "/" + IdUtils.fastSimpleUUID() + "." + ext; + File dest = FileUploadUtils.getAbsoluteFile(uploadDir, pathName); + FileOutputStream fos = null; + try + { + fos = new FileOutputStream(dest); + fos.write(bytes); + } + finally + { + IOUtils.close(fos); + } + String storedPath = FileUploadUtils.getPathFileName(uploadDir, pathName); + + PrcPriceExcelFile row = new PrcPriceExcelFile(); + row.setExcelType(excelType.trim().toUpperCase(Locale.ROOT)); + row.setEffectiveTime(effectiveTime); + row.setFileName(originalName); + row.setFilePath(storedPath); + row.setFileSize(Long.valueOf(bytes.length)); + row.setContentType(resolveContentType(ext)); + row.setFileExtension(ext); + row.setCreateBy(operName); + excelFileMapper.insertPrcPriceExcelFile(row); + return row; + } + + private static String resolveContentType(String ext) + { + if ("xls".equals(ext)) + { + return "application/vnd.ms-excel"; + } + if ("xlsx".equals(ext)) + { + return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + } + return ""; + } +} 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 10649d04..c844ab6b 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 @@ -22,10 +22,12 @@ import com.bms.common.exception.ServiceException; import com.bms.common.utils.DateUtils; import com.bms.common.utils.MessageUtils; import com.bms.common.utils.StringUtils; +import com.bms.common.utils.SecurityUtils; import com.bms.common.utils.uuid.IdUtils; import com.bms.price.domain.BmsProduct; import com.bms.price.domain.BmsProductCountry; import com.bms.price.domain.PrcCustomerPriceSet; +import com.bms.price.domain.PrcPriceExcelFile; import com.bms.price.domain.PrcPriceSet; import com.bms.price.domain.PrcPriceSetCheckItem; import com.bms.price.domain.PrcPriceSetDetail; @@ -46,6 +48,7 @@ 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.IPrcPriceExcelFileService; import com.bms.price.service.IPrcPriceSetService; import com.bms.price.task.PrcPriceSetSaveAsyncRunner; @@ -117,6 +120,9 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService @Autowired private PrcPriceSetSaveAsyncRunner saveAsyncRunner; + @Autowired + private IPrcPriceExcelFileService priceExcelFileService; + @Override public PrcPriceSet selectPrcPriceSetById(Long priceSetId) { @@ -1071,6 +1077,18 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService { assertUpdateOnlyWeightBandsMatch(byProduct, detailIndex); } + String operName = null; + try + { + operName = SecurityUtils.getUsername(); + } + catch (Exception ignored) + { + operName = null; + } + PrcPriceExcelFile excelFile = priceExcelFileService.saveImportExcel( + PrcPriceExcelFile.TYPE_SALES, new Date(), bytes, filename, operName); + Long pefId = excelFile != null ? excelFile.getPefId() : null; Map productMap = new LinkedHashMap(); int updated = 0; @@ -1172,9 +1190,20 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService throw new ServiceException(MessageUtils.message("price.set.import.noDetailWritten")); } + if (pefId != null) + { + for (PrcPriceSetProduct sp : productMap.values()) + { + if (sp != null) + { + sp.setPefId(pefId); + } + } + } Map result = new HashMap(); result.put("products", new ArrayList(productMap.values())); result.put("details", details); + result.put("pefId", pefId); if (updateOnly) { result.put("message", MessageUtils.message("price.set.import.updateSuccess", @@ -1291,6 +1320,12 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService { assertUpdateOnlyWeightBandsMatch(byProduct, detailIndex); } + PrcPriceSetVersion verForFile = versionMapper.selectPrcPriceSetVersionById(psvId); + Date excelEff = verForFile != null && verForFile.getEffectiveTime() != null + ? verForFile.getEffectiveTime() : new Date(); + PrcPriceExcelFile excelFile = priceExcelFileService.saveImportExcel( + PrcPriceExcelFile.TYPE_SALES, excelEff, bytes, filename, operName); + Long pefId = excelFile != null ? excelFile.getPefId() : null; int updated = 0; int inserted = 0; @@ -1321,7 +1356,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService Long pspId = null; if (!updateOnly) { - pspId = ensureSetProduct(priceSetId, psvId, productCode, productName); + pspId = ensureSetProduct(priceSetId, psvId, productCode, productName, pefId); } for (BmsProductCountry row : e.getValue()) { @@ -1385,6 +1420,11 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService { setProductMapper.bindDetailPspByPsvId(psvId); } + if (pefId != null && (inserted > 0 || updated > 0)) + { + List codes = new ArrayList(byProduct.keySet()); + setProductMapper.updatePefIdByPsvId(psvId, pefId, codes); + } reportImportProgress(taskId, priceSetId, 95, "finishing"); if (inserted == 0 && updated == 0) { @@ -2935,7 +2975,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService d.setPriceSetId(set.getPriceSetId()); d.setPsvId(version.getPsvId()); Long pspId = ensureSetProduct(set.getPriceSetId(), version.getPsvId(), - d.getProductCode(), d.getProductName()); + d.getProductCode(), d.getProductName(), set.getPefId()); if (pspId != null) { d.setPspId(pspId); @@ -3059,6 +3099,12 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService * Uses request-scoped cache during bulk upsert to avoid N selects on same code. */ private Long ensureSetProduct(Long priceSetId, Long psvId, String productCode, String productNameHint) + { + return ensureSetProduct(priceSetId, psvId, productCode, productNameHint, null); + } + + private Long ensureSetProduct(Long priceSetId, Long psvId, String productCode, String productNameHint, + Long pefId) { if (psvId == null || StringUtils.isEmpty(productCode)) { @@ -3069,15 +3115,32 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService Map cache = setProductCacheTl.get(); if (cache != null && cache.containsKey(key)) { + if (pefId != null) + { + PrcPriceSetProduct pefPatch = new PrcPriceSetProduct(); + pefPatch.setPspId(cache.get(key)); + pefPatch.setPefId(pefId); + setProductMapper.updatePrcPriceSetProduct(pefPatch); + } return cache.get(key); } PrcPriceSetProduct existing = setProductMapper.selectByPsvIdAndCode(psvId, code); if (existing != null) { + boolean needUpdate = false; if (StringUtils.isEmpty(existing.getProductName()) && StringUtils.isNotEmpty(productNameHint) && !code.equals(productNameHint)) { existing.setProductName(productNameHint); + needUpdate = true; + } + if (pefId != null && (existing.getPefId() == null || !pefId.equals(existing.getPefId()))) + { + existing.setPefId(pefId); + needUpdate = true; + } + if (needUpdate) + { setProductMapper.updatePrcPriceSetProduct(existing); } if (cache != null) @@ -3090,6 +3153,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService row.setPriceSetId(priceSetId); row.setPsvId(psvId); row.setProductCode(code); + row.setPefId(pefId); BmsProduct lib = null; try { 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 93466b8b..501f8562 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 @@ -17,6 +17,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -30,7 +31,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select p.product_id, p.product_code, p.product_name, p.service_level, p.cargo_attr, p.dest_region, p.update_note, p.tax_mode, p.effective_date, p.expire_date, p.status, - p.source_sheet, p.remark, p.tms_id, p.created_by, p.create_time, p.updated_by, p.update_time, + p.source_sheet, p.pef_id, p.remark, p.tms_id, p.created_by, p.create_time, p.updated_by, p.update_time, (select count(distinct c.country_name) from product_country c where c.product_id = p.product_id or (c.product_id is null and c.product_code = p.product_code @@ -139,6 +140,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" expire_date, status, source_sheet, + pef_id, remark, tms_id, created_by, @@ -155,6 +157,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{expireDate}, #{status}, #{sourceSheet}, + #{pefId}, #{remark}, #{tmsId}, #{createBy}, @@ -176,6 +179,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" expire_date = #{expireDate}, status = #{status}, source_sheet = #{sourceSheet}, + pef_id = #{pefId}, remark = #{remark}, tms_id = #{tmsId}, updated_by = #{updateBy}, diff --git a/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceExcelFileMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceExcelFileMapper.xml new file mode 100644 index 00000000..2713d744 --- /dev/null +++ b/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceExcelFileMapper.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + select pef_id, excel_type, effective_time, file_name, file_path, file_size, content_type, + file_extension, oss_id, sheet_names, remark, created_by, create_time, updated_by, update_time + from prc_price_excel_file + + + + + + + + + + insert into prc_price_excel_file ( + excel_type, + effective_time, + file_name, + file_path, + file_size, + content_type, + file_extension, + oss_id, + sheet_names, + remark, + created_by, + create_time + ) values ( + #{excelType}, + #{effectiveTime}, + #{fileName}, + #{filePath}, + #{fileSize}, + #{contentType}, + #{fileExtension}, + #{ossId}, + #{sheetNames}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + update prc_price_excel_file + + excel_type = #{excelType}, + effective_time = #{effectiveTime}, + file_name = #{fileName}, + file_path = #{filePath}, + file_size = #{fileSize}, + content_type = #{contentType}, + file_extension = #{fileExtension}, + oss_id = #{ossId}, + sheet_names = #{sheetNames}, + remark = #{remark}, + updated_by = #{updateBy}, + update_time = sysdate() + + where pef_id = #{pefId} + + + + delete from prc_price_excel_file where pef_id in + + #{pefId} + + + + diff --git a/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceSetProductMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceSetProductMapper.xml index 382778e1..2b3a0495 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceSetProductMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/PrcPriceSetProductMapper.xml @@ -17,13 +17,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + select psp_id, price_set_id, psv_id, product_code, product_name, service_level, cargo_attr, - dest_region, update_note, tax_mode, source_product_id, source_sheet, create_time, update_time + dest_region, update_note, tax_mode, source_product_id, source_sheet, pef_id, + create_time, update_time from prc_price_set_product @@ -52,10 +54,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" insert into prc_price_set_product ( price_set_id, psv_id, product_code, product_name, service_level, cargo_attr, - dest_region, update_note, tax_mode, source_product_id, source_sheet, create_time + dest_region, update_note, tax_mode, source_product_id, source_sheet, pef_id, create_time ) values ( #{priceSetId}, #{psvId}, #{productCode}, #{productName}, #{serviceLevel}, #{cargoAttr}, - #{destRegion}, #{updateNote}, #{taxMode}, #{sourceProductId}, #{sourceSheet}, sysdate() + #{destRegion}, #{updateNote}, #{taxMode}, #{sourceProductId}, #{sourceSheet}, #{pefId}, sysdate() ) @@ -70,6 +72,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" tax_mode = #{taxMode}, source_product_id = #{sourceProductId}, source_sheet = #{sourceSheet}, + pef_id = #{pefId}, update_time = sysdate() where psp_id = #{pspId} @@ -88,11 +91,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" insert into prc_price_set_product ( price_set_id, psv_id, product_code, product_name, service_level, cargo_attr, - dest_region, update_note, tax_mode, source_product_id, source_sheet, create_time + dest_region, update_note, tax_mode, source_product_id, source_sheet, pef_id, create_time ) select price_set_id, #{newPsvId}, product_code, product_name, service_level, cargo_attr, - dest_region, update_note, tax_mode, source_product_id, source_sheet, sysdate() + dest_region, update_note, tax_mode, source_product_id, source_sheet, pef_id, sysdate() from prc_price_set_product where psv_id = #{srcPsvId} order by psp_id asc @@ -159,4 +162,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and (d.psp_id is null or d.psp_id <> sp.psp_id) + + update prc_price_set_product + set pef_id = #{pefId}, update_time = sysdate() + where psv_id = #{psvId} + + and product_code in + + #{code} + + + + diff --git a/bms-back/sql/price/prc_price_excel_file.sql b/bms-back/sql/price/prc_price_excel_file.sql index 4245c594..033e5101 100644 --- a/bms-back/sql/price/prc_price_excel_file.sql +++ b/bms-back/sql/price/prc_price_excel_file.sql @@ -1,26 +1,26 @@ -- ------------------------------------------------------------ --- 导入价表 Excel 附件记录(仅建表/字段,待确认后再接代码) +-- 导入价表 Excel 附件记录(建表/字段) -- 用途:产品价/红线价/销售价 Excel 导入时落库文件元数据 --- 关联:product.pef_id、prc_price_set_version.pef_id -> prc_price_excel_file.pef_id +-- 关联:product.pef_id、prc_price_set_product.pef_id -> prc_price_excel_file.pef_id -- ------------------------------------------------------------ -- 1) 主表:导入价表 Excel 附件 CREATE TABLE IF NOT EXISTS prc_price_excel_file ( - pef_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '1 主键', - excel_type varchar(20) NOT NULL COMMENT '2 价表类型 PRODUCT=产品价 REDLINE=红线价 SALES=销售价', - effective_time datetime NOT NULL COMMENT '3 生效时间(导入时选择/解析)', - file_name varchar(255) NOT NULL COMMENT '4 文件原始名称', - file_path varchar(500) NOT NULL COMMENT '5 文件存储路径(相对路径或完整URL)', - file_size bigint(20) DEFAULT 0 COMMENT '6 文件大小(字节)', - content_type varchar(100) DEFAULT '' COMMENT '7 MIME类型,如 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - file_extension varchar(20) DEFAULT '' COMMENT '8 扩展名,如 xlsx/xls', - oss_id varchar(64) DEFAULT NULL COMMENT '9 OSS/对象存储ID(可空)', - sheet_names varchar(1000) DEFAULT NULL COMMENT '10 导入涉及的 sheet 名(多个逗号分隔,可空)', - remark varchar(500) DEFAULT NULL COMMENT '11 备注', - created_by varchar(64) DEFAULT '' COMMENT '12 创建人', - create_time datetime DEFAULT NULL COMMENT '13 创建时间', - updated_by varchar(64) DEFAULT '' COMMENT '14 更新人', - update_time datetime DEFAULT NULL COMMENT '15 更新时间', + pef_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + excel_type varchar(20) NOT NULL COMMENT '价表类型 PRODUCT=产品价 REDLINE=红线价 SALES=销售价', + effective_time datetime NOT NULL COMMENT '生效时间(导入时选择/解析)', + file_name varchar(255) NOT NULL COMMENT '文件原始名称', + file_path varchar(500) NOT NULL COMMENT '文件存储路径(相对路径或完整URL)', + file_size bigint(20) DEFAULT 0 COMMENT '文件大小(字节)', + content_type varchar(100) DEFAULT '' COMMENT 'MIME类型', + file_extension varchar(20) DEFAULT '' COMMENT '扩展名,如 xlsx/xls', + oss_id varchar(64) DEFAULT NULL COMMENT 'OSS/对象存储ID(可空)', + sheet_names varchar(1000) DEFAULT NULL COMMENT '导入涉及的 sheet 名(多个逗号分隔,可空)', + remark varchar(500) DEFAULT NULL COMMENT '备注', + created_by varchar(64) DEFAULT '' COMMENT '创建人', + create_time datetime DEFAULT NULL COMMENT '创建时间', + updated_by varchar(64) DEFAULT '' COMMENT '更新人', + update_time datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (pef_id), KEY idx_pef_type_eff (excel_type, effective_time), KEY idx_pef_create_time (create_time) @@ -31,7 +31,7 @@ ALTER TABLE product ADD COLUMN pef_id bigint(20) DEFAULT NULL COMMENT '关联导入价表Excel附件 prc_price_excel_file.pef_id' AFTER source_sheet, ADD KEY idx_product_pef_id (pef_id); --- 3) 套餐版本表:关联导入附件(销售价 Excel 建价) -ALTER TABLE prc_price_set_version - ADD COLUMN pef_id bigint(20) DEFAULT NULL COMMENT '关联导入价表Excel附件 prc_price_excel_file.pef_id' AFTER price_build_mode, - ADD KEY idx_psv_pef_id (pef_id); +-- 3) 套餐产品表:关联导入附件(销售价 Excel 建价) +ALTER TABLE prc_price_set_product + ADD COLUMN pef_id bigint(20) DEFAULT NULL COMMENT '关联导入价表Excel附件 prc_price_excel_file.pef_id' AFTER source_sheet, + ADD KEY idx_psp_pef_id (pef_id); diff --git a/bms-front/src/api/price/product.js b/bms-front/src/api/price/product.js index c798bc96..a90b5634 100644 --- a/bms-front/src/api/price/product.js +++ b/bms-front/src/api/price/product.js @@ -167,3 +167,11 @@ export async function importProductCountryExcelAsync(file, countryCode, effectiv } return pollProductImportTask(taskId, onProgress) } + +/** List imported Excel attachments for product_code */ +export function listProductExcelFiles(productCode) { + return request({ + url: '/price/product/' + encodeURIComponent(productCode) + '/excelFiles', + method: 'get' + }) +} diff --git a/bms-front/src/views/price/basic/product/components/ProductExcelFileDrawer.vue b/bms-front/src/views/price/basic/product/components/ProductExcelFileDrawer.vue new file mode 100644 index 00000000..ac329c47 --- /dev/null +++ b/bms-front/src/views/price/basic/product/components/ProductExcelFileDrawer.vue @@ -0,0 +1,65 @@ + + + diff --git a/bms-front/src/views/price/basic/product/components/ProductExpiredDrawer.vue b/bms-front/src/views/price/basic/product/components/ProductExpiredDrawer.vue index 44310150..8631cfeb 100644 --- a/bms-front/src/views/price/basic/product/components/ProductExpiredDrawer.vue +++ b/bms-front/src/views/price/basic/product/components/ProductExpiredDrawer.vue @@ -52,8 +52,16 @@ - +