1、新增装配设置接口、多语言整理;2、订单部件cadinfo接口部件范围查询错误修复;

This commit is contained in:
gaoqr
2026-02-27 16:05:14 +08:00
parent d825ce8f6d
commit 1fad32a235
31 changed files with 1017 additions and 21 deletions
@@ -108,4 +108,10 @@ public class AssertUtils {
throw new ServiceException(errorCode);
}
}
public static void isTrue(boolean expression, ErrorCode errorCode, Object... params) {
if (expression) {
throw new ServiceException(errorCode, params);
}
}
}
@@ -0,0 +1,29 @@
package com.cf.imes.module.executor.api.ordercomponent;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.module.executor.api.ordercomponent.dto.OrderComponentListReqDTO;
import com.cf.imes.module.executor.api.ordercomponent.dto.OrderComponentListRespDTO;
import com.cf.imes.module.executor.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/25 16:06
*/
@FeignClient(name = ApiConstants.NAME)
@Tag(name = "RPC 服务 - 部件管理")
public interface OrderComponentApi {
String PREFIX = ApiConstants.PREFIX + "/order/component";
@PostMapping(PREFIX + "/list")
@Operation(summary = "获取生产单下的部件列表")
CommonResult<List<OrderComponentListRespDTO>> getOrderComponentList(@RequestBody OrderComponentListReqDTO dto);
}
@@ -0,0 +1,22 @@
package com.cf.imes.module.executor.api.ordercomponent.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/25 16:18
*/
@Schema(description = "RPC 服务 - 部件管理 - 生产单部件列表查询 - Request DTO")
@Data
public class OrderComponentListReqDTO implements Serializable {
private static final long serialVersionUID = -5691595836226548840L;
@Schema(description = "生产单编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3,4]")
private List<Long> orderIds;
}
@@ -0,0 +1,30 @@
package com.cf.imes.module.executor.api.ordercomponent.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/25 16:18
*/
@Schema(description = "RPC 服务 - 部件管理 - 生产单部件列表查询 - Response DTO")
@Data
public class OrderComponentListRespDTO implements Serializable {
private static final long serialVersionUID = -5691595836226548840L;
@Schema(description = "父ID")
private Long pid;
@Schema(description = "部件Id")
private Long id;
@Schema(description = "部件名")
private String name;
private List<OrderComponentListRespDTO> children;
}
@@ -0,0 +1,31 @@
package com.cf.imes.module.executor.api.ordercomponent;
import cn.hutool.core.bean.BeanUtil;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.module.executor.api.ordercomponent.dto.OrderComponentListReqDTO;
import com.cf.imes.module.executor.api.ordercomponent.dto.OrderComponentListRespDTO;
import com.cf.imes.module.executor.controller.admin.ordercomponent.vo.OrderComponentRespVO;
import com.cf.imes.module.executor.service.ordercomponent.OrderComponentService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/25 16:26
*/
@RestController // 提供 RESTful API 接口,给 Feign 调用
public class OrderComponentApiImpl implements OrderComponentApi {
@Resource
private OrderComponentService orderComponentService;
@Override
public CommonResult<List<OrderComponentListRespDTO>> getOrderComponentList(OrderComponentListReqDTO dto) {
List<OrderComponentRespVO> orderComponentListOnOrders = orderComponentService.getOrderComponentListOnOrders(dto.getOrderIds());
return CommonResult.success(BeanUtil.copyToList(orderComponentListOnOrders, OrderComponentListRespDTO.class));
}
}
@@ -22,4 +22,7 @@ public class OrderComponentRespVO {
@Schema(description = "CAD图纸文件哈希值")
private String fileHash;
@Schema(description = "加工状态")
private Integer processStatus;
}
@@ -66,4 +66,22 @@ public class OrderViewPlatePageRespVO {
@Schema(description = "CAD设计板编号")
private String customNumber;
@Schema(description = "面积")
private BigDecimal area;
@Schema(description = "纹理")
private Integer texture;
@Schema(description = "是否造型")
private Boolean isSculpt;
@Schema(description = "是否异形")
private Boolean isSpecialShaped;
@Schema(description = "是否排孔")
private Boolean isRowHole;
@Schema(description = "备注")
private String remark;
}
@@ -96,4 +96,34 @@ public class OrderBodyViewPlatesPageDO {
* cad图纸文件id
*/
private Long cadViewFileId;
/**
* 面积
*/
private BigDecimal area;
/**
* 纹理
*/
private Integer texture;
/**
* 是否造型
*/
private Boolean isSculpt;
/**
* 是否异形
*/
private Boolean isSpecialShaped;
/**
* 是否排孔
*/
private Boolean isRowHole;
/**
* 备注
*/
private String remark;
}
@@ -67,4 +67,12 @@ public interface OrderComponentService {
* @param id
*/
void restoreOrderComponent(Long orderId, Long id);
/**
* 查询订单列表下所有部件
*
* @param orderIds
* @return
*/
List<OrderComponentRespVO> getOrderComponentListOnOrders(List<Long> orderIds);
}
@@ -256,9 +256,12 @@ public class OrderComponentServiceImpl implements OrderComponentService {
.in(OrderComponentDO::getTopId, topIds)
.eq(OrderComponentDO::getOrderId, orderId)
.eqIfPresent(OrderComponentDO::getDeleted, pageReqVO.isDeleted())
.select(OrderComponentDO::getId, OrderComponentDO::getCadViewFileId));
.select(OrderComponentDO::getId, OrderComponentDO::getCadViewFileId, OrderComponentDO::getPid));
Set<Long> queryComponentIds = new HashSet<>();
if (CollUtil.isNotEmpty(orderComponentDOS)) {
componentIds = orderComponentDOS.stream().map(OrderComponentDO::getId).collect(Collectors.toSet());
for (OrderComponentDO co : componentDOS) {
queryComponentIds.addAll(getChildrenIds(co, orderComponentDOS));
}
} else {
return Collections.emptyList();
}
@@ -573,13 +576,13 @@ public class OrderComponentServiceImpl implements OrderComponentService {
return needDeleteIds;
}
// @Override
// public List<OrderComponentRespVO> getOrderComponentListOnOrders(List<Long> orderIds) {
// List<OrderComponentDO> orderComponentDOS = orderComponentMapper.selectList(new LambdaQueryWrapper<OrderComponentDO>()
// .in(OrderComponentDO::getOrderId, orderIds)
// .eq(OrderComponentDO::getDeleted, false)
// .eq(OrderComponentDO::getOrganId, SecurityFrameworkUtils.getUserOrganId())
// .select(OrderComponentDO::getId, OrderComponentDO::getName, OrderComponentDO::getPid));
// return BeanUtil.copyToList(orderComponentDOS, OrderComponentRespVO.class);
// }
@Override
public List<OrderComponentRespVO> getOrderComponentListOnOrders(List<Long> orderIds) {
List<OrderComponentDO> orderComponentDOS = orderComponentMapper.selectList(new LambdaQueryWrapper<OrderComponentDO>()
.in(OrderComponentDO::getOrderId, orderIds)
.eq(OrderComponentDO::getDeleted, false)
.eq(OrderComponentDO::getOrganId, SecurityFrameworkUtils.getUserOrganId())
.select(OrderComponentDO::getId, OrderComponentDO::getName, OrderComponentDO::getPid));
return BeanUtil.copyToList(orderComponentDOS, OrderComponentRespVO.class);
}
}
@@ -536,9 +536,14 @@
<select id="selectBodyViewPlatesPage" resultType="com.cf.imes.module.executor.dal.dataobject.orderItem.OrderBodyViewPlatesPageDO">
SELECT p.plate_no, p.name, p.width, p.height, p.thickness, g.material, g.color, p.cad_plate_no as customNumber, p.id, i.body_id, p.cad_view_id
<if test="cadView">
<choose>
<when test="cadView">
, p.seal_left, p.seal_down, p.seal_right, p.seal_up
</if>
</when>
<otherwise>
, p.area, p.texture, p.is_special_shaped, p.is_sculpt, p.is_row_hole, p.remark
</otherwise>
</choose>
<if test="componentIds != null and componentIds.size() > 0">
, i.comp_id
</if>
@@ -365,4 +365,12 @@ public class ErrorCodeConstants {
public static final ErrorCode PRODUCT_PURCHASE_NO_EXIST = new ErrorCode(1_002_049_001, "product_purchase.no_exist");
public static final ErrorCode PRODUCT_PURCHASE_ENDTIME_BEFORE_DELAYTIME_ERROR = new ErrorCode(1_002_049_002, "product_purchase.endtime_before_delaytime_error");
public static final ErrorCode PRODUCT_DELAY_UNIT_NOT_SUPPORT = new ErrorCode(1_002_049_003, "product.delay_duration_unit_not_support");
//=========== 装配设置 1-002-050-000 ============
public static final ErrorCode ASSEMBLY_CONFIG_IMPORT_ORDER_COMPONENTS_QUERY_ERROR = new ErrorCode(1_002_050_001, "assembly.config.import.order_components.query.error");
public static final ErrorCode ASSEMBLY_CONFIG_NOT_EXIST = new ErrorCode(1_002_050_002, "assembly.config.not_exist");
public static final ErrorCode ASSEMBLY_CONFIG_DO_CONFIG_EXIST = new ErrorCode(1_002_050_003, "assembly.config.do_config_exist");
public static final ErrorCode ASSEMBLY_CONFIG_COVER_TARGET_NOT_EXIST = new ErrorCode(1_002_050_004, "assembly.config.cover_target_not_exist");
public static final ErrorCode ASSEMBLY_CONFIG_NEW_CONFIG_NAME_EXIST = new ErrorCode(1_002_050_005, "assembly.config.new_config_name_exist");
public static final ErrorCode ASSEMBLY_CONFIG_REMOVE_NOT_EXIST = new ErrorCode(1_002_050_006, "assembly.config.remove_not_exist");
}
@@ -0,0 +1,86 @@
package com.cf.imes.module.system.controller.admin.assemblyconfig;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigImportReqVO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigListRespVO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigSaveReqVO;
import com.cf.imes.module.system.service.assemblyconfig.AssemblyConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/25 15:13
*/
@Tag(name = "管理后台 - 系统配置 - 装配设置")
@RestController
@RequestMapping("/system/assembly/config")
@Validated
@Slf4j
public class AssemblyConfigController {
@Resource
private AssemblyConfigService assemblyConfigService;
@PostMapping("/order/import")
@Operation(summary = "导入装配顺序")
public CommonResult<Boolean> importAssemblyConfigFromOrders(@RequestBody @Valid AssemblyConfigImportReqVO reqVO) {
assemblyConfigService.importAssemblyConfigFromOrders(reqVO);
return CommonResult.success(true);
}
@GetMapping("/list")
@Operation(summary = "查询装配设置")
public CommonResult<List<AssemblyConfigListRespVO>> getAssemblyConfigList() {
return CommonResult.success(assemblyConfigService.getOrgAssemblyConfigList());
}
@PostMapping("/{configId}")
@Operation(summary = "待选部件转加工部件")
public CommonResult<Boolean> doConfig(@PathVariable Long configId) {
assemblyConfigService.doConfig(configId);
return CommonResult.success(true);
}
@PostMapping("/cover/{configId}")
@Operation(summary = "覆盖原有加工部件")
public CommonResult<Boolean> coverConfig(@PathVariable Long configId) {
assemblyConfigService.coverConfig(configId);
return CommonResult.success(true);
}
@PostMapping("/new/{configId}")
@Operation(summary = "新增加工部件")
public CommonResult<Boolean> newConfig(@PathVariable Long configId, @RequestParam("name") String name) {
assemblyConfigService.newConfig(configId, name);
return CommonResult.success(true);
}
@PostMapping("/configured/remove/{configId}")
@Operation(summary = "删除已配置的加工部件,恢复到待选")
public CommonResult<Boolean> removeConfigured(@PathVariable Long configId) {
assemblyConfigService.removeConfigured(configId);
return CommonResult.success(true);
}
@PostMapping("/save")
@Operation(summary = "保存装配设置")
public CommonResult<Boolean> saveAssemblyConfig(@RequestBody AssemblyConfigSaveReqVO reqVO) {
assemblyConfigService.saveConfig(reqVO);
return CommonResult.success(true);
}
}
@@ -0,0 +1,23 @@
package com.cf.imes.module.system.controller.admin.assemblyconfig.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/25 15:53
*/
@Schema(description = "管理后台 - 装配设置 - 导入部件 Request VO")
@Data
public class AssemblyConfigImportReqVO {
@Schema(description = "生产单号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3,4]")
@NotEmpty(message = "{assembly.config.import.orderIds.notEmpty}")
@Size(max = 100, message = "{assembly.config.import.orderIds.size}")
private List<Long> orderIds;
}
@@ -0,0 +1,28 @@
package com.cf.imes.module.system.controller.admin.assemblyconfig.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
/**
*
*
* @author Gqr
* @since 2026/2/26 14:11
*/
@Data
@Builder
@Schema(description = "管理后台 - 装配设置 - 列表 Response VO")
public class AssemblyConfigListRespVO {
@Schema(description = "装配设置ID")
private Long id;
@Schema(description = "部件名称")
private String componentName;
@Schema(description = "源部件ID")
private Long sourceComponentId;
@Schema(description = "设置状态,0导入、1已配置", example = "1")
private Integer status;
}
@@ -0,0 +1,23 @@
package com.cf.imes.module.system.controller.admin.assemblyconfig.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
*
*
* @author Gqr
* @since 2026/2/26 17:13
*/
@Data
@Schema(description = "管理后台 - 装配设置保存 Request VO")
public class AssemblyConfigSaveReqVO {
@Schema(description = "装配设置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "{assembly.config.save.id.notNull}")
private Long id;
@Schema(description = "装备设置树形结构", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{assembly.config.save.structure.config.notNull}")
private AssemblyConfigSaveStructureReqVO config;
}
@@ -0,0 +1,25 @@
package com.cf.imes.module.system.controller.admin.assemblyconfig.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
*
*
* @author Gqr
* @since 2026/2/26 17:15
*/
@Data
@Schema(description = "管理后台 - 装配设置保存树形结构 Request VO")
public class AssemblyConfigSaveStructureReqVO {
@Schema(description = "部件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
private String name;
@Schema(description = "是否加工,true是,false否", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private boolean process;
@Schema(description = "子部件列表")
private List<AssemblyConfigSaveStructureReqVO> children;
}
@@ -0,0 +1,46 @@
package com.cf.imes.module.system.controller.admin.assemblyconfig.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 装配设置树形结构VO
*
* @author Gqr
* @since 2026/2/26 10:27
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AssemblyConfigStructureVO {
/**
* 源部件ID
*/
@JsonIgnore
private Long sourceComponentId;
/**
* 部件名称
*/
private String name;
/**
* 子部件
*/
private List<AssemblyConfigStructureVO> children;
/**
* 结构哈希值
*/
@JsonIgnore
private String structureHash;
/**
* 是否加工,true是,false否
*/
private boolean process;
}
@@ -0,0 +1,63 @@
package com.cf.imes.module.system.dal.dataobject.assemblyconfig;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.cf.imes.framework.mybatis.core.dataobject.BaseDO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* 装配设置实体
*
* @author Gqr
* @since 2026/2/26 10:04
*/
@TableName(value = "system_config_assembly")
@KeySequence("system_config_assembly_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AssemblyConfigDO extends BaseDO {
/**
* 主键ID
*/
private Long id;
/**
* 组织ID
*/
@TableField(fill = FieldFill.INSERT)
private Long organId;
/**
* 源组件ID
*/
private Long sourceComponentId;
/**
* 结构JSON
*/
private String structureJson;
/**
* 结构哈希
*/
private String structureHash;
/**
* 组件名称
*/
private String componentName;
/**
* 状态
*/
private Integer status;
}
@@ -20,7 +20,7 @@ import java.io.Serializable;
* @since 2024/11/11 18:31
*/
@TableName(value = "custom_plateno_seq")
@KeySequence("custom_plateno_seq_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@KeySequence("custom_plateno_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@ToString(callSuper = true)
@Builder
@@ -0,0 +1,15 @@
package com.cf.imes.module.system.dal.mysql.assemblyconfig;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cf.imes.module.system.dal.dataobject.assemblyconfig.AssemblyConfigDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 装配设置 Mapper
*
* @author Gqr
* @since 2026/2/26 10:14
*/
@Mapper
public interface AssemblyConfigMapper extends BaseMapper<AssemblyConfigDO> {
}
@@ -0,0 +1,26 @@
package com.cf.imes.module.system.enums.assemblyconfig;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 装配设置状态
*
* @author Gqr
* @since 2026/2/26 11:18
*/
@Getter
@AllArgsConstructor
public enum AssemblyConfigStatusEnum {
/**
* 导入
*/
IMPORT(0),
/**
* 配置完成
*/
CONFIGURED(1);
private final int status;
}
@@ -2,6 +2,7 @@ package com.cf.imes.module.system.framework.rpc.config;
import com.cf.imes.module.executor.api.customplateno.OrderCustomPlateNoApi;
import com.cf.imes.module.executor.api.orderProcess.OrderProcessApi;
import com.cf.imes.module.executor.api.ordercomponent.OrderComponentApi;
import com.cf.imes.module.executor.api.plan.OrderPlanApi;
import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.infra.api.websocket.WebSocketSenderApi;
@@ -9,6 +10,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = {FileApi.class, WebSocketSenderApi.class, OrderProcessApi.class, OrderPlanApi.class, OrderCustomPlateNoApi.class})
@EnableFeignClients(clients = {FileApi.class, WebSocketSenderApi.class, OrderProcessApi.class,
OrderPlanApi.class, OrderCustomPlateNoApi.class, OrderComponentApi.class})
public class RpcConfiguration {
}
@@ -0,0 +1,65 @@
package com.cf.imes.module.system.service.assemblyconfig;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigImportReqVO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigListRespVO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigSaveReqVO;
import java.util.List;
/**
* 装配设置 Service 接口
*
* @author Gqr
* @since 2026/2/25 15:10
*/
public interface AssemblyConfigService {
/**
* 导入装配顺序
*
* @param reqVO
*/
void importAssemblyConfigFromOrders(AssemblyConfigImportReqVO reqVO);
/**
* 查询组织装配设置列表
*
* @return
*/
List<AssemblyConfigListRespVO> getOrgAssemblyConfigList();
/**
* 待选部件转加工部件
*
* @param configId
*/
void doConfig(Long configId);
/**
* 覆盖原有加工部件
*
* @param configId
*/
void coverConfig(Long configId);
/**
* 新增加工部件
*
* @param configId
* @param name
*/
void newConfig(Long configId, String name);
/**
* 移除已配置的加工部件
*
* @param configId
*/
void removeConfigured(Long configId);
/**
* 保存装配设置
*
* @param reqVO
*/
void saveConfig(AssemblyConfigSaveReqVO reqVO);
}
@@ -0,0 +1,386 @@
package com.cf.imes.module.system.service.assemblyconfig;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.enums.DeletedCodeEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.executor.api.ordercomponent.OrderComponentApi;
import com.cf.imes.module.executor.api.ordercomponent.dto.OrderComponentListReqDTO;
import com.cf.imes.module.executor.api.ordercomponent.dto.OrderComponentListRespDTO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigImportReqVO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigListRespVO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigSaveReqVO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigSaveStructureReqVO;
import com.cf.imes.module.system.controller.admin.assemblyconfig.vo.AssemblyConfigStructureVO;
import com.cf.imes.module.system.dal.dataobject.assemblyconfig.AssemblyConfigDO;
import com.cf.imes.module.system.dal.mysql.assemblyconfig.AssemblyConfigMapper;
import com.cf.imes.module.system.enums.assemblyconfig.AssemblyConfigStatusEnum;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ASSEMBLY_CONFIG_COVER_TARGET_NOT_EXIST;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ASSEMBLY_CONFIG_DO_CONFIG_EXIST;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ASSEMBLY_CONFIG_IMPORT_ORDER_COMPONENTS_QUERY_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ASSEMBLY_CONFIG_NEW_CONFIG_NAME_EXIST;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ASSEMBLY_CONFIG_NOT_EXIST;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ASSEMBLY_CONFIG_REMOVE_NOT_EXIST;
/**
* 装配设置 ServiceImpl 接口实现类
*
* @author Gqr
* @since 2026/2/25 15:11
*/
@Service
public class AssemblyConfigServiceImpl implements AssemblyConfigService {
@Resource
private OrderComponentApi orderComponentApi;
@Resource
private AssemblyConfigMapper assemblyConfigMapper;
@Override
public void importAssemblyConfigFromOrders(AssemblyConfigImportReqVO reqVO) {
Long organId = SecurityFrameworkUtils.getUserOrganId();
// 1、获取订单列表下的所有部件
OrderComponentListReqDTO orderComponentListReqDTO = new OrderComponentListReqDTO();
orderComponentListReqDTO.setOrderIds(reqVO.getOrderIds());
CommonResult<List<OrderComponentListRespDTO>> orderComponentListResult = orderComponentApi.getOrderComponentList(orderComponentListReqDTO);
if (orderComponentListResult.isError()) {
throw new ServiceException(ASSEMBLY_CONFIG_IMPORT_ORDER_COMPONENTS_QUERY_ERROR);
}
List<OrderComponentListRespDTO> orderComponentList = orderComponentListResult.getData();
if(CollUtil.isEmpty(orderComponentList)) {
return;
}
// 2、构建树 + 排序 + 生成结构hash
List<AssemblyConfigStructureVO> roots = buildTreeAndComputeHash(orderComponentList);
// 3、按 name 分组去重(同名、同结构只保留一条)
Map<String, Map<String, AssemblyConfigStructureVO>> uniqueMap = new LinkedHashMap<>();
for (AssemblyConfigStructureVO node : roots) {
uniqueMap.computeIfAbsent(node.getName(), k -> new LinkedHashMap<>())
.putIfAbsent(node.getStructureHash(), node);
}
List<AssemblyConfigStructureVO> dedupedList = uniqueMap.values().stream()
.flatMap(m -> m.values().stream())
.toList();
// 4、查询数据库已存在的结构
List<String> names = dedupedList.stream()
.map(AssemblyConfigStructureVO::getName)
.distinct()
.toList();
List<AssemblyConfigDO> existConfigs = assemblyConfigMapper.selectList(
new LambdaQueryWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getOrganId, organId)
.in(AssemblyConfigDO::getComponentName, names)
.eq(AssemblyConfigDO::getDeleted, 0)
);
Map<String, Set<String>> existHashMap = existConfigs.stream()
.collect(Collectors.groupingBy(
AssemblyConfigDO::getComponentName,
Collectors.mapping(AssemblyConfigDO::getStructureHash, Collectors.toSet())
));
// 5、过滤数据库已存在的结构
List<AssemblyConfigStructureVO> needImportList = dedupedList.stream()
.filter(node -> {
Set<String> hashes = existHashMap.get(node.getName());
return hashes == null || !hashes.contains(node.getStructureHash());
})
.toList();
if (needImportList.isEmpty()) return;
// 6、批量生成 AssemblyConfigDO 并插入
List<AssemblyConfigDO> importDOList = needImportList.stream()
.map(node -> {
AssemblyConfigDO configDO = new AssemblyConfigDO();
configDO.setOrganId(organId);
configDO.setSourceComponentId(node.getSourceComponentId());
configDO.setComponentName(node.getName());
configDO.setStructureHash(node.getStructureHash());
configDO.setStructureJson(JsonUtils.zipString(JsonUtils.toJsonString(node)));
configDO.setStatus(AssemblyConfigStatusEnum.IMPORT.getStatus());
return configDO;
})
.toList();
assemblyConfigMapper.insert(importDOList);
}
/**
* 构建树 + 排序 + 生成结构 hash
*
* @param list
* @return
*/
private List<AssemblyConfigStructureVO> buildTreeAndComputeHash(List<OrderComponentListRespDTO> list) {
if (list == null || list.isEmpty()) return Collections.emptyList();
Map<Long, AssemblyConfigStructureVO> map = new HashMap<>(list.size());
List<AssemblyConfigStructureVO> roots = new ArrayList<>();
// 1、初始化节点
for (OrderComponentListRespDTO node : list) {
AssemblyConfigStructureVO vo = new AssemblyConfigStructureVO();
vo.setName(node.getName());
vo.setChildren(new ArrayList<>());
map.put(node.getId(), vo);
}
// 2、组装树 + 设置 sourceComponentId
for (OrderComponentListRespDTO node : list) {
AssemblyConfigStructureVO vo = map.get(node.getId());
if (node.getPid() == 0) {
vo.setSourceComponentId(node.getId());
roots.add(vo);
} else {
AssemblyConfigStructureVO parent = map.get(node.getPid());
if (parent != null) parent.getChildren().add(vo);
}
}
// 3、递归排序 + 生成 hash
for (AssemblyConfigStructureVO root : roots) {
computeHashRecursively(root);
}
return roots;
}
/**
* 递归排序 children + 生成结构 hash
*
* @param node
*/
private void computeHashRecursively(AssemblyConfigStructureVO node) {
List<AssemblyConfigStructureVO> children = node.getChildren();
if (children != null && !children.isEmpty()) {
// 按 name 排序保证 hash 稳定
children.sort(Comparator.comparing(AssemblyConfigStructureVO::getName));
// 递归处理
for (AssemblyConfigStructureVO child : children) {
computeHashRecursively(child);
}
}
// 生成结构字符串并 hash
String structureStr = buildStructureString(node);
node.setStructureHash(DigestUtil.sha256Hex(structureStr));
// 默认是加工的
node.setProcess(true);
}
/**
* 构建结构字符串(name + children
*
* @param node
* @return
*/
private String buildStructureString(AssemblyConfigStructureVO node) {
StringBuilder sb = new StringBuilder();
sb.append(node.getName());
List<AssemblyConfigStructureVO> children = node.getChildren();
if (children != null && !children.isEmpty()) {
sb.append("(");
for (AssemblyConfigStructureVO child : children) {
sb.append(buildStructureString(child));
}
sb.append(")");
}
return sb.toString();
}
@Override
public List<AssemblyConfigListRespVO> getOrgAssemblyConfigList() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
List<AssemblyConfigDO> list = assemblyConfigMapper.selectList(
new LambdaQueryWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.select(AssemblyConfigDO::getId, AssemblyConfigDO::getComponentName, AssemblyConfigDO::getStatus)
);
if (list.isEmpty()) {
return Collections.emptyList();
}
return BeanUtil.copyToList(list, AssemblyConfigListRespVO.class);
}
/**
* 查询部件设置
*
* @param configId
* @param organId
* @return
*/
private AssemblyConfigDO getById(Long configId, Long organId) {
AssemblyConfigDO assemblyConfigDO = assemblyConfigMapper.selectOne(
new LambdaQueryWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getId, configId)
.eq(AssemblyConfigDO::getOrganId, organId)
);
AssertUtils.notEmpty(assemblyConfigDO, ASSEMBLY_CONFIG_NOT_EXIST);
return assemblyConfigDO;
}
@Override
public void doConfig(Long configId) {
Long organId = SecurityFrameworkUtils.getUserOrganId();
// 1、校验本身
AssemblyConfigDO assemblyConfigDO = getById(configId, organId);
// 2、校验本身以外是否还有重名的顶级部件设置
boolean exists = assemblyConfigMapper.exists(new LambdaQueryWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getComponentName, assemblyConfigDO.getComponentName())
.ne(AssemblyConfigDO::getId, configId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.eq(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.CONFIGURED.getStatus())
);
AssertUtils.isTrue(exists, ASSEMBLY_CONFIG_DO_CONFIG_EXIST);
// 3、更新状态
assemblyConfigMapper.update(new LambdaUpdateWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getId, configId)
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.set(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.CONFIGURED.getStatus())
);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void coverConfig(Long configId) {
Long organId = SecurityFrameworkUtils.getUserOrganId();
// 1、校验本身
AssemblyConfigDO assemblyConfigDO = getById(configId, organId);
// 2、校验要覆盖的目标是否存在
boolean exists = assemblyConfigMapper.exists(new LambdaQueryWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getComponentName, assemblyConfigDO.getComponentName())
.ne(AssemblyConfigDO::getId, configId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.eq(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.CONFIGURED.getStatus())
);
AssertUtils.isFalse(exists, ASSEMBLY_CONFIG_COVER_TARGET_NOT_EXIST);
// 3、把原来同名的改为导入
assemblyConfigMapper.update(new LambdaUpdateWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getComponentName, assemblyConfigDO.getComponentName())
.ne(AssemblyConfigDO::getId, configId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.eq(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.CONFIGURED.getStatus())
.set(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.IMPORT.getStatus())
);
// 4、更新状态
assemblyConfigMapper.update(new LambdaUpdateWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getId, configId)
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.set(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.CONFIGURED.getStatus())
);
}
@Override
public void newConfig(Long configId, String name) {
Long organId = SecurityFrameworkUtils.getUserOrganId();
// 1、校验本身
getById(configId, organId);
// 2、校验新的名字是否已有存在的部件
boolean exists = assemblyConfigMapper.exists(new LambdaQueryWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getComponentName, name)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.eq(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.CONFIGURED.getStatus())
);
AssertUtils.isTrue(exists, ASSEMBLY_CONFIG_NEW_CONFIG_NAME_EXIST, name);
// 4、更新状态和名称
assemblyConfigMapper.update(new LambdaUpdateWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getId, configId)
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.set(AssemblyConfigDO::getComponentName, name)
.set(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.CONFIGURED.getStatus())
);
}
@Override
public void removeConfigured(Long configId) {
Long organId = SecurityFrameworkUtils.getUserOrganId();
// 1、校验本身
AssemblyConfigDO assemblyConfigDO = getById(configId, organId);
// 2、校验状态
AssertUtils.notEquals(assemblyConfigDO.getStatus(), AssemblyConfigStatusEnum.CONFIGURED.getStatus(), ASSEMBLY_CONFIG_REMOVE_NOT_EXIST);
// 3、更新状态
assemblyConfigMapper.update(new LambdaUpdateWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getId, configId)
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.set(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.IMPORT.getStatus())
);
}
@Override
public void saveConfig(AssemblyConfigSaveReqVO reqVO) {
Long organId = SecurityFrameworkUtils.getUserOrganId();
// 1、校验本身
AssemblyConfigDO assemblyConfigDO = getById(reqVO.getId(), organId);
// 2、更新hash和json
AssemblyConfigSaveStructureReqVO config = reqVO.getConfig();
AssemblyConfigStructureVO structureVO = BeanUtil.toBean(config, AssemblyConfigStructureVO.class);
computeHashRecursively(structureVO);
String structureHash = structureVO.getStructureHash();
assemblyConfigMapper.update(new LambdaUpdateWrapper<AssemblyConfigDO>()
.eq(AssemblyConfigDO::getId, assemblyConfigDO.getId())
.eq(AssemblyConfigDO::getOrganId, organId)
.eq(AssemblyConfigDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
.eq(AssemblyConfigDO::getStatus, AssemblyConfigStatusEnum.CONFIGURED.getStatus())
.set(AssemblyConfigDO::getStructureHash, structureHash)
.set(AssemblyConfigDO::getStructureJson, JsonUtils.zipString(JsonUtils.toJsonString(config)))
);
}
}
@@ -99,4 +99,9 @@ aj.captcha.6201=get接口请求次数超限,请稍后再试!
aj.captcha.6206=无效请求,请重新获取验证码。
aj.captcha.6202=接口验证失败数过多,请稍后再试。
aj.captcha.6204=check接口请求次数超限,请稍后再试!
aj.captcha.6205=verify请求次数超限。
aj.captcha.6205=verify请求次数超限。
assembly.config.import.orderIds.notEmpty=生产单号列表不能为空
assembly.config.import.orderIds.size=生产单号列表长度不能超过100
assembly.config.save.id.notNull=装备设置编号不能为空
assembly.config.save.structure.config.notNull=装备设置结构配置不能为空
@@ -100,4 +100,9 @@ aj.captcha.6201=get 接口請求次數超限,請稍後再試!
aj.captcha.6206=無效請求,請重新獲取驗證碼。
aj.captcha.6202=接口驗證失敗次數過多,請稍後再試。
aj.captcha.6204=check 接口請求次數超限,請稍後再試!
aj.captcha.6205=verify 請求次數超限。
aj.captcha.6205=verify 請求次數超限。
assembly.config.import.orderIds.notEmpty=生產單號清單不能為空
assembly.config.import.orderIds.size=生產單號清單長度不能超過100
assembly.config.save.id.notNull=裝備設定編號不能為空
assembly.config.save.structure.config.notNull=裝備設定結構配寘不能為空
@@ -99,4 +99,9 @@ aj.captcha.6201=GET request limit exceeded, please try again later!
aj.captcha.6206=Invalid request, please try again
aj.captcha.6202=Too many verification failures, please try again later
aj.captcha.6204=CHECK request limit exceeded, please try again later!
aj.captcha.6205=VERIFY request limit exceeded!
aj.captcha.6205=VERIFY request limit exceeded!
assembly.config.import.orderIds.notEmpty=The production order number list cannot be empty
assembly.config.import.orderIds.size=The length of the production order number list cannot exceed 100
assembly.config.save.id.notNull=Assembly setting number cannot be empty
assembly.config.save.structure.config.notNull=Assembly setting structure configuration cannot be empty
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long