修改导入问题
This commit is contained in:
@@ -101,6 +101,9 @@ price.product.import.needCodeEffUnique=无法新增「同代码、不同生效
|
||||
price.product.import.success=导入成功:新增 {0} 个产品,跳过 {1} 个(同代码同生效日不覆盖);写入国家/重量段明细 {2} 行。
|
||||
price.product.import.success.detail1=产品主数据按「产品代码+生效日期」新增,不覆盖已有记录。国家明细:新生效日晚于上次则保留历史,上次失效日=本次生效日。
|
||||
price.product.import.success.detail2=范围:产品目录 + 重量段 + 运费/挂号费 + 尺寸/尾程/时效;国家码来自 bms_region。
|
||||
price.product.import.noSheet=未找到产品明细sheet(需与产品名称一致):{0}
|
||||
price.product.import.noCountry=产品明细sheet无有效国家/重量段数据:{0}
|
||||
price.product.import.euEmpty=国家表无欧盟成员(is_eu=1),无法展开「欧盟」
|
||||
price.product.import.success.unmatched=未匹配国家表(country_code 为空):{0}
|
||||
# 报价试算 TmsPriceQuote(对外 TMS API 错误码,保持英文契约)
|
||||
price.quote.priceNotHit=没有产品/国家/重量段绑定,暂无价格
|
||||
|
||||
+296
-83
@@ -23,7 +23,11 @@ import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
@@ -73,6 +77,9 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
@Autowired
|
||||
private IPrcSurchargeRelService surchargeRelService;
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
@Override
|
||||
public BmsProduct selectBmsProductById(Long productId)
|
||||
{
|
||||
@@ -207,7 +214,6 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String importProductExcel(MultipartFile file, boolean updateSupport, String operName) throws Exception
|
||||
{
|
||||
if (file == null || file.isEmpty())
|
||||
@@ -234,12 +240,14 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.noData"));
|
||||
}
|
||||
products = dedupeCatalogProducts(products);
|
||||
|
||||
Map<String, BmsRegion> regionByNameCn = loadRegionByNameCn();
|
||||
if (regionByNameCn.isEmpty())
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.regionEmpty"));
|
||||
}
|
||||
List<BmsRegion> euRegions = loadEuRegions(regionByNameCn);
|
||||
|
||||
int successNum = 0;
|
||||
int skipNum = 0;
|
||||
@@ -249,61 +257,35 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
|
||||
for (BmsProduct product : products)
|
||||
{
|
||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
TransactionStatus tx = transactionManager.getTransaction(def);
|
||||
try
|
||||
{
|
||||
product.setSourceSheet(product.getProductName());
|
||||
product.setCreateBy(operName);
|
||||
product.setUpdateBy(operName);
|
||||
|
||||
List<BmsProductCountry> countries = parseProductSheet(workbook, product, regionByNameCn, unmatchedCountries);
|
||||
// Sheet header date is the price version; catalog column is often stale
|
||||
Date sheetEff = resolveImportEffectiveDate(countries);
|
||||
Date newEff = toDateOnly(sheetEff != null ? sheetEff : product.getEffectiveDate());
|
||||
product.setEffectiveDate(newEff);
|
||||
if (newEff == null)
|
||||
{
|
||||
failureMsg.append("<br/>").append(product.getProductCode()).append("\uff1a")
|
||||
.append(MessageUtils.message("price.product.import.effEmpty"));
|
||||
continue;
|
||||
}
|
||||
BmsProduct existing = productMapper.selectBmsProductByCodeAndDate(
|
||||
product.getProductCode(), newEff);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
skipNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
applyProductStatus(product);
|
||||
try
|
||||
{
|
||||
productMapper.insertBmsProduct(product);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (isProductCodeUniqueViolation(e))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.needCodeEffUnique"));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
productMapper.expireOpenByProductCode(product.getProductCode(), newEff, product.getProductId());
|
||||
productMapper.refreshStatusByDates();
|
||||
countryNum += saveCountriesVersioned(product, countries);
|
||||
successNum++;
|
||||
}
|
||||
int[] nums = importOneProduct(workbook, product, operName, regionByNameCn, euRegions,
|
||||
unmatchedCountries);
|
||||
transactionManager.commit(tx);
|
||||
successNum += nums[0];
|
||||
skipNum += nums[1];
|
||||
countryNum += nums[2];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
failureMsg.append("<br/>").append(product.getProductCode()).append("\uff1a").append(e.getMessage());
|
||||
transactionManager.rollback(tx);
|
||||
String tip = e.getMessage();
|
||||
if (StringUtils.isEmpty(tip))
|
||||
{
|
||||
tip = e.getClass().getSimpleName();
|
||||
}
|
||||
failureMsg.append("<br/>").append(product.getProductCode()).append("\uff1a").append(tip);
|
||||
}
|
||||
}
|
||||
|
||||
if (failureMsg.length() > 0)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.partialFail",
|
||||
successNum, skipNum, failureMsg.toString()));
|
||||
// Do not throw: each product already committed/rolled back independently
|
||||
return MessageUtils.message("price.product.import.partialFail",
|
||||
Integer.valueOf(successNum), Integer.valueOf(skipNum), failureMsg.toString());
|
||||
}
|
||||
String msg = MessageUtils.message("price.product.import.success", successNum, skipNum, countryNum)
|
||||
+ "<br/>" + MessageUtils.message("price.product.import.success.detail1")
|
||||
@@ -316,10 +298,68 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
}
|
||||
|
||||
/** @return int[]{added, skipped, countryRows} */
|
||||
private int[] importOneProduct(Workbook workbook, BmsProduct product, String operName,
|
||||
Map<String, BmsRegion> regionByNameCn, List<BmsRegion> euRegions, Set<String> unmatchedCountries)
|
||||
{
|
||||
product.setSourceSheet(product.getProductName());
|
||||
product.setCreateBy(operName);
|
||||
product.setUpdateBy(operName);
|
||||
|
||||
Sheet productSheet = findProductSheet(workbook, product);
|
||||
if (productSheet == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.noSheet",
|
||||
product.getProductName()));
|
||||
}
|
||||
product.setSourceSheet(productSheet.getSheetName());
|
||||
List<BmsProductCountry> countries = parseProductSheet(productSheet, product,
|
||||
regionByNameCn, euRegions, unmatchedCountries);
|
||||
if (countries == null || countries.isEmpty())
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.noCountry",
|
||||
productSheet.getSheetName()));
|
||||
}
|
||||
Date sheetEff = resolveImportEffectiveDate(countries);
|
||||
Date newEff = toDateOnly(sheetEff != null ? sheetEff : product.getEffectiveDate());
|
||||
product.setEffectiveDate(newEff);
|
||||
if (newEff == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effEmpty"));
|
||||
}
|
||||
BmsProduct existing = productMapper.selectBmsProductByCodeAndDate(
|
||||
product.getProductCode(), newEff);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
product.setProductId(existing.getProductId());
|
||||
int countryRows = saveCountriesVersioned(product, countries);
|
||||
return new int[] { 0, 1, countryRows };
|
||||
}
|
||||
|
||||
applyProductStatus(product);
|
||||
try
|
||||
{
|
||||
productMapper.insertBmsProduct(product);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (isProductCodeUniqueViolation(e))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.needCodeEffUnique"));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
productMapper.expireOpenByProductCode(product.getProductCode(), newEff, product.getProductId());
|
||||
productMapper.refreshStatusByDates();
|
||||
int countryRows = saveCountriesVersioned(product, countries);
|
||||
return new int[] { 1, 0, countryRows };
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioned country save:
|
||||
* - newEff > last open: close old (expire_date = newEff), insert new (keep history)
|
||||
* - newEff equals last open: skip (never overwrite)
|
||||
* - newEff equals last open: replace open rows
|
||||
* - newEff < last open: reject
|
||||
*/
|
||||
private int saveCountriesVersioned(BmsProduct product, List<BmsProductCountry> countries)
|
||||
@@ -347,8 +387,8 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
else if (lastOpenEff != null)
|
||||
{
|
||||
// Same effective day: never overwrite existing country rows
|
||||
return 0;
|
||||
// Same effective day: replace open rows so re-import can fill/fix details
|
||||
countryMapper.deleteOpenByProductCodeAndEffectiveDate(productCode, newEff);
|
||||
}
|
||||
|
||||
for (BmsProductCountry c : countries)
|
||||
@@ -543,27 +583,141 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<BmsProductCountry> parseProductSheet(Workbook workbook, BmsProduct product,
|
||||
Map<String, BmsRegion> regionByNameCn, Set<String> unmatchedCountries)
|
||||
/** Keep first row per product_code (catalog often repeats code across country rows). */
|
||||
private List<BmsProduct> dedupeCatalogProducts(List<BmsProduct> products)
|
||||
{
|
||||
String sheetName = product.getProductName();
|
||||
Sheet sheet = workbook.getSheet(sheetName);
|
||||
if (sheet == null)
|
||||
Map<String, BmsProduct> map = new HashMap<>();
|
||||
for (BmsProduct p : products)
|
||||
{
|
||||
for (int i = 0; i < workbook.getNumberOfSheets(); i++)
|
||||
if (p == null || StringUtils.isEmpty(p.getProductCode()))
|
||||
{
|
||||
String name = workbook.getSheetName(i);
|
||||
if (SKIP_SHEETS.contains(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (name != null && name.trim().equals(sheetName.trim()))
|
||||
{
|
||||
sheet = workbook.getSheetAt(i);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
String code = p.getProductCode().trim().toUpperCase(Locale.ROOT);
|
||||
if (!map.containsKey(code))
|
||||
{
|
||||
map.put(code, p);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(map.values());
|
||||
}
|
||||
|
||||
private Sheet findProductSheet(Workbook workbook, BmsProduct product)
|
||||
{
|
||||
if (workbook == null || product == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
String wantName = product.getProductName();
|
||||
String wantCode = product.getProductCode();
|
||||
if (StringUtils.isNotEmpty(wantName))
|
||||
{
|
||||
Sheet exact = workbook.getSheet(wantName.trim());
|
||||
if (exact != null)
|
||||
{
|
||||
return exact;
|
||||
}
|
||||
}
|
||||
String nameKey = normalizeSheetKey(wantName);
|
||||
String codeKey = normalizeSheetKey(wantCode);
|
||||
Sheet best = null;
|
||||
int bestScore = 0;
|
||||
for (int i = 0; i < workbook.getNumberOfSheets(); i++)
|
||||
{
|
||||
String name = workbook.getSheetName(i);
|
||||
if (name == null || SKIP_SHEETS.contains(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
String key = normalizeSheetKey(name);
|
||||
if (StringUtils.isEmpty(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int score = 0;
|
||||
if (StringUtils.isNotEmpty(nameKey) && key.equals(nameKey))
|
||||
{
|
||||
return workbook.getSheetAt(i);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(nameKey) && key.contains(nameKey))
|
||||
{
|
||||
score = 100;
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(nameKey) && nameKey.contains(key) && key.length() >= 4)
|
||||
{
|
||||
score = 80;
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(codeKey) && key.contains(codeKey))
|
||||
{
|
||||
score = 60;
|
||||
}
|
||||
if (score > bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
best = workbook.getSheetAt(i);
|
||||
}
|
||||
}
|
||||
return bestScore >= 60 ? best : null;
|
||||
}
|
||||
|
||||
private static String normalizeSheetKey(String s)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
String out = s.trim().toLowerCase(Locale.ROOT);
|
||||
// unify dash variants: - \u2013 \u2014 \uff0d
|
||||
out = out.replace('\u2013', '-').replace('\u2014', '-').replace('\uff0d', '-');
|
||||
out = out.replace(" ", "").replace("\u3000", "");
|
||||
return out;
|
||||
}
|
||||
|
||||
private List<BmsRegion> loadEuRegions(Map<String, BmsRegion> regionByNameCn)
|
||||
{
|
||||
List<BmsRegion> list = new ArrayList<>();
|
||||
if (regionByNameCn == null)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
Set<String> seen = new HashSet<>();
|
||||
for (BmsRegion region : regionByNameCn.values())
|
||||
{
|
||||
if (region == null || !"1".equals(region.getIsEu()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.isEmpty(region.getCountryNameCn()) || StringUtils.isEmpty(region.getCountryCode2()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
String code = region.getCountryCode2().toUpperCase(Locale.ROOT);
|
||||
if (seen.contains(code))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
seen.add(code);
|
||||
list.add(region);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static boolean isEuZoneName(String name)
|
||||
{
|
||||
if (StringUtils.isEmpty(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
String n = name.trim();
|
||||
return "\u6b27\u76df".equals(n)
|
||||
|| "EU".equalsIgnoreCase(n)
|
||||
|| "\u6b27\u6d32\u8054\u76df".equals(n)
|
||||
|| "\u6b27\u76df\u56fd\u5bb6".equals(n);
|
||||
}
|
||||
|
||||
private List<BmsProductCountry> parseProductSheet(Sheet sheet, BmsProduct product,
|
||||
Map<String, BmsRegion> regionByNameCn, List<BmsRegion> euRegions, Set<String> unmatchedCountries)
|
||||
{
|
||||
if (sheet == null)
|
||||
{
|
||||
return new ArrayList<>();
|
||||
@@ -631,7 +785,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
if (StringUtils.isNotEmpty(countryCell))
|
||||
{
|
||||
currentCountry = countryCell.trim();
|
||||
currentCountry = normalizeCountryName(countryCell);
|
||||
currentSize = emptyToNull(cellString(row.getCell(colSize)));
|
||||
currentLastMile = emptyToNull(cellString(row.getCell(colLastMile)));
|
||||
currentLeadTime = emptyToNull(cellString(row.getCell(colLeadTime)));
|
||||
@@ -645,32 +799,54 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BigDecimal freight = cellDecimal(row.getCell(colFreight));
|
||||
BigDecimal registration = cellDecimal(row.getCell(colRegister));
|
||||
Date eff = sheetEffective != null ? sheetEffective : product.getEffectiveDate();
|
||||
|
||||
BmsRegion region = resolveRegion(currentCountry, regionByNameCn);
|
||||
BmsProductCountry c = new BmsProductCountry();
|
||||
if (region != null)
|
||||
{
|
||||
c.setCountryName(region.getCountryNameCn());
|
||||
c.setCountryCode(region.getCountryCode2());
|
||||
list.add(buildCountryRow(region.getCountryNameCn(), region.getCountryCode2(),
|
||||
range, freight, registration, currentSize, currentLastMile, currentLeadTime, eff));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if (isEuZoneName(currentCountry))
|
||||
{
|
||||
c.setCountryName(currentCountry);
|
||||
c.setCountryCode(null);
|
||||
unmatchedCountries.add(currentCountry);
|
||||
if (euRegions == null || euRegions.isEmpty())
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.euEmpty"));
|
||||
}
|
||||
for (BmsRegion eu : euRegions)
|
||||
{
|
||||
list.add(buildCountryRow(eu.getCountryNameCn(), eu.getCountryCode2(),
|
||||
range, freight, registration, currentSize, currentLastMile, currentLeadTime, eff));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
c.setWeightMin(range[0]);
|
||||
c.setWeightMax(range[1]);
|
||||
c.setFreightPrice(cellDecimal(row.getCell(colFreight)));
|
||||
c.setRegistrationFee(cellDecimal(row.getCell(colRegister)));
|
||||
c.setSizeLimit(currentSize);
|
||||
c.setLastMile(currentLastMile);
|
||||
c.setLeadTime(currentLeadTime);
|
||||
c.setEffectiveDate(sheetEffective != null ? sheetEffective : product.getEffectiveDate());
|
||||
list.add(c);
|
||||
unmatchedCountries.add(currentCountry);
|
||||
list.add(buildCountryRow(currentCountry, null,
|
||||
range, freight, registration, currentSize, currentLastMile, currentLeadTime, eff));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private BmsProductCountry buildCountryRow(String countryName, String countryCode, BigDecimal[] range,
|
||||
BigDecimal freight, BigDecimal registration, String sizeLimit, String lastMile, String leadTime, Date eff)
|
||||
{
|
||||
BmsProductCountry c = new BmsProductCountry();
|
||||
c.setCountryName(countryName);
|
||||
c.setCountryCode(countryCode);
|
||||
c.setWeightMin(range[0]);
|
||||
c.setWeightMax(range[1]);
|
||||
c.setFreightPrice(freight);
|
||||
c.setRegistrationFee(registration);
|
||||
c.setSizeLimit(sizeLimit);
|
||||
c.setLastMile(lastMile);
|
||||
c.setLeadTime(leadTime);
|
||||
c.setEffectiveDate(eff);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bms_region map: country_name_cn -> region (for country_code_2).
|
||||
*/
|
||||
@@ -723,11 +899,48 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
candidates.add(region);
|
||||
}
|
||||
}
|
||||
if (candidates.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (candidates.size() == 1)
|
||||
{
|
||||
return candidates.get(0);
|
||||
}
|
||||
return null;
|
||||
// Prefer longest Chinese name match (e.g. 捷克共和国 over 捷克)
|
||||
BmsRegion best = candidates.get(0);
|
||||
for (int i = 1; i < candidates.size(); i++)
|
||||
{
|
||||
String cn = candidates.get(i).getCountryNameCn();
|
||||
if (cn != null && cn.length() > best.getCountryNameCn().length())
|
||||
{
|
||||
best = candidates.get(i);
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/** Strip Excel footnotes like "澳大利亚(1区)\\n分区点击" */
|
||||
private static String normalizeCountryName(String name)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
String n = name.trim();
|
||||
int cut = n.length();
|
||||
int nl = n.indexOf('\n');
|
||||
if (nl >= 0 && nl < cut)
|
||||
{
|
||||
cut = nl;
|
||||
}
|
||||
int cr = n.indexOf('\r');
|
||||
if (cr >= 0 && cr < cut)
|
||||
{
|
||||
cut = cr;
|
||||
}
|
||||
n = n.substring(0, cut).trim();
|
||||
return n.isEmpty() ? null : n;
|
||||
}
|
||||
|
||||
private BigDecimal[] parseWeightRange(String label)
|
||||
|
||||
+1
-1
@@ -747,7 +747,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
|
||||
private static String formatWeightLabel(BigDecimal min, BigDecimal max)
|
||||
{
|
||||
return stripTrailingZeros(min) + "\u2264W\u2264" + stripTrailingZeros(max);
|
||||
return stripTrailingZeros(min) + "<W\u2264" + stripTrailingZeros(max);
|
||||
}
|
||||
|
||||
private static String stripTrailingZeros(BigDecimal v)
|
||||
|
||||
+1
-1
@@ -897,7 +897,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
|
||||
private static String formatWeightLabel(BigDecimal min, BigDecimal max)
|
||||
{
|
||||
return strip(min) + "\u2264W\u2264" + strip(max);
|
||||
return strip(min) + "<W\u2264" + strip(max);
|
||||
}
|
||||
|
||||
private static String strip(BigDecimal v)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<script setup>
|
||||
import SimpleTable from '@/components/SimpleTable'
|
||||
import { listProductCountries } from '@/api/price/product'
|
||||
import { formatWeightLabel } from '@/views/price/set/utils/priceSet'
|
||||
|
||||
const columns = [
|
||||
{ prop: 'countryName', label: '国家', width: 90, showOverflowTooltip: true },
|
||||
@@ -32,9 +33,11 @@ const columns = [
|
||||
{
|
||||
prop: 'weightMin',
|
||||
label: '重量段(KG)',
|
||||
width: 120,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
formatter: (row) => (row.weightMin != null || row.weightMax != null ? (row.weightMin + ' ~ ' + row.weightMax) : '-')
|
||||
formatter: (row) => (row.weightMin != null || row.weightMax != null
|
||||
? formatWeightLabel(row.weightMin, row.weightMax)
|
||||
: '-')
|
||||
},
|
||||
{ prop: 'freightPrice', label: '运费(RMB/KG)', width: 110, align: 'right' },
|
||||
{ prop: 'registrationFee', label: '挂号费(RMB/票)', width: 120, align: 'right' },
|
||||
|
||||
@@ -294,7 +294,7 @@ const rules = {
|
||||
}
|
||||
|
||||
function loadProducts() {
|
||||
listProduct({ pageNum: 1, pageSize: 500, status: '0' }).then(res => {
|
||||
listProduct({ pageNum: 1, pageSize: 500, status: '1' }).then(res => {
|
||||
productOptions.value = res.rows || []
|
||||
})
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ export function usePriceSetRefData() {
|
||||
|
||||
const productMap = computed(() => new Map(productOptions.value.map(p => [p.value, p])))
|
||||
|
||||
/** 加载可选产品(在售) */
|
||||
/** 加载可选产品(已生效) */
|
||||
function loadProducts() {
|
||||
return listProduct({ status: '0', pageNum: 1, pageSize: 1000 }).then(res => {
|
||||
return listProduct({ status: '1', pageNum: 1, pageSize: 1000 }).then(res => {
|
||||
productOptions.value = (res.rows || []).map(p => ({
|
||||
value: p.productCode,
|
||||
label: `${p.productCode} ${p.productName || ''}`.trim(),
|
||||
@@ -162,7 +162,7 @@ export function useDetailCascade(refData) {
|
||||
if (opt.registrationFee != null) row.fvRegistrationFee = Number(opt.registrationFee)
|
||||
}
|
||||
|
||||
/** 回显历史明细行:补齐字段,并把旧重量段文案归一化为 min≤W≤max */
|
||||
/** hydrate detail row; normalize weight label to min<W\u2264max */
|
||||
function hydrateRow(d, setType) {
|
||||
const row = toEditableDetailRow(d)
|
||||
if (!row.productCode) return row
|
||||
|
||||
@@ -94,9 +94,9 @@ export function trimNum(v) {
|
||||
return String(parseFloat(n.toFixed(6)))
|
||||
}
|
||||
|
||||
/** 重量段展示文案:1≤W≤2 */
|
||||
/** Weight label: left-open right-closed, e.g. 0.3<W\u22641 */
|
||||
export function formatWeightLabel(min, max) {
|
||||
return `${trimNum(min)}≤W≤${trimNum(max)}`
|
||||
return `${trimNum(min)}<W≤${trimNum(max)}`
|
||||
}
|
||||
|
||||
/** 国家唯一键:优先国家三字码,其次国家名称 */
|
||||
|
||||
Reference in New Issue
Block a user