feat(wcs): 完成WCS模块多维度优化

- 统一Excel字段展示格式,简化表头并配置字典转换
- 新增实时任务明细下拉查询接口,避免分页全量问题
- 为核心业务service添加缓存注解,优化查询性能
- 完善MyBatis跨库用户表配置,支持动态schema
- 优化各业务service的校验逻辑与代码注释
main
zch 4 weeks ago
parent 7e2bf493dd
commit 365731af39

@ -8,31 +8,103 @@ import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* WCS MyBatis
* WCS MyBatis
*
* <h3></h3>
* <p>hw-wcs 使 slave wcs_core create_byupdate_by
* bigint ID"创建人/更新人"
* master sys_user </p>
*
* <p> Mapper XML slave SQL
* <ol>
* <li> schema wcs_core_ruoyi prod_ruoyi</li>
* <li> SQL </li>
* </ol>
* </p>
*
* <h3></h3>
* <p> Spring schema.table table
* MyBatis {@code ${wcsSysUserTable}}
* Mapper XML MyBatis
* </p>
*
* <h3>使Mapper XML</h3>
* <pre>{@code
* left join ${wcsSysUserTable} cu on t.create_by = cu.user_id
* left join ${wcsSysUserTable} uu on t.update_by = uu.user_id
* }</pre>
*
* @author zch
*/
@Configuration
@Configuration // 标记为 Spring 配置类,容器启动时自动扫描并处理其中的 @Bean 方法
public class WcsMybatisConfig {
/**
* MyBatis Mapper XML ${wcsSysUserTable}
* wcs_core_ruoyi.sys_user
*/
private static final String SYS_USER_TABLE_VARIABLE = "wcsSysUserTable";
/**
* "table" "schema.table"
* - [A-Za-z0-9_]+ schema 线
* - (\\.[A-Za-z0-9_]+)? ".table" schema.table
*
* <p>sys_userwcs_core_ruoyi.sys_user</p>
* <p>sys-user线DROP TABLE sys_user/</p>
*/
private static final String TABLE_NAME_PATTERN = "[A-Za-z0-9_]+(\\.[A-Za-z0-9_]+)?";
/**
* MyBatis ConfigurationCustomizer
*
* <p>Spring MyBatis-Plus ConfigurationCustomizer Bean
* Configuration </p>
*
* @param systemUserTable
* ${wcs.system-user-table:}
* - wcs.system-user-table
* - wcs_core_ruoyi.sys_user
* - WCS_SYSTEM_USER_TABLE
* application-dev.yml ${WCS_SYSTEM_USER_TABLE:...}
* @return ConfigurationCustomizer LambdaMyBatis
*/
@Bean
public ConfigurationCustomizer wcsSqlVariableCustomizer(
@Value("${wcs.system-user-table:wcs_core_ruoyi.sys_user}") String systemUserTable) {
// 启动期立即校验,不合法则直接抛异常阻止应用启动,防止非法表名进入 SQL
String validatedSystemUserTable = validateTableName(systemUserTable);
// 返回 LambdaMyBatis Configuration 对象创建完毕后执行
return configuration -> {
// 获取 MyBatis 已有的全局变量集合(可能为 null
Properties variables = configuration.getVariables();
if (variables == null) {
// 首次访问时初始化,避免 NPE
variables = new Properties();
configuration.setVariables(variables);
}
// 将校验后的用户表全名写入 MyBatis 全局变量:
// key = "wcsSysUserTable"
// value = "wcs_core_ruoyi.sys_user"(或其他通过校验的值)
// 之后 Mapper XML 中所有 ${wcsSysUserTable} 占位符都会被替换为此值
// 用户表全名交给环境配置避免从库XML写死主库schema后在生产库名变化时直接失效。
variables.setProperty(SYS_USER_TABLE_VARIABLE, validatedSystemUserTable);
};
}
/**
* 线 schema
*
* <p> MyBatis ${} SQL
* "非参数化"
* SQL fail-fast</p>
*
* @param tableName
* @return
* @throws IllegalArgumentException null
*/
private String validateTableName(String tableName) {
if (tableName == null || !tableName.matches(TABLE_NAME_PATTERN)) {
// 该值会进入MyBatis ${} 表名占位启动期失败比运行期暴露SQL注入面更稳妥。
@ -40,4 +112,5 @@ public class WcsMybatisConfig {
}
return tableName;
}
}

@ -45,6 +45,16 @@ public class LiveTaskDetailController extends BaseController {
return liveTaskDetailService.queryPageList(bo, pageQuery);
}
/**
*
*/
@SaCheckPermission("wcs:taskDetail:query")
@GetMapping("/getTaskDetailList")
public R<List<LiveTaskDetailVo>> getTaskDetailList(LiveTaskDetailBo bo) {
// 表单下拉使用非分页主数据,避免 pageSize 伪全量在明细数量增长后漏选。
return R.ok(liveTaskDetailService.queryList(bo));
}
/**
*
*/

@ -67,7 +67,7 @@ public class BaseDeviceHostVo implements Serializable {
/**
* 1-0-
*/
@ExcelProperty(value = "是否标识1-是0-否", converter = ExcelDictConvert.class)
@ExcelProperty(value = "是否标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_is_flag")
private Integer isFlag;

@ -4,6 +4,8 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.wcs.domain.BaseDeviceInfo;
import java.io.Serial;
@ -53,19 +55,22 @@ public class BaseDeviceInfoVo implements Serializable {
/**
* 0-线1-AGV2-
*/
@ExcelProperty(value = "设备类型0-输送线1-AGV2-提升机")
@ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_device_type")
private Integer deviceType;
/**
* 0-1-2-
*/
@ExcelProperty(value = "设备状态0-正常1-在忙2-异常")
@ExcelProperty(value = "设备状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_device_status")
private Integer deviceStatus;
/**
* 1-0-
*/
@ExcelProperty(value = "是否标识1-是0-否")
@ExcelProperty(value = "是否标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_is_flag")
private Integer isFlag;
/**

@ -67,7 +67,8 @@ public class BaseDeviceParamVo implements Serializable {
/**
* 1-2-0-
*/
@ExcelProperty(value = "操作类型1-只读2-只写0-默认读写")
@ExcelProperty(value = "操作类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_operation_type")
private Integer operationType;
/**
@ -80,7 +81,8 @@ public class BaseDeviceParamVo implements Serializable {
/**
* 1-0-
*/
@ExcelProperty(value = "是否标识1-是0-否")
@ExcelProperty(value = "是否标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_is_flag")
private Integer isFlag;
/**

@ -103,14 +103,14 @@ public class BaseLocationInfoVo implements Serializable {
/**
* ;0-使;1-使;2-;3-
*/
@ExcelProperty(value = "库位状态;0-未使用;1-已使用;2-锁库;3-异常", converter = ExcelDictConvert.class)
@ExcelProperty(value = "库位状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_location_status")
private Integer locationStatus;
/**
* 1-0-
*/
@ExcelProperty(value = "是否标识1-是0-否", converter = ExcelDictConvert.class)
@ExcelProperty(value = "是否标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_is_flag")
private Integer isFlag;

@ -73,7 +73,7 @@ public class BaseMaterialInfoVo implements Serializable {
/**
* 1-0-
*/
@ExcelProperty(value = "是否标识1-是0-否", converter = ExcelDictConvert.class)
@ExcelProperty(value = "是否标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_is_flag")
private Integer isFlag;

@ -55,7 +55,7 @@ public class BasePathDetailsVo implements Serializable {
/**
* 1-0-
*/
@ExcelProperty(value = "是否标识1-是0-否", converter = ExcelDictConvert.class)
@ExcelProperty(value = "是否标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_is_flag")
private Integer isFlag;

@ -50,7 +50,7 @@ public class BasePathInfoVo implements Serializable {
/**
* 1-0-
*/
@ExcelProperty(value = "是否标识1-是0-否", converter = ExcelDictConvert.class)
@ExcelProperty(value = "是否标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_is_flag")
private Integer isFlag;

@ -49,7 +49,7 @@ public class BaseStoreInfoVo implements Serializable {
/**
* 1-0-
*/
@ExcelProperty(value = "是否标识1-是0-否", converter = ExcelDictConvert.class)
@ExcelProperty(value = "是否标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wcs_is_flag")
private Integer isFlag;

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.bo.BaseDeviceHostBo;
import org.dromara.wcs.domain.vo.BaseDeviceHostVo;
@ -44,6 +46,7 @@ public class BaseDeviceHostServiceImpl implements IBaseDeviceHostService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public BaseDeviceHostVo queryById(Long objId){
return baseMapper.selectCustomBaseDeviceHostVoById(objId);
}
@ -142,10 +145,14 @@ public class BaseDeviceHostServiceImpl implements IBaseDeviceHostService {
@Override
@DSTransactional
public Boolean insertByBo(BaseDeviceHostBo bo) {
// 将 BO 对象转换为实体对象
BaseDeviceHost add = MapstructUtils.convert(bo, BaseDeviceHost.class);
// 保存前进行数据校验
validEntityBeforeSave(add);
// 执行插入操作
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
// 插入成功后将生成的主键回填到 BO 对象
bo.setObjId(add.getObjId());
}
return flag;
@ -158,10 +165,14 @@ public class BaseDeviceHostServiceImpl implements IBaseDeviceHostService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(BaseDeviceHostBo bo) {
// 将 BO 对象转换为实体对象
BaseDeviceHost update = MapstructUtils.convert(bo, BaseDeviceHost.class);
// 保存前进行数据校验
validEntityBeforeSave(update);
// 执行更新操作
return baseMapper.updateById(update) > 0;
}
@ -169,15 +180,19 @@ public class BaseDeviceHostServiceImpl implements IBaseDeviceHostService {
*
*/
private void validEntityBeforeSave(BaseDeviceHost entity){
// 校验实体对象和主机编号
if (entity == null || StringUtils.isBlank(entity.getHostCode())) {
throw new ServiceException("主机编号不能为空");
}
// 查询相同主机编号的数量,排除当前记录(更新场景)
Long sameHostCodeCount = baseMapper.selectCount(Wrappers.<BaseDeviceHost>lambdaQuery()
.eq(BaseDeviceHost::getHostCode, entity.getHostCode())
.ne(entity.getObjId() != null, BaseDeviceHost::getObjId, entity.getObjId()));
// 校验主机编号唯一性
if (sameHostCodeCount > 0) {
throw new ServiceException("主机编号已存在,请更换主机编号");
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
// 主数据新增默认启用,避免下拉选择时新建记录因空标识被业务过滤。
entity.setIsFlag(1);
@ -192,6 +207,7 @@ public class BaseDeviceHostServiceImpl implements IBaseDeviceHostService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.bo.BaseDeviceInfoBo;
import org.dromara.wcs.domain.vo.BaseDeviceInfoVo;
@ -44,6 +46,7 @@ public class BaseDeviceInfoServiceImpl implements IBaseDeviceInfoService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public BaseDeviceInfoVo queryById(Long objId){
return baseMapper.selectCustomBaseDeviceInfoVoById(objId);
}
@ -158,6 +161,7 @@ public class BaseDeviceInfoServiceImpl implements IBaseDeviceInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(BaseDeviceInfoBo bo) {
BaseDeviceInfo update = MapstructUtils.convert(bo, BaseDeviceInfo.class);
@ -169,15 +173,19 @@ public class BaseDeviceInfoServiceImpl implements IBaseDeviceInfoService {
*
*/
private void validEntityBeforeSave(BaseDeviceInfo entity){
// 校验实体对象和设备编号
if (entity == null || StringUtils.isBlank(entity.getDeviceCode())) {
throw new ServiceException("设备编号不能为空");
}
// 查询相同设备编号的数量,排除当前记录(更新场景)
Long sameDeviceCodeCount = baseMapper.selectCount(Wrappers.<BaseDeviceInfo>lambdaQuery()
.eq(BaseDeviceInfo::getDeviceCode, entity.getDeviceCode())
.ne(entity.getObjId() != null, BaseDeviceInfo::getObjId, entity.getObjId()));
// 校验设备编号唯一性
if (sameDeviceCodeCount > 0) {
throw new ServiceException("设备编号已存在,请更换设备编号");
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
// 设备主数据默认有效,便于调度侧只按启用设备组装可选范围。
entity.setIsFlag(1);
@ -192,6 +200,7 @@ public class BaseDeviceInfoServiceImpl implements IBaseDeviceInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.bo.BaseDeviceParamBo;
import org.dromara.wcs.domain.vo.BaseDeviceParamVo;
@ -44,6 +46,7 @@ public class BaseDeviceParamServiceImpl implements IBaseDeviceParamService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public BaseDeviceParamVo queryById(Long objId){
return baseMapper.selectCustomBaseDeviceParamVoById(objId);
}
@ -160,6 +163,7 @@ public class BaseDeviceParamServiceImpl implements IBaseDeviceParamService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(BaseDeviceParamBo bo) {
BaseDeviceParam update = MapstructUtils.convert(bo, BaseDeviceParam.class);
@ -171,15 +175,19 @@ public class BaseDeviceParamServiceImpl implements IBaseDeviceParamService {
*
*/
private void validEntityBeforeSave(BaseDeviceParam entity){
// 校验实体对象和参数编号
if (entity == null || StringUtils.isBlank(entity.getParamCode())) {
throw new ServiceException("参数编号不能为空");
}
// 查询相同参数编号的数量,排除当前记录(更新场景)
Long sameParamCodeCount = baseMapper.selectCount(Wrappers.<BaseDeviceParam>lambdaQuery()
.eq(BaseDeviceParam::getParamCode, entity.getParamCode())
.ne(entity.getObjId() != null, BaseDeviceParam::getObjId, entity.getObjId()));
// 校验参数编号唯一性
if (sameParamCodeCount > 0) {
throw new ServiceException("参数编号已存在,请更换参数编号");
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
// 参数默认启用,避免设备通讯配置保存后却不参与后续参数装载。
entity.setIsFlag(1);
@ -194,6 +202,7 @@ public class BaseDeviceParamServiceImpl implements IBaseDeviceParamService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.bo.BaseLocationInfoBo;
import org.dromara.wcs.domain.vo.BaseLocationInfoVo;
@ -44,6 +46,7 @@ public class BaseLocationInfoServiceImpl implements IBaseLocationInfoService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public BaseLocationInfoVo queryById(Long objId){
return baseMapper.selectCustomBaseLocationInfoVoById(objId);
}
@ -165,6 +168,7 @@ public class BaseLocationInfoServiceImpl implements IBaseLocationInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(BaseLocationInfoBo bo) {
BaseLocationInfo update = MapstructUtils.convert(bo, BaseLocationInfo.class);
@ -176,19 +180,24 @@ public class BaseLocationInfoServiceImpl implements IBaseLocationInfoService {
*
*/
private void validEntityBeforeSave(BaseLocationInfo entity){
// 校验实体对象和库位编号
if (entity == null || StringUtils.isBlank(entity.getLocationCode())) {
throw new ServiceException("库位编号不能为空");
}
// 查询相同库位编号的数量,排除当前记录(更新场景)
Long sameLocationCodeCount = baseMapper.selectCount(Wrappers.<BaseLocationInfo>lambdaQuery()
.eq(BaseLocationInfo::getLocationCode, entity.getLocationCode())
.ne(entity.getObjId() != null, BaseLocationInfo::getObjId, entity.getObjId()));
// 校验库位编号唯一性
if (sameLocationCodeCount > 0) {
throw new ServiceException("库位编号已存在,请更换库位编号");
}
// 设置默认库位状态
if (entity.getLocationStatus() == null) {
// 新库位默认未使用,避免空状态影响库位看板与分配策略判断。
entity.setLocationStatus(0);
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
entity.setIsFlag(1);
}
@ -202,6 +211,7 @@ public class BaseLocationInfoServiceImpl implements IBaseLocationInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.bo.BaseMaterialInfoBo;
import org.dromara.wcs.domain.vo.BaseMaterialInfoVo;
@ -44,6 +46,7 @@ public class BaseMaterialInfoServiceImpl implements IBaseMaterialInfoService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public BaseMaterialInfoVo queryById(Long objId){
return baseMapper.selectCustomBaseMaterialInfoVoById(objId);
}
@ -159,10 +162,14 @@ public class BaseMaterialInfoServiceImpl implements IBaseMaterialInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(BaseMaterialInfoBo bo) {
// 将 BO 对象转换为实体对象
BaseMaterialInfo update = MapstructUtils.convert(bo, BaseMaterialInfo.class);
// 保存前进行数据校验
validEntityBeforeSave(update);
// 执行更新操作
return baseMapper.updateById(update) > 0;
}
@ -170,15 +177,19 @@ public class BaseMaterialInfoServiceImpl implements IBaseMaterialInfoService {
*
*/
private void validEntityBeforeSave(BaseMaterialInfo entity){
// 校验实体对象和物料编号
if (entity == null || StringUtils.isBlank(entity.getMaterialCode())) {
throw new ServiceException("物料编号不能为空");
}
// 查询相同物料编号的数量,排除当前记录(更新场景)
Long sameMaterialCodeCount = baseMapper.selectCount(Wrappers.<BaseMaterialInfo>lambdaQuery()
.eq(BaseMaterialInfo::getMaterialCode, entity.getMaterialCode())
.ne(entity.getObjId() != null, BaseMaterialInfo::getObjId, entity.getObjId()));
// 校验物料编号唯一性
if (sameMaterialCodeCount > 0) {
throw new ServiceException("物料编号已存在,请更换物料编号");
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
// 物料主数据默认有效,确保任务和库位表单可直接引用新建物料。
entity.setIsFlag(1);
@ -193,6 +204,7 @@ public class BaseMaterialInfoServiceImpl implements IBaseMaterialInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.bo.BasePathDetailsBo;
import org.dromara.wcs.domain.vo.BasePathDetailsVo;
@ -44,6 +46,7 @@ public class BasePathDetailsServiceImpl implements IBasePathDetailsService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public BasePathDetailsVo queryById(Long objId){
return baseMapper.selectCustomBasePathDetailsVoById(objId);
}
@ -156,10 +159,14 @@ public class BasePathDetailsServiceImpl implements IBasePathDetailsService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(BasePathDetailsBo bo) {
// 将 BO 对象转换为实体对象
BasePathDetails update = MapstructUtils.convert(bo, BasePathDetails.class);
// 保存前进行数据校验
validEntityBeforeSave(update);
// 执行更新操作
return baseMapper.updateById(update) > 0;
}
@ -167,9 +174,11 @@ public class BasePathDetailsServiceImpl implements IBasePathDetailsService {
*
*/
private void validEntityBeforeSave(BasePathDetails entity){
// 校验实体对象和路径编号
if (entity == null || StringUtils.isBlank(entity.getPathCode())) {
throw new ServiceException("路径编号不能为空");
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
entity.setIsFlag(1);
}
@ -183,11 +192,13 @@ public class BasePathDetailsServiceImpl implements IBasePathDetailsService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
// TODO: 做一些业务上的校验,判断是否需要校验
}
// 执行批量删除操作
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -11,6 +11,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.wcs.domain.BasePathDetails;
@ -50,6 +52,7 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public BasePathInfoVo queryById(Long objId){
BasePathInfoVo vo = baseMapper.selectCustomBasePathInfoVoById(objId);
if (vo != null) {
@ -151,11 +154,16 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
@Override
@DSTransactional
public Boolean insertByBo(BasePathInfoBo bo) {
// 将 BO 对象转换为实体对象
BasePathInfo add = MapstructUtils.convert(bo, BasePathInfo.class);
// 保存前进行数据校验
validEntityBeforeSave(add);
// 执行插入操作
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
// 插入成功后将生成的主键回填到 BO 对象
bo.setObjId(add.getObjId());
// 保存路径明细
saveDetails(bo);
}
return flag;
@ -168,18 +176,24 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(BasePathInfoBo bo) {
// 查询原记录
BasePathInfo old = baseMapper.selectById(bo.getObjId());
if (old == null) {
throw new ServiceException("路径信息不存在,无法修改");
}
// 将 BO 对象转换为实体对象
BasePathInfo update = MapstructUtils.convert(bo, BasePathInfo.class);
// 保存前进行数据校验
validEntityBeforeSave(update);
// 路径编号是子表外键,先按旧编号删除旧明细,避免 ON UPDATE CASCADE 后删不到旧数据。
deleteDetailsByPathCode(old.getPathCode());
// 执行更新操作
boolean flag = baseMapper.updateById(update) > 0;
if (flag) {
// 更新成功后保存路径明细
saveDetails(bo);
}
return flag;
@ -189,15 +203,19 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
*
*/
private void validEntityBeforeSave(BasePathInfo entity){
// 校验实体对象和路径编号
if (entity == null || StringUtils.isBlank(entity.getPathCode())) {
throw new ServiceException("路径编号不能为空");
}
// 查询相同路径编号的数量,排除当前记录(更新场景)
Long samePathCodeCount = baseMapper.selectCount(Wrappers.<BasePathInfo>lambdaQuery()
.eq(BasePathInfo::getPathCode, entity.getPathCode())
.ne(entity.getObjId() != null, BasePathInfo::getObjId, entity.getObjId()));
// 校验路径编号唯一性
if (samePathCodeCount > 0) {
throw new ServiceException("路径编号已存在,请更换路径编号");
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
// 路径默认有效,避免新建后任务下拉因状态为空无法选择。
entity.setIsFlag(1);
@ -208,19 +226,24 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
*
*/
private void saveDetails(BasePathInfoBo bo) {
// 获取路径明细列表
List<BasePathDetailsBo> details = bo.getDetails();
if (details == null || details.isEmpty()) {
return;
}
// 遍历明细列表并保存
for (BasePathDetailsBo detailBo : details) {
// 将明细 BO 转换为实体对象
BasePathDetails detail = MapstructUtils.convert(detailBo, BasePathDetails.class);
// 主表整体保存时统一替换子表,清空明细主键避免误更新历史明细。
detail.setObjId(null);
// 明细始终跟随当前主表路径编号,避免用户改编号后子表仍挂在旧路径上。
detail.setPathCode(bo.getPathCode());
// 设置默认启用标识
if (detail.getIsFlag() == null) {
detail.setIsFlag(1);
}
// 插入明细记录
basePathDetailsMapper.insert(detail);
}
}
@ -229,9 +252,11 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
*
*/
private void deleteDetailsByPathCode(String pathCode) {
// 路径编号为空时直接返回
if (StringUtils.isBlank(pathCode)) {
return;
}
// 根据路径编号删除明细
basePathDetailsMapper.delete(Wrappers.<BasePathDetails>lambdaQuery()
.eq(BasePathDetails::getPathCode, pathCode));
}
@ -240,9 +265,11 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
*
*/
private void deleteDetailsByPathCodes(Collection<String> pathCodes) {
// 路径编号集合为空时直接返回
if (pathCodes == null || pathCodes.isEmpty()) {
return;
}
// 根据路径编号集合批量删除明细
basePathDetailsMapper.delete(Wrappers.<BasePathDetails>lambdaQuery()
.in(BasePathDetails::getPathCode, pathCodes));
}
@ -251,21 +278,26 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
* XML collection N+1
*/
private void attachDetails(List<BasePathInfoVo> pathInfoList) {
// 路径信息列表为空时直接返回
if (pathInfoList == null || pathInfoList.isEmpty()) {
return;
}
// 提取所有路径编号并去重
List<String> pathCodes = pathInfoList.stream()
.map(BasePathInfoVo::getPathCode)
.filter(StringUtils::isNotBlank)
.distinct()
.toList();
// 路径编号为空时设置空明细列表
if (pathCodes.isEmpty()) {
pathInfoList.forEach(item -> item.setDetails(List.of()));
return;
}
// 批量查询明细并按路径编号分组
Map<String, List<BasePathDetailsVo>> detailMap = basePathDetailsMapper.selectCustomBasePathDetailsVoByPathCodes(pathCodes)
.stream()
.collect(Collectors.groupingBy(BasePathDetailsVo::getPathCode));
// 将明细挂载到对应的路径信息
pathInfoList.forEach(item -> item.setDetails(detailMap.getOrDefault(item.getPathCode(), List.of())));
}
@ -277,21 +309,25 @@ public class BasePathInfoServiceImpl implements IBasePathInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
// 主键集合为空时直接返回
if (ids == null || ids.isEmpty()) {
// 删除入口明确要求主键集合空集合直接返回避免拼出无意义SQL。
return false;
}
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
// TODO: 做一些业务上的校验,判断是否需要校验
}
// 根据主键集合查询路径编号
List<String> pathCodes = baseMapper.selectPathCodesByIds(ids).stream()
.filter(StringUtils::isNotBlank)
.distinct()
.toList();
// 主子表删除放在同一个本地多数据源事务里,避免只删主表后明细残留。
deleteDetailsByPathCodes(pathCodes);
// 执行主表批量删除
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.bo.BaseStoreInfoBo;
import org.dromara.wcs.domain.vo.BaseStoreInfoVo;
@ -44,6 +46,7 @@ public class BaseStoreInfoServiceImpl implements IBaseStoreInfoService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public BaseStoreInfoVo queryById(Long objId){
return baseMapper.selectCustomBaseStoreInfoVoById(objId);
}
@ -139,10 +142,14 @@ public class BaseStoreInfoServiceImpl implements IBaseStoreInfoService {
@Override
@DSTransactional
public Boolean insertByBo(BaseStoreInfoBo bo) {
// 将 BO 对象转换为实体对象
BaseStoreInfo add = MapstructUtils.convert(bo, BaseStoreInfo.class);
// 保存前进行数据校验
validEntityBeforeSave(add);
// 执行插入操作
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
// 插入成功后将生成的主键回填到 BO 对象
bo.setObjId(add.getObjId());
}
return flag;
@ -155,10 +162,14 @@ public class BaseStoreInfoServiceImpl implements IBaseStoreInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(BaseStoreInfoBo bo) {
// 将 BO 对象转换为实体对象
BaseStoreInfo update = MapstructUtils.convert(bo, BaseStoreInfo.class);
// 保存前进行数据校验
validEntityBeforeSave(update);
// 执行更新操作
return baseMapper.updateById(update) > 0;
}
@ -166,15 +177,19 @@ public class BaseStoreInfoServiceImpl implements IBaseStoreInfoService {
*
*/
private void validEntityBeforeSave(BaseStoreInfo entity){
// 校验实体对象和仓库编号
if (entity == null || StringUtils.isBlank(entity.getStoreCode())) {
throw new ServiceException("仓库编号不能为空");
}
// 查询相同仓库编号的数量,排除当前记录(更新场景)
Long sameStoreCodeCount = baseMapper.selectCount(Wrappers.<BaseStoreInfo>lambdaQuery()
.eq(BaseStoreInfo::getStoreCode, entity.getStoreCode())
.ne(entity.getObjId() != null, BaseStoreInfo::getObjId, entity.getObjId()));
// 校验仓库编号唯一性
if (sameStoreCodeCount > 0) {
throw new ServiceException("仓库编号已存在,请更换仓库编号");
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
// 仓库默认启用,保证库位维护时可以立即作为所属仓库使用。
entity.setIsFlag(1);
@ -189,6 +204,7 @@ public class BaseStoreInfoServiceImpl implements IBaseStoreInfoService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.bo.LiveTaskDetailBo;
import org.dromara.wcs.domain.vo.LiveTaskDetailVo;
@ -47,6 +49,7 @@ public class LiveTaskDetailServiceImpl implements ILiveTaskDetailService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public LiveTaskDetailVo queryById(Long objId){
return baseMapper.selectCustomLiveTaskDetailVoById(objId);
}
@ -153,10 +156,14 @@ public class LiveTaskDetailServiceImpl implements ILiveTaskDetailService {
@Override
@DSTransactional
public Boolean insertByBo(LiveTaskDetailBo bo) {
// 将 BO 对象转换为实体对象
LiveTaskDetail add = MapstructUtils.convert(bo, LiveTaskDetail.class);
// 保存前进行数据校验
validEntityBeforeSave(add);
// 执行插入操作
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
// 插入成功后将生成的主键回填到 BO 对象
bo.setObjId(add.getObjId());
}
return flag;
@ -169,17 +176,23 @@ public class LiveTaskDetailServiceImpl implements ILiveTaskDetailService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(LiveTaskDetailBo bo) {
// 将 BO 对象转换为实体对象
LiveTaskDetail update = MapstructUtils.convert(bo, LiveTaskDetail.class);
// 校验主键标识
if (update == null || update.getObjId() == null) {
throw new ServiceException("主键标识不能为空");
}
// 查询原记录
LiveTaskDetail old = baseMapper.selectById(update.getObjId());
if (old == null) {
throw new ServiceException("实时任务明细不存在,无法修改");
}
// 保存前进行数据校验
validEntityBeforeSave(update);
// 执行更新操作
return baseMapper.updateById(update) > 0;
}
@ -187,19 +200,25 @@ public class LiveTaskDetailServiceImpl implements ILiveTaskDetailService {
*
*/
private void validEntityBeforeSave(LiveTaskDetail entity){
// 校验实体对象和任务编号
if (entity == null || StringUtils.isBlank(entity.getTaskCode())) {
throw new ServiceException("任务编号不能为空");
}
// 查询任务队列主表记录
LiveTaskQueue taskQueue = liveTaskQueueMapper.selectOne(Wrappers.<LiveTaskQueue>lambdaQuery()
.eq(LiveTaskQueue::getTaskCode, entity.getTaskCode())
.last("limit 1"));
// 校验任务编号是否存在
if (taskQueue == null) {
throw new ServiceException("任务编号不存在,请先维护实时任务队列");
}
// 从主表继承空字段
inheritMasterFieldsWhenBlank(entity, taskQueue);
// 设置默认校验标识
if (entity.getIsValidate() == null) {
entity.setIsValidate(1);
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
entity.setIsFlag(1);
}
@ -209,33 +228,43 @@ public class LiveTaskDetailServiceImpl implements ILiveTaskDetailService {
*
*/
private void inheritMasterFieldsWhenBlank(LiveTaskDetail detail, LiveTaskQueue taskQueue) {
// 物料编码为空时从主表继承
if (StringUtils.isBlank(detail.getMaterialCode())) {
detail.setMaterialCode(taskQueue.getMaterialCode());
}
// 托盘条码为空时从主表继承
if (StringUtils.isBlank(detail.getPalletBarcode())) {
detail.setPalletBarcode(taskQueue.getPalletBarcode());
}
// 物料条码为空时从主表继承
if (StringUtils.isBlank(detail.getMaterialBarcode())) {
detail.setMaterialBarcode(taskQueue.getMaterialBarcode());
}
// 物料数量为空时从主表继承
if (detail.getMaterialCount() == null) {
detail.setMaterialCount(taskQueue.getMaterialCount());
}
// 任务类型为空时从主表继承
if (detail.getTaskType() == null) {
detail.setTaskType(taskQueue.getTaskType());
}
// 任务分类为空时从主表继承
if (detail.getTaskCategory() == null) {
detail.setTaskCategory(taskQueue.getTaskCategory());
}
// 起始点位为空时从主表继承
if (StringUtils.isBlank(detail.getStartPoint())) {
detail.setStartPoint(taskQueue.getStartPoint());
}
// 目标点位为空时从主表继承
if (StringUtils.isBlank(detail.getEndPoint())) {
detail.setEndPoint(taskQueue.getEndPoint());
}
// 路径编号为空时从主表继承
if (StringUtils.isBlank(detail.getPathCode())) {
detail.setPathCode(taskQueue.getPathCode());
}
// 任务状态为空时从主表继承
if (detail.getTaskStatus() == null) {
detail.setTaskStatus(taskQueue.getTaskStatus());
}
@ -249,15 +278,18 @@ public class LiveTaskDetailServiceImpl implements ILiveTaskDetailService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
// 主键集合为空时直接返回
if (ids == null || ids.isEmpty()) {
// 删除入口明确要求主键集合空集合直接返回避免拼出无意义SQL。
return false;
}
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
// TODO: 做一些业务上的校验,判断是否需要校验
}
// 执行批量删除操作
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.dromara.wcs.domain.LiveTaskDetail;
import org.dromara.wcs.domain.bo.LiveTaskDetailBo;
@ -50,6 +52,7 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
* @return
*/
@Override
@Cacheable(cacheNames = "wcs_cache", key = "#objId")
public LiveTaskQueueVo queryById(Long objId){
LiveTaskQueueVo vo = baseMapper.selectCustomLiveTaskQueueVoById(objId);
if (vo != null) {
@ -162,11 +165,16 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
@Override
@DSTransactional
public Boolean insertByBo(LiveTaskQueueBo bo) {
// 将 BO 对象转换为实体对象
LiveTaskQueue add = MapstructUtils.convert(bo, LiveTaskQueue.class);
// 保存前进行数据校验
validEntityBeforeSave(add);
// 执行插入操作
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
// 插入成功后将生成的主键回填到 BO 对象
bo.setObjId(add.getObjId());
// 保存任务明细
saveDetails(bo);
}
return flag;
@ -179,18 +187,24 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", key = "#bo.objId")
@DSTransactional
public Boolean updateByBo(LiveTaskQueueBo bo) {
// 查询原记录
LiveTaskQueue old = baseMapper.selectById(bo.getObjId());
if (old == null) {
throw new ServiceException("实时任务队列不存在,无法修改");
}
// 将 BO 对象转换为实体对象
LiveTaskQueue update = MapstructUtils.convert(bo, LiveTaskQueue.class);
// 保存前进行数据校验
validEntityBeforeSave(update);
// 任务编号是子表外键,先按旧编号删除旧明细,避免 ON UPDATE CASCADE 后删不到旧数据。
deleteDetailsByTaskCode(old.getTaskCode());
// 执行更新操作
boolean flag = baseMapper.updateById(update) > 0;
if (flag) {
// 更新成功后保存任务明细
saveDetails(bo);
}
return flag;
@ -200,19 +214,24 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
*
*/
private void validEntityBeforeSave(LiveTaskQueue entity){
// 校验实体对象和任务编号
if (entity == null || StringUtils.isBlank(entity.getTaskCode())) {
throw new ServiceException("任务编号不能为空");
}
// 查询相同任务编号的数量,排除当前记录(更新场景)
Long sameTaskCodeCount = baseMapper.selectCount(Wrappers.<LiveTaskQueue>lambdaQuery()
.eq(LiveTaskQueue::getTaskCode, entity.getTaskCode())
.ne(entity.getObjId() != null, LiveTaskQueue::getObjId, entity.getObjId()));
// 校验任务编号唯一性
if (sameTaskCodeCount > 0) {
throw new ServiceException("任务编号已存在,请更换任务编号");
}
// 设置默认任务状态
if (entity.getTaskStatus() == null) {
// 新建任务默认进入待执行,避免空状态在调度看板中无法归类。
entity.setTaskStatus(1);
}
// 设置默认启用标识
if (entity.getIsFlag() == null) {
entity.setIsFlag(1);
}
@ -222,17 +241,22 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
*
*/
private void saveDetails(LiveTaskQueueBo bo) {
// 获取任务明细列表
List<LiveTaskDetailBo> details = bo.getDetails();
if (details == null || details.isEmpty()) {
return;
}
// 遍历明细列表并保存
for (LiveTaskDetailBo detailBo : details) {
// 将明细 BO 转换为实体对象
LiveTaskDetail detail = MapstructUtils.convert(detailBo, LiveTaskDetail.class);
// 子表跟随主表整体替换,清空旧主键避免误把历史明细主键带入新增流程。
detail.setObjId(null);
// 设置任务编号
detail.setTaskCode(bo.getTaskCode());
// 明细常用字段默认继承主表,减少人工重复录入导致的主子表业务信息不一致。
inheritMasterFieldsWhenBlank(detail, bo);
// 插入明细记录
liveTaskDetailMapper.insert(detail);
}
}
@ -241,39 +265,51 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
*
*/
private void inheritMasterFieldsWhenBlank(LiveTaskDetail detail, LiveTaskQueueBo bo) {
// 物料编码为空时从主表继承
if (StringUtils.isBlank(detail.getMaterialCode())) {
detail.setMaterialCode(bo.getMaterialCode());
}
// 托盘条码为空时从主表继承
if (StringUtils.isBlank(detail.getPalletBarcode())) {
detail.setPalletBarcode(bo.getPalletBarcode());
}
// 物料条码为空时从主表继承
if (StringUtils.isBlank(detail.getMaterialBarcode())) {
detail.setMaterialBarcode(bo.getMaterialBarcode());
}
// 物料数量为空时从主表继承
if (detail.getMaterialCount() == null) {
detail.setMaterialCount(bo.getMaterialCount());
}
// 任务类型为空时从主表继承
if (detail.getTaskType() == null) {
detail.setTaskType(bo.getTaskType());
}
// 任务分类为空时从主表继承
if (detail.getTaskCategory() == null) {
detail.setTaskCategory(bo.getTaskCategory());
}
// 起始点位为空时从主表继承
if (StringUtils.isBlank(detail.getStartPoint())) {
detail.setStartPoint(bo.getStartPoint());
}
// 目标点位为空时从主表继承
if (StringUtils.isBlank(detail.getEndPoint())) {
detail.setEndPoint(bo.getEndPoint());
}
// 路径编号为空时从主表继承
if (StringUtils.isBlank(detail.getPathCode())) {
detail.setPathCode(bo.getPathCode());
}
// 任务状态为空时从主表继承
if (detail.getTaskStatus() == null) {
detail.setTaskStatus(bo.getTaskStatus());
}
// 设置默认校验标识
if (detail.getIsValidate() == null) {
detail.setIsValidate(1);
}
// 设置默认启用标识
if (detail.getIsFlag() == null) {
detail.setIsFlag(1);
}
@ -283,9 +319,11 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
*
*/
private void deleteDetailsByTaskCode(String taskCode) {
// 任务编号为空时直接返回
if (StringUtils.isBlank(taskCode)) {
return;
}
// 根据任务编号删除明细
liveTaskDetailMapper.delete(Wrappers.<LiveTaskDetail>lambdaQuery()
.eq(LiveTaskDetail::getTaskCode, taskCode));
}
@ -294,9 +332,11 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
*
*/
private void deleteDetailsByTaskCodes(Collection<String> taskCodes) {
// 任务编号集合为空时直接返回
if (taskCodes == null || taskCodes.isEmpty()) {
return;
}
// 根据任务编号集合批量删除明细
liveTaskDetailMapper.delete(Wrappers.<LiveTaskDetail>lambdaQuery()
.in(LiveTaskDetail::getTaskCode, taskCodes));
}
@ -305,21 +345,26 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
* XML collection N+1
*/
private void attachDetails(List<LiveTaskQueueVo> taskQueueList) {
// 任务队列列表为空时直接返回
if (taskQueueList == null || taskQueueList.isEmpty()) {
return;
}
// 提取所有任务编号并去重
List<String> taskCodes = taskQueueList.stream()
.map(LiveTaskQueueVo::getTaskCode)
.filter(StringUtils::isNotBlank)
.distinct()
.toList();
// 任务编号为空时设置空明细列表
if (taskCodes.isEmpty()) {
taskQueueList.forEach(item -> item.setDetails(List.of()));
return;
}
// 批量查询明细并按任务编号分组
Map<String, List<LiveTaskDetailVo>> detailMap = liveTaskDetailMapper.selectCustomLiveTaskDetailVoByTaskCodes(taskCodes)
.stream()
.collect(Collectors.groupingBy(LiveTaskDetailVo::getTaskCode));
// 将明细挂载到对应的任务队列
taskQueueList.forEach(item -> item.setDetails(detailMap.getOrDefault(item.getTaskCode(), List.of())));
}
@ -331,21 +376,25 @@ public class LiveTaskQueueServiceImpl implements ILiveTaskQueueService {
* @return
*/
@Override
@CacheEvict(cacheNames = "wcs_cache", allEntries = true)
@DSTransactional
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
// 主键集合为空时直接返回
if (ids == null || ids.isEmpty()) {
// 删除入口明确要求主键集合空集合直接返回避免拼出无意义SQL。
return false;
}
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
// TODO: 做一些业务上的校验,判断是否需要校验
}
// 根据主键集合查询任务编号
List<String> taskCodes = baseMapper.selectTaskCodesByIds(ids).stream()
.filter(StringUtils::isNotBlank)
.distinct()
.toList();
// 主子表删除放在同一个本地多数据源事务里,避免只删主表后明细残留。
deleteDetailsByTaskCodes(taskCodes);
// 执行主表批量删除
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -72,4 +72,5 @@
from base_device_host t
${ew.getCustomSqlSegment}
</select>
</mapper>

Loading…
Cancel
Save