增加分区功能

This commit is contained in:
wuweihua
2026-09-15 10:28:07 +08:00
parent ddbbd73ba2
commit c28b5a2b6e
26 changed files with 1512 additions and 1215 deletions
@@ -12,133 +12,136 @@ import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.price.domain.XtdZoneCountry;
import com.ruoyi.price.domain.XtdZoneDivision;
import com.ruoyi.price.domain.XtdZoneScheme;
import com.ruoyi.price.service.IXtdZoneService;
import com.ruoyi.price.domain.PrcZone;
import com.ruoyi.price.domain.PrcZoneDetail;
import com.ruoyi.price.domain.PrcZoneRegion;
import com.ruoyi.price.service.IPrcZoneService;
/**
* 分区管理
*
* @author ruoyi
* Zone management: bms_region -> zone -> postcode detail
*/
@RestController
@RequestMapping("/price/zone")
public class ZoneController extends BaseController
{
@Autowired
private IXtdZoneService zoneService;
private IPrcZoneService zoneService;
// ========== countries that already have zones (from bms_region) ==========
@PreAuthorize("@ss.hasPermi('price:zone:list')")
@GetMapping("/scheme/list")
public TableDataInfo schemeList(XtdZoneScheme scheme)
@GetMapping("/country/list")
public TableDataInfo countryList(PrcZoneRegion query)
{
startPage();
List<XtdZoneScheme> list = zoneService.selectXtdZoneSchemeList(scheme);
List<PrcZoneRegion> list = zoneService.selectZoneRegionList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('price:zone:query')")
@GetMapping("/scheme/{zsId}")
public AjaxResult getScheme(@PathVariable Long zsId)
@GetMapping("/country/{regionId}")
public AjaxResult getCountry(@PathVariable Long regionId)
{
return success(zoneService.selectXtdZoneSchemeById(zsId));
}
@PreAuthorize("@ss.hasPermi('price:zone:add')")
@Log(title = "分区方案", businessType = BusinessType.INSERT)
@PostMapping("/scheme")
public AjaxResult addScheme(@Validated @RequestBody XtdZoneScheme scheme)
{
scheme.setCreateBy(getUsername());
return toAjax(zoneService.insertXtdZoneScheme(scheme));
}
@PreAuthorize("@ss.hasPermi('price:zone:edit')")
@Log(title = "分区方案", businessType = BusinessType.UPDATE)
@PutMapping("/scheme")
public AjaxResult editScheme(@Validated @RequestBody XtdZoneScheme scheme)
{
scheme.setUpdateBy(getUsername());
return toAjax(zoneService.updateXtdZoneScheme(scheme));
return success(zoneService.selectZoneRegionById(regionId));
}
@PreAuthorize("@ss.hasPermi('price:zone:remove')")
@Log(title = "分区方案", businessType = BusinessType.DELETE)
@DeleteMapping("/scheme/{zsIds}")
public AjaxResult removeScheme(@PathVariable Long[] zsIds)
@Log(title = "ZoneRegion", businessType = BusinessType.DELETE)
@DeleteMapping("/country/{regionIds}")
public AjaxResult removeCountryZones(@PathVariable Long[] regionIds)
{
return toAjax(zoneService.deleteXtdZoneSchemeByIds(zsIds));
return toAjax(zoneService.deleteZonesByRegionIds(regionIds));
}
// ========== zone ==========
@PreAuthorize("@ss.hasPermi('price:zone:list')")
@GetMapping("/division/list")
public TableDataInfo divisionList(XtdZoneDivision division)
@GetMapping("/item/list")
public TableDataInfo zoneList(PrcZone zone)
{
startPage();
List<XtdZoneDivision> list = zoneService.selectXtdZoneDivisionList(division);
List<PrcZone> list = zoneService.selectPrcZoneList(zone);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('price:zone:query')")
@GetMapping("/item/{zoneId}")
public AjaxResult getZone(@PathVariable Long zoneId)
{
return success(zoneService.selectPrcZoneById(zoneId));
}
@PreAuthorize("@ss.hasPermi('price:zone:add')")
@Log(title = "Zone", businessType = BusinessType.INSERT)
@PostMapping("/item")
public AjaxResult addZone(@Validated @RequestBody PrcZone zone)
{
return toAjax(zoneService.insertPrcZone(zone));
}
@PreAuthorize("@ss.hasPermi('price:zone:edit')")
@Log(title = "Zone", businessType = BusinessType.UPDATE)
@PutMapping("/item")
public AjaxResult editZone(@Validated @RequestBody PrcZone zone)
{
return toAjax(zoneService.updatePrcZone(zone));
}
@PreAuthorize("@ss.hasPermi('price:zone:remove')")
@Log(title = "Zone", businessType = BusinessType.DELETE)
@DeleteMapping("/item/{zoneIds}")
public AjaxResult removeZone(@PathVariable Long[] zoneIds)
{
return toAjax(zoneService.deletePrcZoneByIds(zoneIds));
}
// ========== detail ==========
@PreAuthorize("@ss.hasPermi('price:zone:list')")
@GetMapping("/detail/list")
public TableDataInfo detailList(PrcZoneDetail detail)
{
startPage();
List<PrcZoneDetail> list = zoneService.selectPrcZoneDetailList(detail);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('price:zone:add')")
@Log(title = "分区区划", businessType = BusinessType.INSERT)
@PostMapping("/division")
public AjaxResult addDivision(@Validated @RequestBody XtdZoneDivision division)
@Log(title = "ZoneDetail", businessType = BusinessType.INSERT)
@PostMapping("/detail")
public AjaxResult addDetail(@Validated @RequestBody PrcZoneDetail detail)
{
return toAjax(zoneService.insertXtdZoneDivision(division));
return toAjax(zoneService.insertPrcZoneDetail(detail));
}
@PreAuthorize("@ss.hasPermi('price:zone:edit')")
@Log(title = "分区区划", businessType = BusinessType.UPDATE)
@PutMapping("/division")
public AjaxResult editDivision(@Validated @RequestBody XtdZoneDivision division)
@Log(title = "ZoneDetail", businessType = BusinessType.UPDATE)
@PutMapping("/detail")
public AjaxResult editDetail(@Validated @RequestBody PrcZoneDetail detail)
{
return toAjax(zoneService.updateXtdZoneDivision(division));
return toAjax(zoneService.updatePrcZoneDetail(detail));
}
@PreAuthorize("@ss.hasPermi('price:zone:remove')")
@Log(title = "分区区划", businessType = BusinessType.DELETE)
@DeleteMapping("/division/{zdIds}")
public AjaxResult removeDivision(@PathVariable Long[] zdIds)
@Log(title = "ZoneDetail", businessType = BusinessType.DELETE)
@DeleteMapping("/detail/{detailIds}")
public AjaxResult removeDetail(@PathVariable Long[] detailIds)
{
return toAjax(zoneService.deleteXtdZoneDivisionByIds(zdIds));
}
@PreAuthorize("@ss.hasPermi('price:zone:list')")
@GetMapping("/country/list")
public TableDataInfo countryList(XtdZoneCountry country)
{
startPage();
List<XtdZoneCountry> list = zoneService.selectXtdZoneCountryList(country);
return getDataTable(list);
return toAjax(zoneService.deletePrcZoneDetailByIds(detailIds));
}
@PreAuthorize("@ss.hasPermi('price:zone:add')")
@Log(title = "分区国家", businessType = BusinessType.INSERT)
@PostMapping("/country")
public AjaxResult addCountry(@Validated @RequestBody XtdZoneCountry country)
@Log(title = "ZoneImport", businessType = BusinessType.IMPORT)
@PostMapping("/importData")
public AjaxResult importData(MultipartFile file) throws Exception
{
return toAjax(zoneService.insertXtdZoneCountry(country));
}
@PreAuthorize("@ss.hasPermi('price:zone:edit')")
@Log(title = "分区国家", businessType = BusinessType.UPDATE)
@PutMapping("/country")
public AjaxResult editCountry(@Validated @RequestBody XtdZoneCountry country)
{
return toAjax(zoneService.updateXtdZoneCountry(country));
}
@PreAuthorize("@ss.hasPermi('price:zone:remove')")
@Log(title = "分区国家", businessType = BusinessType.DELETE)
@DeleteMapping("/country/{zcIds}")
public AjaxResult removeCountry(@PathVariable Long[] zcIds)
{
return toAjax(zoneService.deleteXtdZoneCountryByIds(zcIds));
String message = zoneService.importZoneExcel(file, getUsername());
return success(message);
}
}
@@ -82,8 +82,18 @@ price.set.customer.priority.invalid=优先级必须大于等于 1
# 重量段 PrcWeight
price.weight.range.empty=起始重量和结束重量不能为空
price.weight.range.invalid=起始重量必须小于结束重量
# 分区 XtdZone
price.zone.delete.hasDivision=分区方案【{0}】存在区划明细,不允许删除
# Zone PrcZone (country -> zone -> postcode)
price.zone.import.fileEmpty=上传文件不能为空
price.zone.import.fileType=仅支持 xls / xlsx 文件
price.zone.import.noSheet=未找到分区 sheet(sheet 名需以「分区」结尾,如「澳大利亚分区」)
price.zone.import.noData=分区 sheet 无有效邮编/分区数据
price.zone.import.success=导入成功:{0} 个国家,{1} 个分区,{2} 条邮编明细({3})
price.zone.import.unmatched=;未匹配国家已跳过:{0}
price.zone.import.regionNotFound=未在 bms_region 匹配到国家:{0}
price.zone.import.regionEmpty=bms_region 无可用国家数据,请先同步/维护国家表
price.zone.region.notFound=国家不存在或已删除
price.zone.region.required=请选择国家(bms_region)
price.zone.countryCode.empty=国家编码不能为空,请检查 bms_region.country_code_2
# 产品导入 BmsProduct
price.product.codeDate.exists=同一产品代码与生效日期已存在,不能覆盖历史数据
price.product.effectiveDate.empty=生效日期不能为空
@@ -0,0 +1,30 @@
package com.ruoyi.price.domain;
import java.io.Serializable;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/** Zone under bms_region: prc_zone */
@Data
public class PrcZone implements Serializable
{
private static final long serialVersionUID = 1L;
private Long zoneId;
private Long regionId;
/** ISO2 country code stored on prc_zone */
private String countryCode;
private String zoneCode;
private String zoneName;
private Integer zoneSort;
private String remark;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** list display, not a table column */
private Integer detailCount;
/** list display from bms_region */
private String countryNameCn;
}
@@ -5,16 +5,15 @@ import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/** 分区国家 xtd_zonecountry */
/** Zone postcode detail prc_zone_detail */
@Data
public class XtdZoneCountry implements Serializable
public class PrcZoneDetail implements Serializable
{
private static final long serialVersionUID = 1L;
private Long zcId;
private Long zdId;
private String countryCode;
private String zcDividekind;
private Long detailId;
private Long zoneId;
private String postcode;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@@ -0,0 +1,21 @@
package com.ruoyi.price.domain;
import java.io.Serializable;
import lombok.Data;
/**
* Zone country list row: bms_region + zone aggregates (not a table)
*/
@Data
public class PrcZoneRegion implements Serializable
{
private static final long serialVersionUID = 1L;
private Long regionId;
private String countryNameCn;
private String countryNameEn;
private String countryCode2;
private String status;
private Integer zoneCount;
private Integer detailCount;
}
@@ -1,27 +0,0 @@
package com.ruoyi.price.domain;
import java.io.Serializable;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/** 分区区划 xtd_zone_division */
@Data
public class XtdZoneDivision implements Serializable
{
private static final long serialVersionUID = 1L;
private Long zdId;
private Long zsId;
private Integer zdSort;
private String zdCode;
private String znName;
private String znEname;
private String znNote;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** 列表展示,非表字段 */
private Integer countryCount;
}
@@ -1,24 +0,0 @@
package com.ruoyi.price.domain;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/** 分区方案 xtd_zone_scheme */
@Data
@EqualsAndHashCode(callSuper = true)
public class XtdZoneScheme extends BaseEntity
{
private static final long serialVersionUID = 1L;
private Long zsId;
private String zsName;
/** on / off */
private String ssCode;
private String pgCode;
private Long snId;
private String zsNote;
private Long tmsId;
/** 列表展示,非表字段 */
private Integer divisionCount;
}
@@ -0,0 +1,28 @@
package com.ruoyi.price.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.price.domain.PrcZoneDetail;
public interface PrcZoneDetailMapper
{
public PrcZoneDetail selectPrcZoneDetailById(Long detailId);
public List<PrcZoneDetail> selectPrcZoneDetailList(PrcZoneDetail detail);
public int countByZoneId(Long zoneId);
public int countByRegionId(Long regionId);
public int insertPrcZoneDetail(PrcZoneDetail detail);
public int insertPrcZoneDetailBatch(@Param("list") List<PrcZoneDetail> list);
public int updatePrcZoneDetail(PrcZoneDetail detail);
public int deletePrcZoneDetailByIds(Long[] detailIds);
public int deletePrcZoneDetailByZoneId(Long zoneId);
public int deletePrcZoneDetailByRegionId(Long regionId);
}
@@ -0,0 +1,30 @@
package com.ruoyi.price.mapper;
import java.util.List;
import com.ruoyi.price.domain.PrcZone;
import com.ruoyi.price.domain.PrcZoneRegion;
public interface PrcZoneMapper
{
public PrcZone selectPrcZoneById(Long zoneId);
public List<PrcZone> selectPrcZoneList(PrcZone zone);
public List<PrcZone> selectPrcZoneListByRegionId(Long regionId);
public List<PrcZoneRegion> selectZoneRegionList(PrcZoneRegion query);
public PrcZoneRegion selectZoneRegionById(Long regionId);
public int countByRegionId(Long regionId);
public int insertPrcZone(PrcZone zone);
public int updatePrcZone(PrcZone zone);
public int deletePrcZoneByIds(Long[] zoneIds);
public int deletePrcZoneByRegionId(Long regionId);
public int deletePrcZoneByRegionIds(Long[] regionIds);
}
@@ -1,26 +0,0 @@
package com.ruoyi.price.mapper;
import java.util.List;
import com.ruoyi.price.domain.XtdZoneCountry;
/**
* 分区国家 数据层
*
* @author ruoyi
*/
public interface XtdZoneCountryMapper
{
public XtdZoneCountry selectXtdZoneCountryById(Long zcId);
public List<XtdZoneCountry> selectXtdZoneCountryListByZdId(Long zdId);
public List<XtdZoneCountry> selectXtdZoneCountryList(XtdZoneCountry country);
public int insertXtdZoneCountry(XtdZoneCountry country);
public int updateXtdZoneCountry(XtdZoneCountry country);
public int deleteXtdZoneCountryByIds(Long[] zcIds);
public int countByZdId(Long zdId);
}
@@ -1,26 +0,0 @@
package com.ruoyi.price.mapper;
import java.util.List;
import com.ruoyi.price.domain.XtdZoneDivision;
/**
* 分区区划 数据层
*
* @author ruoyi
*/
public interface XtdZoneDivisionMapper
{
public XtdZoneDivision selectXtdZoneDivisionById(Long zdId);
public List<XtdZoneDivision> selectXtdZoneDivisionListByZsId(Long zsId);
public List<XtdZoneDivision> selectXtdZoneDivisionList(XtdZoneDivision division);
public int insertXtdZoneDivision(XtdZoneDivision division);
public int updateXtdZoneDivision(XtdZoneDivision division);
public int deleteXtdZoneDivisionByIds(Long[] zdIds);
public int countByZsId(Long zsId);
}
@@ -1,22 +0,0 @@
package com.ruoyi.price.mapper;
import java.util.List;
import com.ruoyi.price.domain.XtdZoneScheme;
/**
* 分区方案 数据层
*
* @author ruoyi
*/
public interface XtdZoneSchemeMapper
{
public XtdZoneScheme selectXtdZoneSchemeById(Long zsId);
public List<XtdZoneScheme> selectXtdZoneSchemeList(XtdZoneScheme scheme);
public int insertXtdZoneScheme(XtdZoneScheme scheme);
public int updateXtdZoneScheme(XtdZoneScheme scheme);
public int deleteXtdZoneSchemeByIds(Long[] zsIds);
}
@@ -0,0 +1,39 @@
package com.ruoyi.price.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.price.domain.PrcZone;
import com.ruoyi.price.domain.PrcZoneDetail;
import com.ruoyi.price.domain.PrcZoneRegion;
public interface IPrcZoneService
{
public PrcZoneRegion selectZoneRegionById(Long regionId);
public List<PrcZoneRegion> selectZoneRegionList(PrcZoneRegion query);
/** Delete all zones (and details) for the given bms_region ids */
public int deleteZonesByRegionIds(Long[] regionIds);
public PrcZone selectPrcZoneById(Long zoneId);
public List<PrcZone> selectPrcZoneList(PrcZone zone);
public int insertPrcZone(PrcZone zone);
public int updatePrcZone(PrcZone zone);
public int deletePrcZoneByIds(Long[] zoneIds);
public PrcZoneDetail selectPrcZoneDetailById(Long detailId);
public List<PrcZoneDetail> selectPrcZoneDetailList(PrcZoneDetail detail);
public int insertPrcZoneDetail(PrcZoneDetail detail);
public int updatePrcZoneDetail(PrcZoneDetail detail);
public int deletePrcZoneDetailByIds(Long[] detailIds);
public String importZoneExcel(MultipartFile file, String operName) throws Exception;
}
@@ -1,44 +0,0 @@
package com.ruoyi.price.service;
import java.util.List;
import com.ruoyi.price.domain.XtdZoneCountry;
import com.ruoyi.price.domain.XtdZoneDivision;
import com.ruoyi.price.domain.XtdZoneScheme;
/**
* 分区管理 服务层
*
* @author ruoyi
*/
public interface IXtdZoneService
{
public XtdZoneScheme selectXtdZoneSchemeById(Long zsId);
public List<XtdZoneScheme> selectXtdZoneSchemeList(XtdZoneScheme scheme);
public int insertXtdZoneScheme(XtdZoneScheme scheme);
public int updateXtdZoneScheme(XtdZoneScheme scheme);
public int deleteXtdZoneSchemeByIds(Long[] zsIds);
public XtdZoneDivision selectXtdZoneDivisionById(Long zdId);
public List<XtdZoneDivision> selectXtdZoneDivisionList(XtdZoneDivision division);
public int insertXtdZoneDivision(XtdZoneDivision division);
public int updateXtdZoneDivision(XtdZoneDivision division);
public int deleteXtdZoneDivisionByIds(Long[] zdIds);
public XtdZoneCountry selectXtdZoneCountryById(Long zcId);
public List<XtdZoneCountry> selectXtdZoneCountryList(XtdZoneCountry country);
public int insertXtdZoneCountry(XtdZoneCountry country);
public int updateXtdZoneCountry(XtdZoneCountry country);
public int deleteXtdZoneCountryByIds(Long[] zcIds);
}
@@ -0,0 +1,503 @@
package com.ruoyi.price.service.impl;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
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.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.price.domain.PrcZone;
import com.ruoyi.price.domain.PrcZoneDetail;
import com.ruoyi.price.domain.PrcZoneRegion;
import com.ruoyi.price.mapper.PrcZoneDetailMapper;
import com.ruoyi.price.mapper.PrcZoneMapper;
import com.ruoyi.price.service.IPrcZoneService;
import com.ruoyi.system.domain.BmsRegion;
import com.ruoyi.system.mapper.BmsRegionMapper;
/**
* Zone management: bms_region -> prc_zone -> postcode detail
*/
@Service
public class PrcZoneServiceImpl implements IPrcZoneService
{
private static final String SHEET_SUFFIX = "\u5206\u533a";
private static final String COL_POSTCODE = "\u90ae\u7f16";
private static final String COL_ZONE = "\u5206\u533a";
private static final Pattern ZONE_NUM = Pattern.compile("(\\d+)");
private static final int BATCH_SIZE = 500;
private static final DataFormatter CELL_FMT = new DataFormatter(Locale.ROOT);
@Autowired
private PrcZoneMapper zoneMapper;
@Autowired
private PrcZoneDetailMapper detailMapper;
@Autowired
private BmsRegionMapper regionMapper;
@Override
public PrcZoneRegion selectZoneRegionById(Long regionId)
{
return zoneMapper.selectZoneRegionById(regionId);
}
@Override
public List<PrcZoneRegion> selectZoneRegionList(PrcZoneRegion query)
{
return zoneMapper.selectZoneRegionList(query);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int deleteZonesByRegionIds(Long[] regionIds)
{
if (regionIds == null || regionIds.length == 0)
{
return 0;
}
for (Long regionId : regionIds)
{
detailMapper.deletePrcZoneDetailByRegionId(regionId);
}
return zoneMapper.deletePrcZoneByRegionIds(regionIds);
}
@Override
public PrcZone selectPrcZoneById(Long zoneId)
{
PrcZone zone = zoneMapper.selectPrcZoneById(zoneId);
if (zone != null)
{
zone.setDetailCount(detailMapper.countByZoneId(zoneId));
}
return zone;
}
@Override
public List<PrcZone> selectPrcZoneList(PrcZone zone)
{
return zoneMapper.selectPrcZoneList(zone);
}
@Override
public int insertPrcZone(PrcZone zone)
{
if (zone.getRegionId() == null)
{
throw new ServiceException(MessageUtils.message("price.zone.region.required"));
}
BmsRegion region = regionMapper.selectRegionById(zone.getRegionId());
if (region == null)
{
throw new ServiceException(MessageUtils.message("price.zone.region.notFound"));
}
if (StringUtils.isEmpty(zone.getCountryCode()))
{
zone.setCountryCode(region.getCountryCode2());
}
else
{
zone.setCountryCode(zone.getCountryCode().trim().toUpperCase(Locale.ROOT));
}
if (StringUtils.isEmpty(zone.getCountryCode()))
{
throw new ServiceException(MessageUtils.message("price.zone.countryCode.empty"));
}
if (zone.getZoneSort() == null)
{
zone.setZoneSort(extractZoneSort(zone.getZoneCode()));
}
if (StringUtils.isEmpty(zone.getZoneName()))
{
zone.setZoneName(buildZoneName(region.getCountryNameCn(), zone.getZoneCode()));
}
return zoneMapper.insertPrcZone(zone);
}
@Override
public int updatePrcZone(PrcZone zone)
{
if (zone.getRegionId() != null && StringUtils.isEmpty(zone.getCountryCode()))
{
BmsRegion region = regionMapper.selectRegionById(zone.getRegionId());
if (region != null)
{
zone.setCountryCode(region.getCountryCode2());
}
}
else if (StringUtils.isNotEmpty(zone.getCountryCode()))
{
zone.setCountryCode(zone.getCountryCode().trim().toUpperCase(Locale.ROOT));
}
if (zone.getZoneSort() == null && StringUtils.isNotEmpty(zone.getZoneCode()))
{
zone.setZoneSort(extractZoneSort(zone.getZoneCode()));
}
return zoneMapper.updatePrcZone(zone);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int deletePrcZoneByIds(Long[] zoneIds)
{
return zoneMapper.deletePrcZoneByIds(zoneIds);
}
@Override
public PrcZoneDetail selectPrcZoneDetailById(Long detailId)
{
return detailMapper.selectPrcZoneDetailById(detailId);
}
@Override
public List<PrcZoneDetail> selectPrcZoneDetailList(PrcZoneDetail detail)
{
return detailMapper.selectPrcZoneDetailList(detail);
}
@Override
public int insertPrcZoneDetail(PrcZoneDetail detail)
{
return detailMapper.insertPrcZoneDetail(detail);
}
@Override
public int updatePrcZoneDetail(PrcZoneDetail detail)
{
return detailMapper.updatePrcZoneDetail(detail);
}
@Override
public int deletePrcZoneDetailByIds(Long[] detailIds)
{
return detailMapper.deletePrcZoneDetailByIds(detailIds);
}
@Override
@Transactional(rollbackFor = Exception.class)
public String importZoneExcel(MultipartFile file, String operName) throws Exception
{
if (file == null || file.isEmpty())
{
throw new ServiceException(MessageUtils.message("price.zone.import.fileEmpty"));
}
String filename = file.getOriginalFilename();
if (filename == null || !(filename.toLowerCase(Locale.ROOT).endsWith(".xls")
|| filename.toLowerCase(Locale.ROOT).endsWith(".xlsx")))
{
throw new ServiceException(MessageUtils.message("price.zone.import.fileType"));
}
Map<String, BmsRegion> regionByNameCn = loadRegionByNameCn();
if (regionByNameCn.isEmpty())
{
throw new ServiceException(MessageUtils.message("price.zone.import.regionEmpty"));
}
int countryCount = 0;
int zoneCount = 0;
int detailCount = 0;
List<String> importedCountries = new ArrayList<>();
List<String> unmatched = new ArrayList<>();
try (InputStream is = file.getInputStream(); Workbook workbook = WorkbookFactory.create(is))
{
List<Sheet> zoneSheets = findZoneSheets(workbook);
if (zoneSheets.isEmpty())
{
throw new ServiceException(MessageUtils.message("price.zone.import.noSheet"));
}
for (Sheet sheet : zoneSheets)
{
String countryName = parseCountryNameFromSheet(sheet.getSheetName());
if (StringUtils.isEmpty(countryName))
{
continue;
}
Map<String, List<String>> zonePostcodes = parseZonePostcodes(sheet);
if (zonePostcodes.isEmpty())
{
continue;
}
BmsRegion region = resolveRegion(countryName, regionByNameCn);
if (region == null)
{
unmatched.add(countryName);
continue;
}
int[] counts = replaceRegionZones(region, zonePostcodes);
countryCount += 1;
zoneCount += counts[0];
detailCount += counts[1];
importedCountries.add(region.getCountryNameCn());
}
}
if (countryCount == 0)
{
if (!unmatched.isEmpty())
{
throw new ServiceException(MessageUtils.message("price.zone.import.regionNotFound",
String.join(",", unmatched)));
}
throw new ServiceException(MessageUtils.message("price.zone.import.noData"));
}
String msg = MessageUtils.message("price.zone.import.success", countryCount, zoneCount, detailCount,
String.join(",", importedCountries));
if (!unmatched.isEmpty())
{
msg = msg + " " + MessageUtils.message("price.zone.import.unmatched", String.join(",", unmatched));
}
return msg;
}
private int[] replaceRegionZones(BmsRegion region, Map<String, List<String>> zonePostcodes)
{
if (StringUtils.isEmpty(region.getCountryCode2()))
{
throw new ServiceException(MessageUtils.message("price.zone.countryCode.empty"));
}
Long regionId = region.getRegionId();
detailMapper.deletePrcZoneDetailByRegionId(regionId);
zoneMapper.deletePrcZoneByRegionId(regionId);
int zoneInserted = 0;
int detailInserted = 0;
List<Map.Entry<String, List<String>>> entries = new ArrayList<>(zonePostcodes.entrySet());
entries.sort(Comparator.comparingInt(e -> extractZoneSort(e.getKey())));
String countryName = region.getCountryNameCn();
for (Map.Entry<String, List<String>> entry : entries)
{
String zoneCode = entry.getKey();
PrcZone zone = new PrcZone();
zone.setRegionId(regionId);
zone.setCountryCode(region.getCountryCode2());
zone.setZoneCode(zoneCode);
zone.setZoneName(buildZoneName(countryName, zoneCode));
zone.setZoneSort(extractZoneSort(zoneCode));
zoneMapper.insertPrcZone(zone);
zoneInserted++;
Set<String> uniquePostcodes = new LinkedHashSet<>(entry.getValue());
List<PrcZoneDetail> batch = new ArrayList<>(BATCH_SIZE);
for (String postcode : uniquePostcodes)
{
PrcZoneDetail detail = new PrcZoneDetail();
detail.setZoneId(zone.getZoneId());
detail.setPostcode(postcode);
batch.add(detail);
if (batch.size() >= BATCH_SIZE)
{
detailMapper.insertPrcZoneDetailBatch(batch);
detailInserted += batch.size();
batch = new ArrayList<>(BATCH_SIZE);
}
}
if (!batch.isEmpty())
{
detailMapper.insertPrcZoneDetailBatch(batch);
detailInserted += batch.size();
}
}
return new int[] { zoneInserted, detailInserted };
}
private List<Sheet> findZoneSheets(Workbook workbook)
{
List<Sheet> list = new ArrayList<>();
for (int i = 0; i < workbook.getNumberOfSheets(); i++)
{
Sheet sheet = workbook.getSheetAt(i);
if (sheet == null)
{
continue;
}
String name = StringUtils.trim(sheet.getSheetName());
if (name != null && name.endsWith(SHEET_SUFFIX) && name.length() > SHEET_SUFFIX.length())
{
list.add(sheet);
}
}
return list;
}
private String parseCountryNameFromSheet(String sheetName)
{
String name = StringUtils.trim(sheetName);
if (name == null || !name.endsWith(SHEET_SUFFIX))
{
return null;
}
return StringUtils.trim(name.substring(0, name.length() - SHEET_SUFFIX.length()));
}
private Map<String, List<String>> parseZonePostcodes(Sheet sheet)
{
Map<String, List<String>> map = new LinkedHashMap<>();
int postcodeCol = -1;
int zoneCol = -1;
int headerRow = -1;
int lastRow = sheet.getLastRowNum();
for (int r = 0; r <= Math.min(lastRow, 20); r++)
{
Row row = sheet.getRow(r);
if (row == null)
{
continue;
}
for (int c = 0; c < row.getLastCellNum(); c++)
{
String val = cellText(row.getCell(c));
if (COL_POSTCODE.equals(val))
{
postcodeCol = c;
headerRow = r;
}
else if (COL_ZONE.equals(val))
{
zoneCol = c;
headerRow = r;
}
}
if (postcodeCol >= 0 && zoneCol >= 0)
{
break;
}
}
if (postcodeCol < 0 || zoneCol < 0 || headerRow < 0)
{
return map;
}
for (int r = headerRow + 1; r <= lastRow; r++)
{
Row row = sheet.getRow(r);
if (row == null)
{
continue;
}
String postcode = cellText(row.getCell(postcodeCol));
String zoneCode = cellText(row.getCell(zoneCol));
if (StringUtils.isEmpty(postcode) || StringUtils.isEmpty(zoneCode))
{
continue;
}
if (postcode.endsWith(".0") && postcode.matches("\\d+\\.0"))
{
postcode = postcode.substring(0, postcode.length() - 2);
}
map.computeIfAbsent(zoneCode, k -> new ArrayList<>()).add(postcode);
}
return map;
}
private String cellText(Cell cell)
{
if (cell == null)
{
return "";
}
return StringUtils.trim(CELL_FMT.formatCellValue(cell));
}
private Map<String, BmsRegion> loadRegionByNameCn()
{
BmsRegion query = new BmsRegion();
List<BmsRegion> regions = regionMapper.selectRegionList(query);
Map<String, BmsRegion> map = new HashMap<>();
if (regions == null)
{
return map;
}
for (BmsRegion region : regions)
{
if (region != null && StringUtils.isNotEmpty(region.getCountryNameCn()))
{
map.put(region.getCountryNameCn().trim(), region);
}
}
return map;
}
private BmsRegion resolveRegion(String excelName, Map<String, BmsRegion> regionByNameCn)
{
if (StringUtils.isEmpty(excelName) || regionByNameCn == null || regionByNameCn.isEmpty())
{
return null;
}
String name = excelName.trim();
BmsRegion exact = regionByNameCn.get(name);
if (exact != null)
{
return exact;
}
BmsRegion best = null;
int bestLen = -1;
for (BmsRegion region : regionByNameCn.values())
{
String cn = region.getCountryNameCn();
if (StringUtils.isEmpty(cn))
{
continue;
}
if (name.contains(cn) || cn.contains(name))
{
if (cn.length() > bestLen)
{
best = region;
bestLen = cn.length();
}
}
}
return best;
}
private static String buildZoneName(String countryName, String zoneCode)
{
return (countryName == null ? "" : countryName) + "(" + zoneCode + ")";
}
private static int extractZoneSort(String zoneCode)
{
if (StringUtils.isEmpty(zoneCode))
{
return 0;
}
Matcher m = ZONE_NUM.matcher(zoneCode);
if (m.find())
{
try
{
return Integer.parseInt(m.group(1));
}
catch (NumberFormatException ignored)
{
return 0;
}
}
return 0;
}
}
@@ -1,161 +0,0 @@
package com.ruoyi.price.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.price.domain.XtdZoneCountry;
import com.ruoyi.price.domain.XtdZoneDivision;
import com.ruoyi.price.domain.XtdZoneScheme;
import com.ruoyi.price.mapper.XtdZoneCountryMapper;
import com.ruoyi.price.mapper.XtdZoneDivisionMapper;
import com.ruoyi.price.mapper.XtdZoneSchemeMapper;
import com.ruoyi.price.service.IXtdZoneService;
/**
* 分区管理 服务层实现
*
* @author ruoyi
*/
@Service
public class XtdZoneServiceImpl implements IXtdZoneService
{
@Autowired
private XtdZoneSchemeMapper schemeMapper;
@Autowired
private XtdZoneDivisionMapper divisionMapper;
@Autowired
private XtdZoneCountryMapper countryMapper;
@Override
public XtdZoneScheme selectXtdZoneSchemeById(Long zsId)
{
XtdZoneScheme scheme = schemeMapper.selectXtdZoneSchemeById(zsId);
if (scheme != null)
{
scheme.setDivisionCount(divisionMapper.countByZsId(zsId));
}
return scheme;
}
@Override
public List<XtdZoneScheme> selectXtdZoneSchemeList(XtdZoneScheme scheme)
{
List<XtdZoneScheme> list = schemeMapper.selectXtdZoneSchemeList(scheme);
for (XtdZoneScheme item : list)
{
item.setDivisionCount(divisionMapper.countByZsId(item.getZsId()));
}
return list;
}
@Override
public int insertXtdZoneScheme(XtdZoneScheme scheme)
{
if (StringUtils.isEmpty(scheme.getSsCode()))
{
scheme.setSsCode("on");
}
return schemeMapper.insertXtdZoneScheme(scheme);
}
@Override
public int updateXtdZoneScheme(XtdZoneScheme scheme)
{
return schemeMapper.updateXtdZoneScheme(scheme);
}
@Override
public int deleteXtdZoneSchemeByIds(Long[] zsIds)
{
for (Long zsId : zsIds)
{
int count = divisionMapper.countByZsId(zsId);
if (count > 0)
{
XtdZoneScheme scheme = schemeMapper.selectXtdZoneSchemeById(zsId);
String name = scheme != null ? scheme.getZsName() : String.valueOf(zsId);
throw new ServiceException(MessageUtils.message("price.zone.delete.hasDivision", name));
}
}
return schemeMapper.deleteXtdZoneSchemeByIds(zsIds);
}
@Override
public XtdZoneDivision selectXtdZoneDivisionById(Long zdId)
{
XtdZoneDivision division = divisionMapper.selectXtdZoneDivisionById(zdId);
if (division != null)
{
division.setCountryCount(countryMapper.countByZdId(zdId));
}
return division;
}
@Override
public List<XtdZoneDivision> selectXtdZoneDivisionList(XtdZoneDivision division)
{
List<XtdZoneDivision> list = divisionMapper.selectXtdZoneDivisionList(division);
for (XtdZoneDivision item : list)
{
item.setCountryCount(countryMapper.countByZdId(item.getZdId()));
}
return list;
}
@Override
public int insertXtdZoneDivision(XtdZoneDivision division)
{
return divisionMapper.insertXtdZoneDivision(division);
}
@Override
public int updateXtdZoneDivision(XtdZoneDivision division)
{
return divisionMapper.updateXtdZoneDivision(division);
}
@Override
public int deleteXtdZoneDivisionByIds(Long[] zdIds)
{
return divisionMapper.deleteXtdZoneDivisionByIds(zdIds);
}
@Override
public XtdZoneCountry selectXtdZoneCountryById(Long zcId)
{
return countryMapper.selectXtdZoneCountryById(zcId);
}
@Override
public List<XtdZoneCountry> selectXtdZoneCountryList(XtdZoneCountry country)
{
return countryMapper.selectXtdZoneCountryList(country);
}
@Override
public int insertXtdZoneCountry(XtdZoneCountry country)
{
if (StringUtils.isEmpty(country.getZcDividekind()))
{
country.setZcDividekind("C");
}
return countryMapper.insertXtdZoneCountry(country);
}
@Override
public int updateXtdZoneCountry(XtdZoneCountry country)
{
return countryMapper.updateXtdZoneCountry(country);
}
@Override
public int deleteXtdZoneCountryByIds(Long[] zcIds)
{
return countryMapper.deleteXtdZoneCountryByIds(zcIds);
}
}
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.price.mapper.PrcZoneDetailMapper">
<resultMap type="PrcZoneDetail" id="PrcZoneDetailResult">
<id property="detailId" column="detail_id" />
<result property="zoneId" column="zone_id" />
<result property="postcode" column="postcode" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectPrcZoneDetailVo">
select detail_id, zone_id, postcode, create_time, update_time
from prc_zone_detail
</sql>
<select id="selectPrcZoneDetailById" parameterType="Long" resultMap="PrcZoneDetailResult">
<include refid="selectPrcZoneDetailVo"/>
where detail_id = #{detailId}
</select>
<select id="selectPrcZoneDetailList" parameterType="PrcZoneDetail" resultMap="PrcZoneDetailResult">
<include refid="selectPrcZoneDetailVo"/>
<where>
<if test="zoneId != null">
AND zone_id = #{zoneId}
</if>
<if test="postcode != null and postcode != ''">
AND postcode like concat('%', #{postcode}, '%')
</if>
</where>
order by postcode asc, detail_id asc
</select>
<select id="countByZoneId" parameterType="Long" resultType="int">
select count(1) from prc_zone_detail where zone_id = #{zoneId}
</select>
<select id="countByRegionId" parameterType="Long" resultType="int">
select count(1) from prc_zone_detail d
inner join prc_zone z on z.zone_id = d.zone_id
where z.region_id = #{regionId}
</select>
<insert id="insertPrcZoneDetail" parameterType="PrcZoneDetail" useGeneratedKeys="true" keyProperty="detailId">
insert into prc_zone_detail (
<if test="zoneId != null">zone_id,</if>
<if test="postcode != null and postcode != ''">postcode,</if>
create_time
) values (
<if test="zoneId != null">#{zoneId},</if>
<if test="postcode != null and postcode != ''">#{postcode},</if>
sysdate()
)
</insert>
<insert id="insertPrcZoneDetailBatch">
insert into prc_zone_detail (zone_id, postcode, create_time) values
<foreach collection="list" item="item" separator=",">
(#{item.zoneId}, #{item.postcode}, sysdate())
</foreach>
</insert>
<update id="updatePrcZoneDetail" parameterType="PrcZoneDetail">
update prc_zone_detail
<set>
<if test="zoneId != null">zone_id = #{zoneId},</if>
<if test="postcode != null and postcode != ''">postcode = #{postcode},</if>
update_time = sysdate()
</set>
where detail_id = #{detailId}
</update>
<delete id="deletePrcZoneDetailByIds" parameterType="Long">
delete from prc_zone_detail where detail_id in
<foreach item="detailId" collection="array" open="(" separator="," close=")">
#{detailId}
</foreach>
</delete>
<delete id="deletePrcZoneDetailByZoneId" parameterType="Long">
delete from prc_zone_detail where zone_id = #{zoneId}
</delete>
<delete id="deletePrcZoneDetailByRegionId" parameterType="Long">
delete d from prc_zone_detail d
inner join prc_zone z on z.zone_id = d.zone_id
where z.region_id = #{regionId}
</delete>
</mapper>
@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.price.mapper.PrcZoneMapper">
<resultMap type="PrcZone" id="PrcZoneResult">
<id property="zoneId" column="zone_id" />
<result property="regionId" column="region_id" />
<result property="countryCode" column="country_code" />
<result property="zoneCode" column="zone_code" />
<result property="zoneName" column="zone_name" />
<result property="zoneSort" column="zone_sort" />
<result property="remark" column="remark" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
<result property="detailCount" column="detail_count" />
<result property="countryNameCn" column="country_name_cn" />
</resultMap>
<resultMap type="PrcZoneRegion" id="PrcZoneRegionResult">
<id property="regionId" column="region_id" />
<result property="countryNameCn" column="country_name_cn" />
<result property="countryNameEn" column="country_name_en" />
<result property="countryCode2" column="country_code_2" />
<result property="status" column="status" />
<result property="zoneCount" column="zone_count" />
<result property="detailCount" column="detail_count" />
</resultMap>
<sql id="selectPrcZoneVo">
select zone_id, region_id, country_code, zone_code, zone_name, zone_sort, remark, create_time, update_time
from prc_zone
</sql>
<select id="selectPrcZoneById" parameterType="Long" resultMap="PrcZoneResult">
<include refid="selectPrcZoneVo"/>
where zone_id = #{zoneId}
</select>
<select id="selectPrcZoneListByRegionId" parameterType="Long" resultMap="PrcZoneResult">
select z.zone_id, z.region_id, z.country_code, z.zone_code, z.zone_name, z.zone_sort, z.remark,
z.create_time, z.update_time,
(select count(1) from prc_zone_detail d where d.zone_id = z.zone_id) as detail_count
from prc_zone z
where z.region_id = #{regionId}
order by z.zone_sort asc, z.zone_id asc
</select>
<select id="selectPrcZoneList" parameterType="PrcZone" resultMap="PrcZoneResult">
select z.zone_id, z.region_id, z.country_code, z.zone_code, z.zone_name, z.zone_sort, z.remark,
z.create_time, z.update_time,
r.country_name_cn,
(select count(1) from prc_zone_detail d where d.zone_id = z.zone_id) as detail_count
from prc_zone z
left join bms_region r on r.region_id = z.region_id
<where>
<if test="regionId != null">
AND z.region_id = #{regionId}
</if>
<if test="countryCode != null and countryCode != ''">
AND z.country_code = #{countryCode}
</if>
<if test="zoneCode != null and zoneCode != ''">
AND z.zone_code like concat('%', #{zoneCode}, '%')
</if>
<if test="zoneName != null and zoneName != ''">
AND z.zone_name like concat('%', #{zoneName}, '%')
</if>
</where>
order by z.zone_sort asc, z.zone_id asc
</select>
<select id="selectZoneRegionList" parameterType="PrcZoneRegion" resultMap="PrcZoneRegionResult">
select r.region_id, r.country_name_cn, r.country_name_en, r.country_code_2, r.status,
count(distinct z.zone_id) as zone_count,
count(d.detail_id) as detail_count
from prc_zone z
inner join bms_region r on r.region_id = z.region_id
left join prc_zone_detail d on d.zone_id = z.zone_id
<where>
<if test="countryNameCn != null and countryNameCn != ''">
AND r.country_name_cn like concat('%', #{countryNameCn}, '%')
</if>
<if test="countryCode2 != null and countryCode2 != ''">
AND (r.country_code_2 = #{countryCode2} OR z.country_code = #{countryCode2})
</if>
<if test="status != null and status != ''">
AND r.status = #{status}
</if>
</where>
group by r.region_id, r.country_name_cn, r.country_name_en, r.country_code_2, r.status
order by r.country_name_cn asc, r.region_id asc
</select>
<select id="selectZoneRegionById" parameterType="Long" resultMap="PrcZoneRegionResult">
select r.region_id, r.country_name_cn, r.country_name_en, r.country_code_2, r.status,
(select count(1) from prc_zone z where z.region_id = r.region_id) as zone_count,
(select count(1) from prc_zone_detail d
inner join prc_zone z on z.zone_id = d.zone_id
where z.region_id = r.region_id) as detail_count
from bms_region r
where r.region_id = #{regionId}
</select>
<select id="countByRegionId" parameterType="Long" resultType="int">
select count(1) from prc_zone where region_id = #{regionId}
</select>
<insert id="insertPrcZone" parameterType="PrcZone" useGeneratedKeys="true" keyProperty="zoneId">
insert into prc_zone (
<if test="regionId != null">region_id,</if>
<if test="countryCode != null and countryCode != ''">country_code,</if>
<if test="zoneCode != null and zoneCode != ''">zone_code,</if>
<if test="zoneName != null">zone_name,</if>
<if test="zoneSort != null">zone_sort,</if>
<if test="remark != null">remark,</if>
create_time
) values (
<if test="regionId != null">#{regionId},</if>
<if test="countryCode != null and countryCode != ''">#{countryCode},</if>
<if test="zoneCode != null and zoneCode != ''">#{zoneCode},</if>
<if test="zoneName != null">#{zoneName},</if>
<if test="zoneSort != null">#{zoneSort},</if>
<if test="remark != null">#{remark},</if>
sysdate()
)
</insert>
<update id="updatePrcZone" parameterType="PrcZone">
update prc_zone
<set>
<if test="regionId != null">region_id = #{regionId},</if>
<if test="countryCode != null and countryCode != ''">country_code = #{countryCode},</if>
<if test="zoneCode != null and zoneCode != ''">zone_code = #{zoneCode},</if>
<if test="zoneName != null">zone_name = #{zoneName},</if>
<if test="zoneSort != null">zone_sort = #{zoneSort},</if>
<if test="remark != null">remark = #{remark},</if>
update_time = sysdate()
</set>
where zone_id = #{zoneId}
</update>
<delete id="deletePrcZoneByIds" parameterType="Long">
delete from prc_zone where zone_id in
<foreach item="zoneId" collection="array" open="(" separator="," close=")">
#{zoneId}
</foreach>
</delete>
<delete id="deletePrcZoneByRegionId" parameterType="Long">
delete from prc_zone where region_id = #{regionId}
</delete>
<delete id="deletePrcZoneByRegionIds" parameterType="Long">
delete from prc_zone where region_id in
<foreach item="regionId" collection="array" open="(" separator="," close=")">
#{regionId}
</foreach>
</delete>
</mapper>
@@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.price.mapper.XtdZoneCountryMapper">
<resultMap type="XtdZoneCountry" id="XtdZoneCountryResult">
<id property="zcId" column="zc_id" />
<result property="zdId" column="zd_id" />
<result property="countryCode" column="country_code" />
<result property="zcDividekind" column="zc_dividekind" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectXtdZoneCountryVo">
select zc_id, zd_id, country_code, zc_dividekind, create_time, update_time
from xtd_zonecountry
</sql>
<select id="selectXtdZoneCountryById" parameterType="Long" resultMap="XtdZoneCountryResult">
<include refid="selectXtdZoneCountryVo"/>
where zc_id = #{zcId}
</select>
<select id="selectXtdZoneCountryListByZdId" parameterType="Long" resultMap="XtdZoneCountryResult">
<include refid="selectXtdZoneCountryVo"/>
where zd_id = #{zdId}
order by zc_id asc
</select>
<select id="selectXtdZoneCountryList" parameterType="XtdZoneCountry" resultMap="XtdZoneCountryResult">
<include refid="selectXtdZoneCountryVo"/>
<where>
<if test="zdId != null">
AND zd_id = #{zdId}
</if>
<if test="countryCode != null and countryCode != ''">
AND country_code = #{countryCode}
</if>
<if test="zcDividekind != null and zcDividekind != ''">
AND zc_dividekind = #{zcDividekind}
</if>
</where>
order by zc_id asc
</select>
<select id="countByZdId" parameterType="Long" resultType="int">
select count(1) from xtd_zonecountry where zd_id = #{zdId}
</select>
<insert id="insertXtdZoneCountry" parameterType="XtdZoneCountry" useGeneratedKeys="true" keyProperty="zcId">
insert into xtd_zonecountry (
<if test="zdId != null">zd_id,</if>
<if test="countryCode != null and countryCode != ''">country_code,</if>
<if test="zcDividekind != null and zcDividekind != ''">zc_dividekind,</if>
create_time
) values (
<if test="zdId != null">#{zdId},</if>
<if test="countryCode != null and countryCode != ''">#{countryCode},</if>
<if test="zcDividekind != null and zcDividekind != ''">#{zcDividekind},</if>
sysdate()
)
</insert>
<update id="updateXtdZoneCountry" parameterType="XtdZoneCountry">
update xtd_zonecountry
<set>
<if test="zdId != null">zd_id = #{zdId},</if>
<if test="countryCode != null and countryCode != ''">country_code = #{countryCode},</if>
<if test="zcDividekind != null and zcDividekind != ''">zc_dividekind = #{zcDividekind},</if>
update_time = sysdate()
</set>
where zc_id = #{zcId}
</update>
<delete id="deleteXtdZoneCountryByIds" parameterType="Long">
delete from xtd_zonecountry where zc_id in
<foreach item="zcId" collection="array" open="(" separator="," close=")">
#{zcId}
</foreach>
</delete>
</mapper>
@@ -1,97 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.price.mapper.XtdZoneDivisionMapper">
<resultMap type="XtdZoneDivision" id="XtdZoneDivisionResult">
<id property="zdId" column="zd_id" />
<result property="zsId" column="zs_id" />
<result property="zdSort" column="zd_sort" />
<result property="zdCode" column="zd_code" />
<result property="znName" column="zn_name" />
<result property="znEname" column="zn_ename" />
<result property="znNote" column="zn_note" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
<result property="countryCount" column="country_count" />
</resultMap>
<sql id="selectXtdZoneDivisionVo">
select zd_id, zs_id, zd_sort, zd_code, zn_name, zn_ename, zn_note, create_time, update_time
from xtd_zone_division
</sql>
<select id="selectXtdZoneDivisionById" parameterType="Long" resultMap="XtdZoneDivisionResult">
<include refid="selectXtdZoneDivisionVo"/>
where zd_id = #{zdId}
</select>
<select id="selectXtdZoneDivisionListByZsId" parameterType="Long" resultMap="XtdZoneDivisionResult">
<include refid="selectXtdZoneDivisionVo"/>
where zs_id = #{zsId}
order by zd_sort asc, zd_id asc
</select>
<select id="selectXtdZoneDivisionList" parameterType="XtdZoneDivision" resultMap="XtdZoneDivisionResult">
<include refid="selectXtdZoneDivisionVo"/>
<where>
<if test="zsId != null">
AND zs_id = #{zsId}
</if>
<if test="zdCode != null and zdCode != ''">
AND zd_code like concat('%', #{zdCode}, '%')
</if>
<if test="znName != null and znName != ''">
AND zn_name like concat('%', #{znName}, '%')
</if>
</where>
order by zd_sort asc, zd_id asc
</select>
<select id="countByZsId" parameterType="Long" resultType="int">
select count(1) from xtd_zone_division where zs_id = #{zsId}
</select>
<insert id="insertXtdZoneDivision" parameterType="XtdZoneDivision" useGeneratedKeys="true" keyProperty="zdId">
insert into xtd_zone_division (
<if test="zsId != null">zs_id,</if>
<if test="zdSort != null">zd_sort,</if>
<if test="zdCode != null">zd_code,</if>
<if test="znName != null">zn_name,</if>
<if test="znEname != null">zn_ename,</if>
<if test="znNote != null">zn_note,</if>
create_time
) values (
<if test="zsId != null">#{zsId},</if>
<if test="zdSort != null">#{zdSort},</if>
<if test="zdCode != null">#{zdCode},</if>
<if test="znName != null">#{znName},</if>
<if test="znEname != null">#{znEname},</if>
<if test="znNote != null">#{znNote},</if>
sysdate()
)
</insert>
<update id="updateXtdZoneDivision" parameterType="XtdZoneDivision">
update xtd_zone_division
<set>
<if test="zsId != null">zs_id = #{zsId},</if>
<if test="zdSort != null">zd_sort = #{zdSort},</if>
<if test="zdCode != null">zd_code = #{zdCode},</if>
<if test="znName != null">zn_name = #{znName},</if>
<if test="znEname != null">zn_ename = #{znEname},</if>
<if test="znNote != null">zn_note = #{znNote},</if>
update_time = sysdate()
</set>
where zd_id = #{zdId}
</update>
<delete id="deleteXtdZoneDivisionByIds" parameterType="Long">
delete from xtd_zone_division where zd_id in
<foreach item="zdId" collection="array" open="(" separator="," close=")">
#{zdId}
</foreach>
</delete>
</mapper>
@@ -1,99 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.price.mapper.XtdZoneSchemeMapper">
<resultMap type="XtdZoneScheme" id="XtdZoneSchemeResult">
<id property="zsId" column="zs_id" />
<result property="zsName" column="zs_name" />
<result property="ssCode" column="ss_code" />
<result property="pgCode" column="pg_code" />
<result property="snId" column="sn_id" />
<result property="zsNote" column="zs_note" />
<result property="tmsId" column="tms_id" />
<result property="createBy" column="created_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="updated_by" />
<result property="updateTime" column="update_time" />
<result property="divisionCount" column="division_count" />
</resultMap>
<sql id="selectXtdZoneSchemeVo">
select zs_id, zs_name, ss_code, pg_code, sn_id, zs_note, tms_id,
created_by, create_time, updated_by, update_time
from xtd_zone_scheme
</sql>
<select id="selectXtdZoneSchemeById" parameterType="Long" resultMap="XtdZoneSchemeResult">
<include refid="selectXtdZoneSchemeVo"/>
where zs_id = #{zsId}
</select>
<select id="selectXtdZoneSchemeList" parameterType="XtdZoneScheme" resultMap="XtdZoneSchemeResult">
<include refid="selectXtdZoneSchemeVo"/>
<where>
<if test="zsName != null and zsName != ''">
AND zs_name like concat('%', #{zsName}, '%')
</if>
<if test="ssCode != null and ssCode != ''">
AND ss_code = #{ssCode}
</if>
<if test="pgCode != null and pgCode != ''">
AND pg_code = #{pgCode}
</if>
<if test="snId != null">
AND sn_id = #{snId}
</if>
<if test="tmsId != null">
AND tms_id = #{tmsId}
</if>
</where>
order by zs_id desc
</select>
<insert id="insertXtdZoneScheme" parameterType="XtdZoneScheme" useGeneratedKeys="true" keyProperty="zsId">
insert into xtd_zone_scheme (
<if test="zsName != null and zsName != ''">zs_name,</if>
<if test="ssCode != null and ssCode != ''">ss_code,</if>
<if test="pgCode != null">pg_code,</if>
<if test="snId != null">sn_id,</if>
<if test="zsNote != null">zs_note,</if>
<if test="tmsId != null">tms_id,</if>
<if test="createBy != null and createBy != ''">created_by,</if>
create_time
) values (
<if test="zsName != null and zsName != ''">#{zsName},</if>
<if test="ssCode != null and ssCode != ''">#{ssCode},</if>
<if test="pgCode != null">#{pgCode},</if>
<if test="snId != null">#{snId},</if>
<if test="zsNote != null">#{zsNote},</if>
<if test="tmsId != null">#{tmsId},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate()
)
</insert>
<update id="updateXtdZoneScheme" parameterType="XtdZoneScheme">
update xtd_zone_scheme
<set>
<if test="zsName != null and zsName != ''">zs_name = #{zsName},</if>
<if test="ssCode != null and ssCode != ''">ss_code = #{ssCode},</if>
<if test="pgCode != null">pg_code = #{pgCode},</if>
<if test="snId != null">sn_id = #{snId},</if>
<if test="zsNote != null">zs_note = #{zsNote},</if>
<if test="tmsId != null">tms_id = #{tmsId},</if>
<if test="updateBy != null and updateBy != ''">updated_by = #{updateBy},</if>
update_time = sysdate()
</set>
where zs_id = #{zsId}
</update>
<delete id="deleteXtdZoneSchemeByIds" parameterType="Long">
delete from xtd_zone_scheme where zs_id in
<foreach item="zsId" collection="array" open="(" separator="," close=")">
#{zsId}
</foreach>
</delete>
</mapper>
+43
View File
@@ -0,0 +1,43 @@
-- ----------------------------
-- Zone management: bms_region -> prc_zone -> prc_zone_detail
-- Country master is bms_region (no prc_zone_country)
-- charset: utf8mb4
-- ----------------------------
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS prc_zone_detail;
DROP TABLE IF EXISTS prc_zone;
DROP TABLE IF EXISTS prc_zone_country;
DROP TABLE IF EXISTS xtd_zonecountry;
DROP TABLE IF EXISTS xtd_zone_division;
DROP TABLE IF EXISTS xtd_zone_scheme;
SET FOREIGN_KEY_CHECKS = 1;
CREATE TABLE IF NOT EXISTS prc_zone (
zone_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'zone id',
region_id BIGINT(20) NOT NULL COMMENT 'bms_region.region_id',
country_code VARCHAR(10) NOT NULL COMMENT 'ISO2 country code from bms_region',
zone_code VARCHAR(50) NOT NULL COMMENT 'zone code e.g. 1',
zone_name VARCHAR(100) DEFAULT NULL COMMENT 'display name e.g. AU(1)',
zone_sort INT(11) DEFAULT 0 COMMENT 'sort',
remark VARCHAR(500) DEFAULT NULL COMMENT 'remark',
create_time DATETIME DEFAULT NULL COMMENT 'created at',
update_time DATETIME DEFAULT NULL COMMENT 'updated at',
PRIMARY KEY (zone_id),
UNIQUE KEY uk_zone_region_code (region_id, zone_code),
INDEX idx_zone_region_id (region_id),
INDEX idx_zone_country_code (country_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='zone under bms_region';
CREATE TABLE IF NOT EXISTS prc_zone_detail (
detail_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'detail id',
zone_id BIGINT(20) NOT NULL COMMENT 'zone id',
postcode VARCHAR(32) NOT NULL COMMENT 'postcode',
create_time DATETIME DEFAULT NULL COMMENT 'created at',
update_time DATETIME DEFAULT NULL COMMENT 'updated at',
PRIMARY KEY (detail_id),
INDEX idx_zd_zone_id (zone_id),
INDEX idx_zd_postcode (postcode),
UNIQUE KEY uk_zd_zone_postcode (zone_id, postcode),
CONSTRAINT fk_zd_zone FOREIGN KEY (zone_id) REFERENCES prc_zone (zone_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='zone postcode detail';
@@ -0,0 +1,16 @@
-- Add country_code to existing prc_zone (skip if re-running full zone_country.sql)
-- charset: utf8mb4
ALTER TABLE prc_zone
ADD COLUMN country_code VARCHAR(10) NULL COMMENT 'ISO2 country code from bms_region' AFTER region_id;
UPDATE prc_zone z
INNER JOIN bms_region r ON r.region_id = z.region_id
SET z.country_code = r.country_code_2
WHERE z.country_code IS NULL OR z.country_code = '';
ALTER TABLE prc_zone
MODIFY COLUMN country_code VARCHAR(10) NOT NULL COMMENT 'ISO2 country code from bms_region';
ALTER TABLE prc_zone
ADD INDEX idx_zone_country_code (country_code);
+2 -44
View File
@@ -4,50 +4,8 @@
-- menu_id: 2100-2123 (2115-2123 reserved)
-- ----------------------------
CREATE TABLE IF NOT EXISTS xtd_zone_scheme (
zs_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'zone scheme id',
zs_name VARCHAR(100) NOT NULL COMMENT 'scheme name',
ss_code VARCHAR(20) NOT NULL DEFAULT 'on' COMMENT 'status on/off',
pg_code VARCHAR(50) DEFAULT NULL COMMENT 'product group code',
sn_id BIGINT(20) DEFAULT NULL COMMENT 'service channel id',
zs_note VARCHAR(500) DEFAULT NULL COMMENT 'note',
tms_id BIGINT(20) DEFAULT NULL COMMENT 'tenant id',
created_by VARCHAR(64) DEFAULT '' COMMENT 'created by',
create_time DATETIME DEFAULT NULL COMMENT 'created at',
updated_by VARCHAR(64) DEFAULT '' COMMENT 'updated by',
update_time DATETIME DEFAULT NULL COMMENT 'updated at',
PRIMARY KEY (zs_id),
INDEX idx_zs_ss_code (ss_code),
INDEX idx_zs_tms_id (tms_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='zone scheme';
CREATE TABLE IF NOT EXISTS xtd_zone_division (
zd_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'division id globally unique',
zs_id BIGINT(20) NOT NULL COMMENT 'scheme id',
zd_sort INT(11) DEFAULT 0 COMMENT 'sort',
zd_code VARCHAR(50) DEFAULT NULL COMMENT 'division code',
zn_name VARCHAR(100) DEFAULT NULL COMMENT 'name',
zn_ename VARCHAR(100) DEFAULT NULL COMMENT 'english name',
zn_note VARCHAR(500) DEFAULT NULL COMMENT 'note',
create_time DATETIME DEFAULT NULL COMMENT 'created at',
update_time DATETIME DEFAULT NULL COMMENT 'updated at',
PRIMARY KEY (zd_id),
INDEX idx_zd_zs_id (zs_id),
CONSTRAINT fk_zd_zs FOREIGN KEY (zs_id) REFERENCES xtd_zone_scheme (zs_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='zone division';
CREATE TABLE IF NOT EXISTS xtd_zonecountry (
zc_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'zone country id',
zd_id BIGINT(20) NOT NULL COMMENT 'division id',
country_code CHAR(2) NOT NULL COMMENT 'ISO2 country code',
zc_dividekind VARCHAR(10) NOT NULL DEFAULT 'C' COMMENT 'divide kind default C',
create_time DATETIME DEFAULT NULL COMMENT 'created at',
update_time DATETIME DEFAULT NULL COMMENT 'updated at',
PRIMARY KEY (zc_id),
INDEX idx_zc_zd_id (zd_id),
INDEX idx_zc_country (country_code),
CONSTRAINT fk_zc_zd FOREIGN KEY (zd_id) REFERENCES xtd_zone_division (zd_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='zone country';
-- Zone tables moved to zone_country.sql (prc_zone_country / prc_zone / prc_zone_detail)
-- Run: bms-back/sql/price/zone_country.sql
CREATE TABLE IF NOT EXISTS prc_weight_section_template (
wst_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'weight template id',