1、新增贴皮未分解按订单/按材质查询主数据,查询未分解板件列表接口;2、新增贴皮已分解按订单/按材质查询主数据,查询已分解板件列表接口;3、新增板件贴皮分解接口;4、新增重选贴皮接口;

This commit is contained in:
gaoqr
2026-07-16 18:06:21 +08:00
parent 1842131438
commit 4d52264e6f
33 changed files with 2198 additions and 1 deletions
@@ -176,6 +176,12 @@ public class ErrorCodeConstants {
public static final ErrorCode VENEER_IMPORT_VENEER_NO_DUPLICATE = new ErrorCode(1_003_009_014, "veneer.import.veneer.no.duplicate"); public static final ErrorCode VENEER_IMPORT_VENEER_NO_DUPLICATE = new ErrorCode(1_003_009_014, "veneer.import.veneer.no.duplicate");
public static final ErrorCode VENEER_IMPORT_VENEER_NO_FORMAT_ERROR = new ErrorCode(1_003_009_015, "veneer.import.veneer.no.format.error"); public static final ErrorCode VENEER_IMPORT_VENEER_NO_FORMAT_ERROR = new ErrorCode(1_003_009_015, "veneer.import.veneer.no.format.error");
public static final ErrorCode VENEER_IMPORT_PRODUCT_LEVEL_ERROR = new ErrorCode(1_003_009_016, "veneer.import.product.level.error"); public static final ErrorCode VENEER_IMPORT_PRODUCT_LEVEL_ERROR = new ErrorCode(1_003_009_016, "veneer.import.product.level.error");
public static final ErrorCode VENEER_DECOMPOSE_SCOPE_REQUIRED = new ErrorCode(1_003_009_017, "veneer.decompose.scope.required");
public static final ErrorCode VENEER_DECOMPOSE_SIDE_REQUIRED = new ErrorCode(1_003_009_018, "veneer.decompose.side.required");
public static final ErrorCode VENEER_DECOMPOSE_PLATE_STATUS_CHANGED = new ErrorCode(1_003_009_019, "veneer.decompose.plate.status.changed");
public static final ErrorCode VENEER_RESELECT_RECORD_REQUIRED = new ErrorCode(1_003_009_020, "veneer.reselect.record.required");
public static final ErrorCode VENEER_RESELECT_SOURCE_REQUIRED = new ErrorCode(1_003_009_021, "veneer.reselect.source.required");
public static final ErrorCode VENEER_RESELECT_RECORD_STATUS_CHANGED = new ErrorCode(1_003_009_022, "veneer.reselect.record.status.changed");
//=========== 部件管理 1-003-010-000 ============ //=========== 部件管理 1-003-010-000 ============
public static final ErrorCode ORDER_COMPONENT_NOT_EXIST = new ErrorCode(1_003_010_000, "order.component.not.exist"); public static final ErrorCode ORDER_COMPONENT_NOT_EXIST = new ErrorCode(1_003_010_000, "order.component.not.exist");
@@ -0,0 +1,109 @@
package com.cf.imes.module.executor.controller.admin.veneer;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeCreateReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlatePageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlateRespVO;
import com.cf.imes.module.executor.service.veneer.VeneerDecomposeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
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.RestController;
import java.util.List;
import static com.cf.imes.framework.common.pojo.CommonResult.success;
/**
* 贴皮分解接口。
*/
@Tag(name = "生产管理 - 贴皮分解")
@RestController
@RequestMapping("/executor/veneer-decompose")
@Validated
public class VeneerDecomposeController {
@Resource
private VeneerDecomposeService veneerDecomposeService;
/**
* 分页查询存在未贴皮分解板件的订单。
*
* @param req 分页及筛选条件
* @return 订单分页列表
*/
@PostMapping("/order/page")
@Operation(summary = "获取贴皮分解订单分页列表")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<PageResult<VeneerDecomposeOrderRespVO>> getOrderPage(
@Valid @RequestBody VeneerDecomposeOrderPageReqVO req) {
return success(veneerDecomposeService.getOrderPage(req));
}
/**
* 分页查询存在未贴皮分解板件的板材。
*
* @param req 分页及筛选条件
* @return 板材分页列表
*/
@PostMapping("/goods/page")
@Operation(summary = "获取贴皮分解板材分页列表")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<PageResult<VeneerDecomposeGoodsRespVO>> getGoodsPage(
@Valid @RequestBody VeneerDecomposeGoodsPageReqVO req) {
return success(veneerDecomposeService.getGoodsPage(req));
}
/**
* 按订单查询未贴皮分解板件列表。
*
* @param req 查询条件,必须包含订单ID列表
* @return 板件列表
*/
@PostMapping("/order/plate/page")
@Operation(summary = "获取订单下待贴皮分解板件列表")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<List<VeneerDecomposePlateRespVO>> getOrderPlateList(
@Valid @RequestBody VeneerDecomposePlatePageReqVO req) {
return success(veneerDecomposeService.getOrderPlateList(req));
}
/**
* 按板材查询未贴皮分解板件列表。
*
* @param req 查询条件,必须包含商品编码列表
* @return 板件列表
*/
@PostMapping("/goods/plate/page")
@Operation(summary = "获取材质下待贴皮分解板件列表")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<List<VeneerDecomposePlateRespVO>> getGoodsPlateList(
@Valid @RequestBody VeneerDecomposePlatePageReqVO req) {
return success(veneerDecomposeService.getGoodsPlateList(req));
}
/**
* 将选中的未分解原板件分解为 A 面和/或 B 面贴皮记录。
*
* @param req 分解参数
* @return 是否成功
*/
@PostMapping("/decompose")
@Operation(summary = "执行贴皮分解")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<Boolean> decompose(@Valid @RequestBody VeneerDecomposeCreateReqVO req) {
veneerDecomposeService.decompose(req);
return success(true);
}
}
@@ -0,0 +1,110 @@
package com.cf.imes.module.executor.controller.admin.veneer;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManagePlateListReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManagePlateRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageReselectReqVO;
import com.cf.imes.module.executor.service.veneer.VeneerManageService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
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.RestController;
import java.util.List;
import static com.cf.imes.framework.common.pojo.CommonResult.success;
/**
* 贴皮管理接口。
*/
@Tag(name = "生产管理 - 贴皮管理")
@RestController
@RequestMapping("/executor/veneer-manage")
@Validated
public class VeneerManageController {
@Resource
private VeneerManageService veneerManageService;
/**
* 分页查询存在已分解贴皮板件的订单。
*
* @param req 分页及筛选条件
* @return 订单分页列表
*/
@PostMapping("/order/page")
@Operation(summary = "获取贴皮管理订单分页列表")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<PageResult<VeneerManageOrderRespVO>> getOrderPage(
@Valid @RequestBody VeneerManageOrderPageReqVO req) {
return success(veneerManageService.getOrderPage(req));
}
/**
* 分页查询存在已分解贴皮板件的板材。
*
* @param req 分页及筛选条件
* @return 板材分页列表
*/
@PostMapping("/goods/page")
@Operation(summary = "获取贴皮管理板材分页列表")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<PageResult<VeneerManageGoodsRespVO>> getGoodsPage(
@Valid @RequestBody VeneerManageGoodsPageReqVO req) {
return success(veneerManageService.getGoodsPage(req));
}
/**
* 按订单查询已分解板件贴皮列表。
*
* @param req 查询条件,必须包含订单ID列表
* @return 已分解板件贴皮列表
*/
@PostMapping("/order/plate/list")
@Operation(summary = "按订单获取已分解板件贴皮列表")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<List<VeneerManagePlateRespVO>> getOrderPlateList(
@Valid @RequestBody VeneerManagePlateListReqVO req) {
return success(veneerManageService.getOrderPlateList(req));
}
/**
* 按板材查询已分解板件贴皮列表。
*
* @param req 查询条件,必须包含板材商品编码列表
* @return 已分解板件贴皮列表
*/
@PostMapping("/goods/plate/list")
@Operation(summary = "按板材获取已分解板件贴皮列表")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<List<VeneerManagePlateRespVO>> getGoodsPlateList(
@Valid @RequestBody VeneerManagePlateListReqVO req) {
return success(veneerManageService.getGoodsPlateList(req));
}
/**
* 批量为已分解板件贴皮重新选择贴皮库数据。
*
* @param req 板件贴皮记录ID及新贴皮库ID
* @return 是否成功
*/
@PostMapping("/plate/reselect")
@Operation(summary = "批量重选贴皮")
@PreAuthorize("@ss.hasPermission('unplannedOrders:query')")
public CommonResult<Boolean> reselectVeneer(
@Valid @RequestBody VeneerManageReselectReqVO req) {
veneerManageService.reselectVeneer(req);
return success(true);
}
}
@@ -0,0 +1,49 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import cn.hutool.core.collection.CollUtil;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* 贴皮分解请求参数。
*/
@Data
public class VeneerDecomposeCreateReqVO {
@Schema(description = "订单ID列表;非空时按订单范围分解")
private List<Long> orderIds;
@Schema(description = "板材商品编码;orderIds为空时必填")
private String goodsId;
@Schema(description = "原板件编号列表", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{veneer.decompose.plate.no.required}")
private List<String> plateNos;
@Schema(description = "A面贴皮库ID")
@JsonProperty("aVeneerId")
private Long aVeneerId;
@Schema(description = "B面贴皮库ID")
@JsonProperty("bVeneerId")
private Long bVeneerId;
@Schema(description = "外扩余量(mm),默认10")
@DecimalMin(value = "0", message = "{veneer.decompose.outer.margin.min}")
private BigDecimal outerMargin = new BigDecimal("10");
/**
* 判断是否按订单入口提交。
*
* @return {@code true} 表示按订单范围分解,{@code false} 表示按板材范围分解
*/
public boolean isByOrder() {
return CollUtil.isNotEmpty(orderIds);
}
}
@@ -0,0 +1,29 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import com.cf.imes.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 贴皮分解材质分页查询请求参数。
*/
@Data
public class VeneerDecomposeGoodsPageReqVO extends PageParam {
@Schema(description = "板材名称")
private String goodsName;
@Schema(description = "商品编号")
private String goodsId;
@Schema(description = "材质")
private String material;
@Schema(description = "颜色")
private String color;
@Schema(description = "厚度")
private BigDecimal thickness;
}
@@ -0,0 +1,34 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 贴皮分解板材分页响应参数。
*/
@Data
public class VeneerDecomposeGoodsRespVO {
@Schema(description = "板材名称")
private String goodsName;
@Schema(description = "商品编码")
private String goodsId;
@Schema(description = "材质")
private String material;
@Schema(description = "颜色")
private String color;
@Schema(description = "厚度")
private BigDecimal thickness;
@Schema(description = "总片数")
private Integer num;
@Schema(description = "总平方数")
private BigDecimal area;
}
@@ -0,0 +1,33 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import com.cf.imes.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static com.cf.imes.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
/**
* 贴皮分解订单分页查询请求参数。
*/
@Data
public class VeneerDecomposeOrderPageReqVO extends PageParam {
@Schema(description = "订单号")
private String orderId;
@Schema(description = "自定义单号")
private String customOrderNo;
@Schema(description = "客户")
private String customer;
@Schema(description = "地址")
private String address;
@Schema(description = "订单日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate[] orderDate;
}
@@ -0,0 +1,43 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import static com.cf.imes.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
import static com.cf.imes.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
/**
* 贴皮分解订单分页响应参数。
*/
@Data
public class VeneerDecomposeOrderRespVO {
@Schema(description = "订单号")
private Long orderId;
@Schema(description = "自定义单号")
private String customOrderNo;
@Schema(description = "订单类型")
private Integer orderType;
@Schema(description = "客户")
private String customer;
@Schema(description = "地址")
private String address;
@Schema(description = "片数")
private Integer num;
@Schema(description = "平方数")
private BigDecimal area;
@Schema(description = "订单日期")
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT)
private LocalDateTime orderDate;
}
@@ -0,0 +1,25 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 待贴皮分解板件列表查询参数。
*/
@Data
public class VeneerDecomposePlatePageReqVO {
@Schema(description = "订单ID列表")
private List<Long> orderIds;
@Schema(description = "房间ID列表")
private List<Long> roomIds;
@Schema(description = "柜体ID列表")
private List<Long> bodyIds;
@Schema(description = "板材商品编码列表")
private List<String> goodsIds;
}
@@ -0,0 +1,50 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 待贴皮分解板件响应参数。
*/
@Data
public class VeneerDecomposePlateRespVO {
/**
* 板件主键,仅用于 Service 层按板件去重,不返回前端。
*/
@JsonIgnore
private Long plateId;
@Schema(description = "房名")
private String roomName;
@Schema(description = "柜名")
private String bodyName;
@Schema(description = "板件编号")
private String plateNo;
@Schema(description = "材质")
private String material;
@Schema(description = "颜色")
private String color;
@Schema(description = "板名称")
private String plateName;
@Schema(description = "长度")
private BigDecimal length;
@Schema(description = "宽度")
private BigDecimal width;
@Schema(description = "厚度")
private BigDecimal thickness;
@Schema(description = "面积")
private BigDecimal area;
}
@@ -0,0 +1,29 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import com.cf.imes.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 贴皮管理板材分页查询请求参数。
*/
@Data
public class VeneerManageGoodsPageReqVO extends PageParam {
@Schema(description = "板材名称")
private String goodsName;
@Schema(description = "商品编码")
private String goodsId;
@Schema(description = "材质")
private String material;
@Schema(description = "颜色")
private String color;
@Schema(description = "厚度")
private BigDecimal thickness;
}
@@ -0,0 +1,34 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 贴皮管理板材分页响应参数。
*/
@Data
public class VeneerManageGoodsRespVO {
@Schema(description = "板材名称")
private String goodsName;
@Schema(description = "商品编码")
private String goodsId;
@Schema(description = "材质")
private String material;
@Schema(description = "颜色")
private String color;
@Schema(description = "厚度")
private BigDecimal thickness;
@Schema(description = "总片数")
private Integer num;
@Schema(description = "总平方数")
private BigDecimal area;
}
@@ -0,0 +1,33 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import com.cf.imes.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static com.cf.imes.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
/**
* 贴皮管理订单分页查询请求参数。
*/
@Data
public class VeneerManageOrderPageReqVO extends PageParam {
@Schema(description = "订单号")
private String orderId;
@Schema(description = "自定义单号")
private String customOrderNo;
@Schema(description = "客户")
private String customer;
@Schema(description = "地址")
private String address;
@Schema(description = "订单日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate[] orderDate;
}
@@ -0,0 +1,38 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 贴皮管理订单分页响应参数。
*/
@Data
public class VeneerManageOrderRespVO {
@Schema(description = "订单号")
private Long orderId;
@Schema(description = "自定义单号")
private String customOrderNo;
@Schema(description = "订单类型")
private String orderType;
@Schema(description = "客户")
private String customer;
@Schema(description = "地址")
private String address;
@Schema(description = "片数")
private Integer num;
@Schema(description = "平方数")
private BigDecimal area;
@Schema(description = "订单日期")
private LocalDateTime orderDate;
}
@@ -0,0 +1,19 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 已分解板件贴皮列表查询参数。
*/
@Data
public class VeneerManagePlateListReqVO {
@Schema(description = "订单ID列表")
private List<Long> orderIds;
@Schema(description = "板材商品编码列表")
private List<String> goodsIds;
}
@@ -0,0 +1,49 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 已分解板件贴皮响应参数。
*/
@Data
public class VeneerManagePlateRespVO {
@Schema(description = "板件贴皮记录ID")
private Long id;
@Schema(description = "生成贴皮编号")
private String veneerNo;
@Schema(description = "原板件编号")
private String plateNo;
@Schema(description = "原板件名称")
private String plateName;
@Schema(description = "原板件长(mm)")
private BigDecimal length;
@Schema(description = "原板件宽(mm)")
private BigDecimal width;
@Schema(description = "原板件厚(mm)")
private BigDecimal thickness;
@Schema(description = "贴皮商品号")
private String sourceVeneerNo;
@Schema(description = "贴皮名称")
private String veneerName;
@Schema(description = "产品等级")
private Integer productLevel;
@Schema(description = "颜色")
private String color;
@Schema(description = "材质")
private String material;
}
@@ -0,0 +1,19 @@
package com.cf.imes.module.executor.controller.admin.veneer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 批量重选贴皮请求参数。
*/
@Data
public class VeneerManageReselectReqVO {
@Schema(description = "板件贴皮记录ID列表", requiredMode = Schema.RequiredMode.REQUIRED)
private List<Long> ids;
@Schema(description = "重新选择的贴皮库ID", requiredMode = Schema.RequiredMode.REQUIRED)
private Long veneerId;
}
@@ -108,6 +108,11 @@ public class GoodsDO extends BaseDO {
*/ */
private Integer plannedPlateNum; private Integer plannedPlateNum;
/**
* 已分解贴皮板件数量
*/
private Integer decomposedVeneerPlateNum;
/** /**
* 板件总面积 * 板件总面积
*/ */
@@ -142,6 +142,11 @@ public class OrderDO extends BaseDO {
*/ */
private Integer plannedPlateNum; private Integer plannedPlateNum;
/**
* 已分解贴皮板件数量
*/
private Integer decomposedVeneerPlateNum;
/** /**
* 板件总面积 * 板件总面积
*/ */
@@ -0,0 +1,130 @@
package com.cf.imes.module.executor.dal.dataobject.veneer;
import com.baomidou.mybatisplus.annotation.KeySequence;
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.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 订单板件贴皮记录 DO。
*/
@TableName("order_plate_veneer")
@KeySequence("order_plate_veneer_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderPlateVeneerDO extends BaseDO {
/**
* 主键。
*/
private Long id;
/**
* 组织ID,也是 MyCat 分片键。
*/
private Long organId;
/**
* 订单主键。
*/
private Long orderId;
/**
* 订单板材主键,对应 {@code order_goods.id}。
*/
private Long orderGoodsId;
/**
* 原板件主键,对应 {@code order_plate.id}。
*/
private Long orderPlateId;
/**
* 原板件编号。
*/
private String plateNo;
/**
* 原板件名称。
*/
private String plateName;
/**
* 原板件长度,单位:mm。
*/
private BigDecimal plateLength;
/**
* 原板件宽度,单位:mm。
*/
private BigDecimal plateWidth;
/**
* 原板件厚度,单位:mm。
*/
private BigDecimal plateThickness;
/**
* 原板件排版面:0-正面,1-反面,2-随意面。
*/
private Integer holeArrange;
/**
* 贴皮逻辑面:A-A面,B-B面。
*/
private String veneerSide;
/**
* 实际板件面:0-正面,1-反面。
*/
private Integer plateSurface;
/**
* 分解后生成的贴皮编号,规则为原板件编号加 A/B 后缀。
*/
private String veneerNo;
/**
* 贴皮外扩余量,单位:mm。
*/
private BigDecimal outerMargin;
/**
* 来源贴皮库记录主键,对应 {@code veneers.id}。
*/
private Long sourceVeneerId;
/**
* 贴皮商品编号快照。
*/
private String sourceVeneerNo;
/**
* 贴皮名称快照。
*/
private String veneerName;
/**
* 产品等级快照。
*/
private Integer productLevel;
/**
* 颜色快照。
*/
private String color;
/**
* 材质快照。
*/
private String material;
}
@@ -0,0 +1,24 @@
package com.cf.imes.module.executor.dal.dataobject.veneer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 已分解贴皮板件数量统计结果。
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class VeneerDecomposedPlateCountDO {
/**
* 订单ID或 {@code order_goods} 主键。
*/
private Long targetId;
/**
* 从数据库重新统计的已分解板件数量。
*/
private Integer decomposedPlateNum;
}
@@ -0,0 +1,12 @@
package com.cf.imes.module.executor.dal.mysql.veneer;
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
import com.cf.imes.module.executor.dal.dataobject.veneer.OrderPlateVeneerDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 订单板件贴皮记录 Mapper。
*/
@Mapper
public interface OrderPlateVeneerMapper extends BaseMapperX<OrderPlateVeneerDO> {
}
@@ -0,0 +1,120 @@
package com.cf.imes.module.executor.dal.mysql.veneer;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeCreateReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlatePageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlateRespVO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDecomposedPlateCountDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
/**
* 贴皮分解 Mapper。
*/
@Mapper
public interface VeneerDecomposeMapper {
/**
* 分页查询存在未完成贴皮分解板件的根订单ID。
*
* @param page 分页参数
* @param req 订单查询条件
* @param orderDateTime 完整订单日期时间范围
* @return 根订单ID分页结果
*/
IPage<Long> selectRootOrderIdList(@Param("page") IPage<VeneerDecomposeOrderRespVO> page,
@Param("req") VeneerDecomposeOrderPageReqVO req,
@Param("orderDateTime") LocalDateTime[] orderDateTime);
/**
* 根据根订单ID查询订单及子订单信息。
*
* @param page 分页参数
* @param rootIds 根订单ID列表
* @return 订单分页结果
*/
IPage<VeneerDecomposeOrderRespVO> selectOrderList(@Param("page") IPage<VeneerDecomposeOrderRespVO> page,
@Param("rootIds") List<Long> rootIds);
/**
* 分页查询存在未完成贴皮分解板件的材质。
*
* @param page 分页参数
* @param req 材质查询条件
* @return 材质分页结果
*/
IPage<VeneerDecomposeGoodsRespVO> selectGoodsPage(@Param("page") IPage<VeneerDecomposeGoodsRespVO> page,
@Param("req") VeneerDecomposeGoodsPageReqVO req);
/**
* 按订单查询未贴皮分解板件原始列表。
* 同一板件可能因多个加工组返回多条记录,由 Service 层按板件主键去重。
*
* @param req 查询条件
* @return 板件原始列表
*/
List<VeneerDecomposePlateRespVO> selectOrderPlateList(
@Param("req") VeneerDecomposePlatePageReqVO req);
/**
* 按板材查询未贴皮分解板件原始列表。
* 同一板件可能因多个加工组返回多条记录,由 Service 层按板件主键去重。
*
* @param req 查询条件
* @return 板件原始列表
*/
List<VeneerDecomposePlateRespVO> selectGoodsPlateList(
@Param("req") VeneerDecomposePlatePageReqVO req);
/**
* 查询本次可分解的原板件。
*
* @param req 分解请求参数
* @param plateNos 本批待查询的板件编号
* @return 未分解原板件
*/
List<PlateDO> selectUndecomposedPlateList(@Param("req") VeneerDecomposeCreateReqVO req,
@Param("plateNos") List<String> plateNos);
/**
* 按固定顺序锁定受影响订单,串行化同一订单的分解与计数重算。
*
* @param orderIds 订单ID列表
* @return 已锁定订单ID列表
*/
List<Long> selectOrderIdForUpdate(@Param("orderIds") List<Long> orderIds);
/**
* 将指定原板件标记为已分解。
*
* @param plateIds 原板件ID列表
* @return 更新行数
*/
int updatePlateDecomposed(@Param("plateIds") List<Long> plateIds);
/**
* 按订单重新统计已分解贴皮板件数量。
*
* @param orderIds 订单ID列表
* @return 订单及其已分解板件数量
*/
List<VeneerDecomposedPlateCountDO> selectOrderDecomposedPlateCount(
@Param("orderIds") List<Long> orderIds);
/**
* 按订单板材重新统计已分解贴皮板件数量。
*
* @param orderGoodsIds {@code order_goods} 主键列表
* @return 订单板材及其已分解板件数量
*/
List<VeneerDecomposedPlateCountDO> selectGoodsDecomposedPlateCount(
@Param("orderGoodsIds") List<Long> orderGoodsIds);
}
@@ -0,0 +1,68 @@
package com.cf.imes.module.executor.dal.mysql.veneer;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManagePlateRespVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
/**
* 贴皮管理 Mapper。
*/
@Mapper
public interface VeneerManageMapper {
/**
* 分页查询存在已分解贴皮板件的根订单 ID。
*
* @param page 分页参数
* @param req 订单查询条件
* @param orderDateTime 完整订单日期时间范围
* @return 根订单 ID 分页结果
*/
IPage<Long> selectRootOrderIdList(@Param("page") IPage<VeneerManageOrderRespVO> page,
@Param("req") VeneerManageOrderPageReqVO req,
@Param("orderDateTime") LocalDateTime[] orderDateTime);
/**
* 根据根订单 ID 查询订单及子订单信息。
*
* @param page 分页参数
* @param rootIds 根订单 ID 列表
* @return 订单列表
*/
IPage<VeneerManageOrderRespVO> selectOrderList(@Param("page") IPage<VeneerManageOrderRespVO> page,
@Param("rootIds") List<Long> rootIds);
/**
* 分页查询存在已分解贴皮板件的板材。
*
* @param page 分页参数
* @param req 板材查询条件
* @return 板材分页结果
*/
IPage<VeneerManageGoodsRespVO> selectGoodsPage(@Param("page") IPage<VeneerManageGoodsRespVO> page,
@Param("req") VeneerManageGoodsPageReqVO req);
/**
* 按订单查询已分解板件贴皮列表。
*
* @param orderIds 订单ID列表
* @return 已分解板件贴皮列表
*/
List<VeneerManagePlateRespVO> selectOrderPlateList(@Param("orderIds") List<Long> orderIds);
/**
* 按板材商品编码查询已分解板件贴皮列表。
*
* @param goodsIds 板材商品编码列表
* @return 已分解板件贴皮列表
*/
List<VeneerManagePlateRespVO> selectGoodsPlateList(@Param("goodsIds") List<String> goodsIds);
}
@@ -0,0 +1,57 @@
package com.cf.imes.module.executor.service.veneer;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeCreateReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlatePageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlateRespVO;
import java.util.List;
/**
* 贴皮分解 Service。
*/
public interface VeneerDecomposeService {
/**
* 查询待贴皮分解订单分页列表。
*
* @param req 订单查询参数
* @return 订单分页结果
*/
PageResult<VeneerDecomposeOrderRespVO> getOrderPage(VeneerDecomposeOrderPageReqVO req);
/**
* 查询待贴皮分解材质分页列表。
*
* @param req 材质查询参数
* @return 材质分页结果
*/
PageResult<VeneerDecomposeGoodsRespVO> getGoodsPage(VeneerDecomposeGoodsPageReqVO req);
/**
* 按订单查询未贴皮分解板件列表。
*
* @param req 查询条件,必须包含订单 ID 列表
* @return 去重后的板件列表
*/
List<VeneerDecomposePlateRespVO> getOrderPlateList(VeneerDecomposePlatePageReqVO req);
/**
* 按板材查询未贴皮分解板件列表。
*
* @param req 查询条件,必须包含商品编码列表
* @return 去重后的板件列表
*/
List<VeneerDecomposePlateRespVO> getGoodsPlateList(VeneerDecomposePlatePageReqVO req);
/**
* 将原板件分解为 A 面和/或 B 面贴皮记录。
*
* @param req 分解参数
*/
void decompose(VeneerDecomposeCreateReqVO req);
}
@@ -0,0 +1,396 @@
package com.cf.imes.module.executor.service.veneer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.date.LocalDateTimeUtils;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeCreateReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlatePageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlateRespVO;
import com.cf.imes.module.executor.dal.dataobject.goods.GoodsDO;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.OrderPlateVeneerDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDecomposedPlateCountDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDO;
import com.cf.imes.module.executor.dal.mysql.goods.GoodsMapper;
import com.cf.imes.module.executor.dal.mysql.order.OrderMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.OrderPlateVeneerMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerDecomposeMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.cf.imes.framework.common.pojo.PageParam.PAGE_SIZE_NONE;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.GOODS_PLATE_UPDATE_CONCURRENCY_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_PLATE_UPDATE_CONCURRENCY_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_PLATE_STATUS_CHANGED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_SCOPE_REQUIRED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_DECOMPOSE_SIDE_REQUIRED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_NOT_EXIST;
/**
* 贴皮分解 Service 实现。
*/
@Service
public class VeneerDecomposeServiceImpl implements VeneerDecomposeService {
/**
* 板件查询、状态更新及贴皮记录插入的单批处理数量。
*/
private static final int DECOMPOSE_BATCH_SIZE = 1000;
/**
* 订单及订单板材分解数量重新统计的单批处理数量。
*/
private static final int DECOMPOSE_STAT_BATCH_SIZE = 100;
/**
* 贴皮逻辑 A 面。
*/
private static final String VENEER_SIDE_A = "A";
/**
* 贴皮逻辑 B 面。
*/
private static final String VENEER_SIDE_B = "B";
/**
* WebCAD 反面排版标识。
*/
private static final int HOLE_ARRANGE_REVERSE = 1;
/**
* 板件正面标识。
*/
private static final int PLATE_SURFACE_FRONT = 0;
/**
* 板件反面标识。
*/
private static final int PLATE_SURFACE_BACK = 1;
@Resource
private VeneerDecomposeMapper veneerDecomposeMapper;
@Resource
private OrderPlateVeneerMapper orderPlateVeneerMapper;
@Resource
private VeneerMapper veneerMapper;
@Resource
private OrderMapper orderMapper;
@Resource
private GoodsMapper goodsMapper;
@Override
public PageResult<VeneerDecomposeOrderRespVO> getOrderPage(VeneerDecomposeOrderPageReqVO req) {
PageDTO<VeneerDecomposeOrderRespVO> page = new PageDTO<>(req.getPageNo(), req.getPageSize());
IPage<Long> rootPage = veneerDecomposeMapper.selectRootOrderIdList(
page, req, LocalDateTimeUtils.generateTimeSection(req.getOrderDate()));
List<Long> rootIds = rootPage.getRecords();
if (CollUtil.isEmpty(rootIds)) {
return new PageResult<>();
}
IPage<VeneerDecomposeOrderRespVO> result = veneerDecomposeMapper.selectOrderList(
new PageDTO<>(req.getPageNo(), PAGE_SIZE_NONE), rootIds);
return new PageResult<>(result.getRecords(), rootPage.getTotal());
}
@Override
public PageResult<VeneerDecomposeGoodsRespVO> getGoodsPage(VeneerDecomposeGoodsPageReqVO req) {
IPage<VeneerDecomposeGoodsRespVO> result = veneerDecomposeMapper.selectGoodsPage(
new PageDTO<>(req.getPageNo(), req.getPageSize()), req);
return new PageResult<>(result.getRecords(), result.getTotal());
}
@Override
public List<VeneerDecomposePlateRespVO> getOrderPlateList(VeneerDecomposePlatePageReqVO req) {
if (CollUtil.isEmpty(req.getOrderIds())) {
return List.of();
}
return distinctPlate(veneerDecomposeMapper.selectOrderPlateList(req));
}
@Override
public List<VeneerDecomposePlateRespVO> getGoodsPlateList(VeneerDecomposePlatePageReqVO req) {
if (CollUtil.isEmpty(req.getGoodsIds())) {
return List.of();
}
return distinctPlate(veneerDecomposeMapper.selectGoodsPlateList(req));
}
/**
* 一块板可关联多个加工组,查询结果按板件主键保留第一条。
* 房间、柜体是板件的唯一归属,因此同一板的多条加工组记录展示信息一致。
*
* @param plates 数据库查询得到的板件原始列表
* @return 按板件主键去重后的列表
*/
private List<VeneerDecomposePlateRespVO> distinctPlate(List<VeneerDecomposePlateRespVO> plates) {
if (CollUtil.isEmpty(plates)) {
return plates;
}
Map<Long, VeneerDecomposePlateRespVO> plateMap = new LinkedHashMap<>();
for (VeneerDecomposePlateRespVO plate : plates) {
plateMap.putIfAbsent(plate.getPlateId(), plate);
}
return new ArrayList<>(plateMap.values());
}
/**
* 执行贴皮分解:一块原板按所选 A/B 面生成一条或两条贴皮记录,原板计数只增加一次。
*
* @param req 贴皮分解参数
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void decompose(VeneerDecomposeCreateReqVO req) {
// orderIds 非空表示按订单分解;否则必须指定板材商品编码。
if (!req.isByOrder() && (req.getGoodsId() == null || req.getGoodsId().isBlank())) {
throw new ServiceException(VENEER_DECOMPOSE_SCOPE_REQUIRED);
}
// A、B 面允许分别选择贴皮,但至少需要选择一面。
if (req.getAVeneerId() == null && req.getBVeneerId() == null) {
throw new ServiceException(VENEER_DECOMPOSE_SIDE_REQUIRED);
}
List<String> plateNos = req.getPlateNos().stream().distinct().sorted().toList();
// 板件编号分批查询,避免一次生成过长的 IN 条件。
List<PlateDO> plates = new ArrayList<>();
for (List<String> plateNoBatch : CollUtil.split(plateNos, DECOMPOSE_BATCH_SIZE)) {
plates.addAll(veneerDecomposeMapper.selectUndecomposedPlateList(req, plateNoBatch));
}
// 数量不一致通常表示板件已被其他用户分解,阻止本次请求继续覆盖状态。
if (plates.size() != plateNos.size()) {
throw new ServiceException(VENEER_DECOMPOSE_PLATE_STATUS_CHANGED);
}
// 先锁定受影响订单,避免同一订单的并发分解互相覆盖重新统计的结果。
List<Long> affectedOrderIds = plates.stream().map(PlateDO::getOrderId).distinct().sorted().toList();
for (List<Long> orderIdBatch : CollUtil.split(affectedOrderIds, DECOMPOSE_BATCH_SIZE)) {
veneerDecomposeMapper.selectOrderIdForUpdate(orderIdBatch);
}
// 从贴皮库加载 A/B 面贴皮,并将贴皮属性以快照形式写入板件贴皮表。
Map<Long, VeneerDO> sourceVeneerMap = loadSourceVeneers(req);
List<OrderPlateVeneerDO> plateVeneers = new ArrayList<>();
for (PlateDO plate : plates) {
if (req.getAVeneerId() != null) {
plateVeneers.add(buildPlateVeneer(
plate, sourceVeneerMap.get(req.getAVeneerId()), VENEER_SIDE_A, req.getOuterMargin()));
}
if (req.getBVeneerId() != null) {
plateVeneers.add(buildPlateVeneer(
plate, sourceVeneerMap.get(req.getBVeneerId()), VENEER_SIDE_B, req.getOuterMargin()));
}
}
// 原板状态分批更新;租户插件追加 organ_id 后由 MyCat 按组织路由。
List<Long> plateIds = plates.stream().map(PlateDO::getId).toList();
for (List<Long> plateIdBatch : CollUtil.split(plateIds, DECOMPOSE_BATCH_SIZE)) {
// 条件中包含 is_decomposed=false,通过每批更新行数进行第二次并发校验。
int updated = veneerDecomposeMapper.updatePlateDecomposed(plateIdBatch);
if (updated != plateIdBatch.size()) {
throw new ServiceException(VENEER_DECOMPOSE_PLATE_STATUS_CHANGED);
}
}
// A/B 贴皮记录分批插入,控制单条 INSERT 的参数数量和报文大小。
for (List<OrderPlateVeneerDO> plateVeneerBatch
: CollUtil.split(plateVeneers, DECOMPOSE_BATCH_SIZE)) {
orderPlateVeneerMapper.insertBatch(plateVeneerBatch);
}
// 以 order_plate 当前状态为准重新统计,不使用本次请求数量做增量计算。
List<Long> affectedOrderGoodsIds = plates.stream()
.map(PlateDO::getGoodsId).distinct().sorted().toList();
refreshOrderDecomposedPlateCount(affectedOrderIds);
refreshGoodsDecomposedPlateCount(affectedOrderGoodsIds);
}
/**
* 从 order_plate 重新统计并覆盖订单的已分解贴皮板件数量。
* 每批处理 100 个订单,更新时使用 version 进行乐观锁校验。
*
* @param orderIds 需要重新统计的订单ID列表
*/
private void refreshOrderDecomposedPlateCount(List<Long> orderIds) {
for (List<Long> orderIdBatch : CollUtil.split(orderIds, DECOMPOSE_STAT_BATCH_SIZE)) {
// 先读取当前版本,后续任何并发修改都会使版本条件更新失败。
Map<Long, OrderDO> orderMap = new HashMap<>();
for (OrderDO order : orderMapper.selectByIds(orderIdBatch)) {
orderMap.put(order.getId(), order);
}
List<VeneerDecomposedPlateCountDO> databaseCounts =
veneerDecomposeMapper.selectOrderDecomposedPlateCount(orderIdBatch);
Map<Long, Integer> countMap = convertDecomposedPlateCount(databaseCounts);
for (Long orderId : orderIdBatch) {
OrderDO order = orderMap.get(orderId);
if (order == null) {
throw new ServiceException(ORDER_PLATE_UPDATE_CONCURRENCY_ERROR, orderId);
}
int version = order.getVersion();
int update = orderMapper.update(new LambdaUpdateWrapper<OrderDO>()
.eq(OrderDO::getId, orderId)
.eq(OrderDO::getVersion, version)
.set(OrderDO::getDecomposedVeneerPlateNum, countMap.getOrDefault(orderId, 0))
.set(OrderDO::getVersion, version + 1));
if (update == 0) {
throw new ServiceException(ORDER_PLATE_UPDATE_CONCURRENCY_ERROR, orderId);
}
}
}
}
/**
* 从 order_plate 重新统计并覆盖订单板材的已分解贴皮板件数量。
* 每批处理 100 条订单板材,更新时使用 version 进行乐观锁校验。
*
* @param orderGoodsIds 需要重新统计的 {@code order_goods} 主键列表
*/
private void refreshGoodsDecomposedPlateCount(List<Long> orderGoodsIds) {
for (List<Long> orderGoodsIdBatch : CollUtil.split(orderGoodsIds, DECOMPOSE_STAT_BATCH_SIZE)) {
// 先读取当前版本,防止用旧统计结果覆盖其他业务刚完成的更新。
Map<Long, GoodsDO> goodsMap = new HashMap<>();
for (GoodsDO goods : goodsMapper.selectByIds(orderGoodsIdBatch)) {
goodsMap.put(goods.getId(), goods);
}
List<VeneerDecomposedPlateCountDO> databaseCounts =
veneerDecomposeMapper.selectGoodsDecomposedPlateCount(orderGoodsIdBatch);
Map<Long, Integer> countMap = convertDecomposedPlateCount(databaseCounts);
for (Long orderGoodsId : orderGoodsIdBatch) {
GoodsDO goods = goodsMap.get(orderGoodsId);
if (goods == null) {
throw new ServiceException(GOODS_PLATE_UPDATE_CONCURRENCY_ERROR, orderGoodsId);
}
int version = goods.getVersion();
int update = goodsMapper.update(new LambdaUpdateWrapper<GoodsDO>()
.eq(GoodsDO::getId, orderGoodsId)
.eq(GoodsDO::getVersion, version)
.set(GoodsDO::getDecomposedVeneerPlateNum,
countMap.getOrDefault(orderGoodsId, 0))
.set(GoodsDO::getVersion, version + 1));
if (update == 0) {
throw new ServiceException(GOODS_PLATE_UPDATE_CONCURRENCY_ERROR, orderGoodsId);
}
}
}
}
/**
* 将数据库聚合结果转换为目标ID与已分解数量的映射。
* 未出现在映射中的目标由调用方按 0 处理。
*
* @param databaseCounts 数据库聚合统计结果
* @return 目标ID与已分解板件数量的映射
*/
private Map<Long, Integer> convertDecomposedPlateCount(
List<VeneerDecomposedPlateCountDO> databaseCounts) {
Map<Long, Integer> countMap = new HashMap<>();
for (VeneerDecomposedPlateCountDO databaseCount : databaseCounts) {
countMap.put(databaseCount.getTargetId(), databaseCount.getDecomposedPlateNum());
}
return countMap;
}
/**
* 加载 A/B 面选中的贴皮库数据,并按贴皮库主键构建映射。
*
* @param req 贴皮分解参数
* @return 贴皮库主键与贴皮数据的映射
*/
private Map<Long, VeneerDO> loadSourceVeneers(VeneerDecomposeCreateReqVO req) {
// A、B 可能选择同一贴皮,先去重,避免重复查询贴皮库。
Set<Long> veneerIds = new HashSet<>();
if (req.getAVeneerId() != null) {
veneerIds.add(req.getAVeneerId());
}
if (req.getBVeneerId() != null) {
veneerIds.add(req.getBVeneerId());
}
Map<Long, VeneerDO> result = new HashMap<>();
for (Long veneerId : veneerIds) {
VeneerDO veneer = veneerMapper.selectById(veneerId);
if (veneer == null) {
throw new ServiceException(VENEER_NOT_EXIST);
}
result.put(veneerId, veneer);
}
return result;
}
/**
* 根据原板件、贴皮逻辑面及贴皮库快照构建一条板件贴皮记录。
*
* @param plate 原板件
* @param sourceVeneer 选中的贴皮库数据
* @param veneerSide 贴皮逻辑面
* @param outerMargin 外扩余量
* @return 待保存的板件贴皮记录
*/
private OrderPlateVeneerDO buildPlateVeneer(PlateDO plate, VeneerDO sourceVeneer,
String veneerSide, BigDecimal outerMargin) {
int plateSurface = resolvePlateSurface(plate.getHoleArrange(), veneerSide);
return OrderPlateVeneerDO.builder()
.organId(plate.getOrganId())
.orderId(plate.getOrderId())
.orderGoodsId(plate.getGoodsId())
.orderPlateId(plate.getId())
.plateNo(plate.getPlateNo())
.plateName(plate.getName())
.plateLength(plate.getHeight())
.plateWidth(plate.getWidth())
.plateThickness(plate.getThickness())
.holeArrange(plate.getHoleArrange())
.veneerSide(veneerSide)
.plateSurface(plateSurface)
.veneerNo(plate.getPlateNo() + veneerSide)
.outerMargin(outerMargin)
.sourceVeneerId(sourceVeneer.getId())
.sourceVeneerNo(sourceVeneer.getVeneerNo())
.veneerName(sourceVeneer.getVeneerName())
.productLevel(sourceVeneer.getProductLevel())
.color(ObjectUtil.defaultIfNull(sourceVeneer.getColor(), ""))
.material(ObjectUtil.defaultIfNull(sourceVeneer.getMaterial(), ""))
.build();
}
/**
* 根据 WebCAD 排版面和贴皮逻辑面确定实际板件面。
* 反面排版时 A 面对应反面、B 面对应正面;正面或随意面排版时关系相反。
*
* @param holeArrange WebCAD 排版面
* @param veneerSide 贴皮逻辑面
* @return 实际板件面
*/
private int resolvePlateSurface(Integer holeArrange, String veneerSide) {
boolean reverseArrange = Integer.valueOf(HOLE_ARRANGE_REVERSE).equals(holeArrange);
if (VENEER_SIDE_A.equals(veneerSide)) {
return reverseArrange ? PLATE_SURFACE_BACK : PLATE_SURFACE_FRONT;
}
return reverseArrange ? PLATE_SURFACE_FRONT : PLATE_SURFACE_BACK;
}
}
@@ -0,0 +1,57 @@
package com.cf.imes.module.executor.service.veneer;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManagePlateListReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManagePlateRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageReselectReqVO;
import java.util.List;
/**
* 贴皮管理 Service。
*/
public interface VeneerManageService {
/**
* 分页查询存在已分解贴皮板件的订单。
*
* @param req 订单查询条件
* @return 订单分页结果
*/
PageResult<VeneerManageOrderRespVO> getOrderPage(VeneerManageOrderPageReqVO req);
/**
* 分页查询存在已分解贴皮板件的板材。
*
* @param req 板材查询条件
* @return 板材分页结果
*/
PageResult<VeneerManageGoodsRespVO> getGoodsPage(VeneerManageGoodsPageReqVO req);
/**
* 按订单查询已分解板件贴皮列表。
*
* @param req 查询条件,必须包含订单ID列表
* @return 已分解板件贴皮列表
*/
List<VeneerManagePlateRespVO> getOrderPlateList(VeneerManagePlateListReqVO req);
/**
* 按板材查询已分解板件贴皮列表。
*
* @param req 查询条件,必须包含板材商品编码列表
* @return 已分解板件贴皮列表
*/
List<VeneerManagePlateRespVO> getGoodsPlateList(VeneerManagePlateListReqVO req);
/**
* 批量为已分解板件贴皮重新选择贴皮库数据。
*
* @param req 板件贴皮记录ID及新贴皮库ID
*/
void reselectVeneer(VeneerManageReselectReqVO req);
}
@@ -0,0 +1,152 @@
package com.cf.imes.module.executor.service.veneer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.date.LocalDateTimeUtils;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderPageReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManagePlateListReqVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManagePlateRespVO;
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageReselectReqVO;
import com.cf.imes.module.executor.dal.dataobject.veneer.OrderPlateVeneerDO;
import com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDO;
import com.cf.imes.module.executor.dal.mysql.veneer.OrderPlateVeneerMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerManageMapper;
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
import static com.cf.imes.framework.common.pojo.PageParam.PAGE_SIZE_NONE;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_NOT_EXIST;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_RESELECT_RECORD_REQUIRED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_RESELECT_RECORD_STATUS_CHANGED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_RESELECT_SOURCE_REQUIRED;
/**
* 贴皮管理 Service 实现。
*/
@Service
public class VeneerManageServiceImpl implements VeneerManageService {
/**
* 重选贴皮单批处理数量。
*/
private static final int RESELECT_BATCH_SIZE = 1000;
@Resource
private VeneerManageMapper veneerManageMapper;
@Resource
private OrderPlateVeneerMapper orderPlateVeneerMapper;
@Resource
private VeneerMapper veneerMapper;
@Override
public PageResult<VeneerManageOrderRespVO> getOrderPage(VeneerManageOrderPageReqVO req) {
PageDTO<VeneerManageOrderRespVO> page = new PageDTO<>(req.getPageNo(), req.getPageSize());
IPage<Long> rootPage = veneerManageMapper.selectRootOrderIdList(
page, req, LocalDateTimeUtils.generateTimeSection(req.getOrderDate()));
List<Long> rootIds = rootPage.getRecords();
if (CollUtil.isEmpty(rootIds)) {
return new PageResult<>();
}
IPage<VeneerManageOrderRespVO> result = veneerManageMapper.selectOrderList(
new PageDTO<>(req.getPageNo(), PAGE_SIZE_NONE), rootIds);
return new PageResult<>(result.getRecords(), rootPage.getTotal());
}
@Override
public PageResult<VeneerManageGoodsRespVO> getGoodsPage(VeneerManageGoodsPageReqVO req) {
IPage<VeneerManageGoodsRespVO> result = veneerManageMapper.selectGoodsPage(
new PageDTO<>(req.getPageNo(), req.getPageSize()), req);
return new PageResult<>(result.getRecords(), result.getTotal());
}
@Override
public List<VeneerManagePlateRespVO> getOrderPlateList(VeneerManagePlateListReqVO req) {
if (CollUtil.isEmpty(req.getOrderIds())) {
return List.of();
}
return veneerManageMapper.selectOrderPlateList(req.getOrderIds());
}
@Override
public List<VeneerManagePlateRespVO> getGoodsPlateList(VeneerManagePlateListReqVO req) {
if (CollUtil.isEmpty(req.getGoodsIds())) {
return List.of();
}
return veneerManageMapper.selectGoodsPlateList(req.getGoodsIds());
}
/**
* 批量重选贴皮,仅替换所选 A/B 面记录的贴皮库关联及贴皮属性快照。
*
* @param req 批量重选贴皮参数
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void reselectVeneer(VeneerManageReselectReqVO req) {
if (CollUtil.isEmpty(req.getIds())) {
throw new ServiceException(VENEER_RESELECT_RECORD_REQUIRED);
}
if (ObjectUtil.isNull(req.getVeneerId())) {
throw new ServiceException(VENEER_RESELECT_SOURCE_REQUIRED);
}
List<Long> ids = req.getIds().stream()
.filter(Objects::nonNull)
.distinct()
.sorted()
.toList();
if (CollUtil.isEmpty(ids)) {
throw new ServiceException(VENEER_RESELECT_RECORD_REQUIRED);
}
// 查询新贴皮数据,后续统一更新为当前贴皮库属性快照。
VeneerDO veneer = veneerMapper.selectById(req.getVeneerId());
if (ObjectUtil.isNull(veneer)) {
throw new ServiceException(VENEER_NOT_EXIST);
}
for (List<Long> idBatch : CollUtil.split(ids, RESELECT_BATCH_SIZE)) {
// 锁定本批有效记录,避免重选过程中记录被移除。
List<OrderPlateVeneerDO> records = orderPlateVeneerMapper.selectList(
new LambdaQueryWrapper<OrderPlateVeneerDO>()
.select(OrderPlateVeneerDO::getId)
.in(OrderPlateVeneerDO::getId, idBatch)
.last("FOR UPDATE"));
if (records.size() != idBatch.size()) {
throw new ServiceException(VENEER_RESELECT_RECORD_STATUS_CHANGED);
}
// 生成贴皮编号及原板信息保持不变,只替换贴皮库关联和五个展示快照字段。
int updated = orderPlateVeneerMapper.update(
new LambdaUpdateWrapper<OrderPlateVeneerDO>()
.in(OrderPlateVeneerDO::getId, idBatch)
.set(OrderPlateVeneerDO::getSourceVeneerId, veneer.getId())
.set(OrderPlateVeneerDO::getSourceVeneerNo, veneer.getVeneerNo())
.set(OrderPlateVeneerDO::getVeneerName, veneer.getVeneerName())
.set(OrderPlateVeneerDO::getProductLevel, veneer.getProductLevel())
.set(OrderPlateVeneerDO::getColor,
ObjectUtil.defaultIfNull(veneer.getColor(), ""))
.set(OrderPlateVeneerDO::getMaterial,
ObjectUtil.defaultIfNull(veneer.getMaterial(), "")));
if (updated != idBatch.size()) {
throw new ServiceException(VENEER_RESELECT_RECORD_STATUS_CHANGED);
}
}
}
}
@@ -0,0 +1,278 @@
<?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.cf.imes.module.executor.dal.mysql.veneer.VeneerDecomposeMapper">
<resultMap id="OrderMap"
type="com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeOrderRespVO">
<result property="orderId" column="orderId"/>
<result property="orderType" column="orderType"/>
<result property="customOrderNo" column="customOrderNo"/>
<result property="customer" column="customer"/>
<result property="address" column="address"/>
<result property="orderDate" column="orderDate"/>
<result property="num" column="num"/>
<result property="area" column="area"/>
</resultMap>
<resultMap id="GoodsMap"
type="com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposeGoodsRespVO">
<result property="goodsId" column="goodsId"/>
<result property="goodsName" column="goodsName"/>
<result property="material" column="material"/>
<result property="color" column="color"/>
<result property="thickness" column="thickness"/>
<result property="num" column="num"/>
<result property="area" column="area"/>
</resultMap>
<select id="selectRootOrderIdList" resultType="java.lang.Long">
SELECT o.root_id
FROM orders o
WHERE o.deleted = false
AND IFNULL(o.plate_num, 0) &gt; IFNULL(o.decomposed_veneer_plate_num, 0)
<if test="req.orderId != null and req.orderId != ''">
AND CAST(o.id AS CHAR) LIKE CONCAT('%', #{req.orderId}, '%')
</if>
<if test="req.customOrderNo != null and req.customOrderNo != ''">
AND o.custom_order_no LIKE CONCAT('%', #{req.customOrderNo}, '%')
</if>
<if test="req.customer != null and req.customer != ''">
AND o.customer LIKE CONCAT('%', #{req.customer}, '%')
</if>
<if test="req.address != null and req.address != ''">
AND o.address LIKE CONCAT('%', #{req.address}, '%')
</if>
<if test="orderDateTime != null and orderDateTime.length == 2">
AND o.order_date BETWEEN #{orderDateTime[0]} AND #{orderDateTime[1]}
</if>
GROUP BY o.root_id
ORDER BY o.root_id DESC
</select>
<select id="selectOrderList" resultMap="OrderMap">
SELECT o.id AS orderId,
o.order_type AS orderType,
o.custom_order_no AS customOrderNo,
o.customer,
o.address,
o.order_date AS orderDate,
o.plate_num AS num,
o.area AS area
FROM orders o
WHERE o.deleted = false
AND o.root_id IN
<foreach collection="rootIds" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
ORDER BY o.id DESC
</select>
<select id="selectGoodsPage" resultMap="GoodsMap">
SELECT og.goods_id AS goodsId,
og.goods_name AS goodsName,
og.material,
og.color,
og.thickness,
SUM(og.plate_num) AS num,
SUM(og.area) AS area
FROM orders o
JOIN order_goods og ON og.order_id = o.id
WHERE o.deleted = false
AND o.status IN (1, 2, 3)
AND og.deleted = false
AND og.plate_num &gt; IFNULL(og.decomposed_veneer_plate_num, 0)
<if test="req.goodsName != null and req.goodsName != ''">
AND og.goods_name LIKE CONCAT('%', #{req.goodsName}, '%')
</if>
<if test="req.goodsId != null and req.goodsId != ''">
AND og.goods_id LIKE CONCAT('%', #{req.goodsId}, '%')
</if>
<if test="req.material != null and req.material != ''">
AND og.material LIKE CONCAT('%', #{req.material}, '%')
</if>
<if test="req.color != null and req.color != ''">
AND og.color LIKE CONCAT('%', #{req.color}, '%')
</if>
<if test="req.thickness != null">
AND og.thickness = #{req.thickness}
</if>
GROUP BY og.goods_id, og.goods_name, og.material, og.color, og.thickness
ORDER BY og.thickness DESC
</select>
<resultMap id="PlateMap"
type="com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerDecomposePlateRespVO">
<id property="plateId" column="plateId"/>
<result property="roomName" column="roomName"/>
<result property="bodyName" column="bodyName"/>
<result property="plateNo" column="plateNo"/>
<result property="material" column="material"/>
<result property="color" column="color"/>
<result property="plateName" column="plateName"/>
<result property="length" column="length"/>
<result property="width" column="width"/>
<result property="thickness" column="thickness"/>
<result property="area" column="area"/>
</resultMap>
<select id="selectOrderPlateList" resultMap="PlateMap">
SELECT op.id AS plateId,
ob.room_name AS roomName,
ob.name AS bodyName,
op.plate_no AS plateNo,
og.material AS material,
og.color AS color,
op.name AS plateName,
op.height AS length,
op.width AS width,
op.thickness AS thickness,
op.area AS area
FROM order_plate op
JOIN order_goods og ON og.order_id = op.order_id
AND og.id = op.goods_id
JOIN order_item oi ON oi.order_id = op.order_id
AND oi.plate_id = op.id
AND oi.plate_id != 0
JOIN order_body ob ON ob.order_id = op.order_id
AND ob.id = oi.body_id
WHERE op.deleted = false
AND op.is_decomposed = false
<if test="req.orderIds != null and req.orderIds.size() > 0">
AND op.order_id IN
<foreach collection="req.orderIds" item="orderId" open="(" close=")" separator=",">
#{orderId}
</foreach>
</if>
<if test="req.roomIds != null and req.roomIds.size() > 0">
AND oi.room_id IN
<foreach collection="req.roomIds" item="roomId" open="(" close=")" separator=",">
#{roomId}
</foreach>
</if>
<if test="req.bodyIds != null and req.bodyIds.size() > 0">
AND oi.body_id IN
<foreach collection="req.bodyIds" item="bodyId" open="(" close=")" separator=",">
#{bodyId}
</foreach>
</if>
ORDER BY op.id DESC
</select>
<select id="selectGoodsPlateList" resultMap="PlateMap">
SELECT op.id AS plateId,
ob.room_name AS roomName,
ob.name AS bodyName,
op.plate_no AS plateNo,
og.material AS material,
og.color AS color,
op.name AS plateName,
op.height AS length,
op.width AS width,
op.thickness AS thickness,
op.area AS area
FROM order_plate op
JOIN order_goods og ON og.order_id = op.order_id
AND og.id = op.goods_id
JOIN order_item oi ON oi.order_id = op.order_id
AND oi.plate_id = op.id
AND oi.plate_id != 0
JOIN order_body ob ON ob.order_id = op.order_id
AND ob.id = oi.body_id
WHERE op.deleted = false
AND op.is_decomposed = false
<if test="req.goodsIds != null and req.goodsIds.size() > 0">
AND og.goods_id IN
<foreach collection="req.goodsIds" item="goodsId" open="(" close=")" separator=",">
#{goodsId}
</foreach>
</if>
ORDER BY op.id DESC
</select>
<select id="selectUndecomposedPlateList"
resultType="com.cf.imes.module.executor.dal.dataobject.plate.PlateDO">
SELECT op.id,
op.order_id AS orderId,
op.organ_id AS organId,
op.goods_id AS goodsId,
op.plate_no AS plateNo,
op.name,
op.height,
op.width,
op.thickness,
op.hole_arrange AS holeArrange
FROM order_plate op
<if test="req.orderIds == null or req.orderIds.size() == 0">
JOIN order_goods og ON og.order_id = op.order_id
AND og.id = op.goods_id
</if>
WHERE op.deleted = false
AND op.is_decomposed = false
AND op.plate_no IN
<foreach collection="plateNos" item="plateNo" open="(" close=")" separator=",">
#{plateNo}
</foreach>
<choose>
<when test="req.orderIds != null and req.orderIds.size() > 0">
AND op.order_id IN
<foreach collection="req.orderIds" item="orderId" open="(" close=")" separator=",">
#{orderId}
</foreach>
</when>
<otherwise>
AND og.goods_id = #{req.goodsId}
</otherwise>
</choose>
ORDER BY op.id
FOR UPDATE
</select>
<select id="selectOrderIdForUpdate" resultType="java.lang.Long">
SELECT id
FROM orders
WHERE id IN
<foreach collection="orderIds" item="orderId" open="(" close=")" separator=",">
#{orderId}
</foreach>
ORDER BY id
FOR UPDATE
</select>
<update id="updatePlateDecomposed">
UPDATE order_plate
SET is_decomposed = true
WHERE is_decomposed = false
AND id IN
<foreach collection="plateIds" item="plateId" open="(" close=")" separator=",">
#{plateId}
</foreach>
</update>
<select id="selectOrderDecomposedPlateCount"
resultType="com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDecomposedPlateCountDO">
SELECT op.order_id AS targetId,
COUNT(*) AS decomposedPlateNum
FROM order_plate op
WHERE op.deleted = false
AND op.is_decomposed = true
AND op.order_id IN
<foreach collection="orderIds" item="orderId" open="(" close=")" separator=",">
#{orderId}
</foreach>
GROUP BY op.order_id
</select>
<select id="selectGoodsDecomposedPlateCount"
resultType="com.cf.imes.module.executor.dal.dataobject.veneer.VeneerDecomposedPlateCountDO">
SELECT op.goods_id AS targetId,
COUNT(*) AS decomposedPlateNum
FROM order_plate op
WHERE op.deleted = false
AND op.is_decomposed = true
AND op.goods_id IN
<foreach collection="orderGoodsIds" item="orderGoodsId" open="(" close=")" separator=",">
#{orderGoodsId}
</foreach>
GROUP BY op.goods_id
</select>
</mapper>
@@ -0,0 +1,160 @@
<?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.cf.imes.module.executor.dal.mysql.veneer.VeneerManageMapper">
<resultMap id="OrderMap"
type="com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageOrderRespVO">
<result property="orderId" column="orderId"/>
<result property="orderType" column="orderType"/>
<result property="customOrderNo" column="customOrderNo"/>
<result property="customer" column="customer"/>
<result property="address" column="address"/>
<result property="orderDate" column="orderDate"/>
<result property="num" column="num"/>
<result property="area" column="area"/>
</resultMap>
<resultMap id="GoodsMap"
type="com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManageGoodsRespVO">
<result property="goodsId" column="goodsId"/>
<result property="goodsName" column="goodsName"/>
<result property="material" column="material"/>
<result property="color" column="color"/>
<result property="thickness" column="thickness"/>
<result property="num" column="num"/>
<result property="area" column="area"/>
</resultMap>
<resultMap id="PlateVeneerMap"
type="com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerManagePlateRespVO">
<id property="id" column="id"/>
<result property="veneerNo" column="veneerNo"/>
<result property="plateNo" column="plateNo"/>
<result property="plateName" column="plateName"/>
<result property="length" column="length"/>
<result property="width" column="width"/>
<result property="thickness" column="thickness"/>
<result property="sourceVeneerNo" column="sourceVeneerNo"/>
<result property="veneerName" column="veneerName"/>
<result property="productLevel" column="productLevel"/>
<result property="color" column="color"/>
<result property="material" column="material"/>
</resultMap>
<select id="selectRootOrderIdList" resultType="java.lang.Long">
SELECT o.root_id
FROM orders o
WHERE o.deleted = false
AND IFNULL(o.decomposed_veneer_plate_num, 0) &gt; 0
<if test="req.orderId != null and req.orderId != ''">
AND CAST(o.id AS CHAR) LIKE CONCAT('%', #{req.orderId}, '%')
</if>
<if test="req.customOrderNo != null and req.customOrderNo != ''">
AND o.custom_order_no LIKE CONCAT('%', #{req.customOrderNo}, '%')
</if>
<if test="req.customer != null and req.customer != ''">
AND o.customer LIKE CONCAT('%', #{req.customer}, '%')
</if>
<if test="req.address != null and req.address != ''">
AND o.address LIKE CONCAT('%', #{req.address}, '%')
</if>
<if test="orderDateTime != null and orderDateTime.length == 2">
AND o.order_date BETWEEN #{orderDateTime[0]} AND #{orderDateTime[1]}
</if>
GROUP BY o.root_id
ORDER BY o.root_id DESC
</select>
<select id="selectOrderList" resultMap="OrderMap">
SELECT o.id AS orderId,
o.order_type AS orderType,
o.custom_order_no AS customOrderNo,
o.customer,
o.address,
o.order_date AS orderDate,
o.plate_num AS num,
o.area AS area
FROM orders o
WHERE o.deleted = false
AND o.root_id IN
<foreach collection="rootIds" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
ORDER BY o.id DESC
</select>
<select id="selectGoodsPage" resultMap="GoodsMap">
SELECT og.goods_id AS goodsId,
og.goods_name AS goodsName,
og.material,
og.color,
og.thickness,
SUM(og.plate_num) AS num,
SUM(og.area) AS area
FROM orders o
JOIN order_goods og ON og.order_id = o.id
WHERE o.deleted = false
AND o.status IN (1, 2, 3)
AND og.deleted = false
AND IFNULL(og.decomposed_veneer_plate_num, 0) &gt; 0
<if test="req.goodsName != null and req.goodsName != ''">
AND og.goods_name LIKE CONCAT('%', #{req.goodsName}, '%')
</if>
<if test="req.goodsId != null and req.goodsId != ''">
AND og.goods_id LIKE CONCAT('%', #{req.goodsId}, '%')
</if>
<if test="req.material != null and req.material != ''">
AND og.material LIKE CONCAT('%', #{req.material}, '%')
</if>
<if test="req.color != null and req.color != ''">
AND og.color LIKE CONCAT('%', #{req.color}, '%')
</if>
<if test="req.thickness != null">
AND og.thickness = #{req.thickness}
</if>
GROUP BY og.goods_id, og.goods_name, og.material, og.color, og.thickness
ORDER BY og.thickness DESC
</select>
<sql id="PlateVeneerColumns">
opv.id,
opv.veneer_no AS veneerNo,
opv.plate_no AS plateNo,
opv.plate_name AS plateName,
opv.plate_length AS length,
opv.plate_width AS width,
opv.plate_thickness AS thickness,
opv.source_veneer_no AS sourceVeneerNo,
opv.veneer_name AS veneerName,
opv.product_level AS productLevel,
opv.color,
opv.material
</sql>
<select id="selectOrderPlateList" resultMap="PlateVeneerMap">
SELECT
<include refid="PlateVeneerColumns"/>
FROM order_plate_veneer opv
WHERE opv.deleted = false
AND opv.order_id IN
<foreach collection="orderIds" item="orderId" open="(" close=")" separator=",">
#{orderId}
</foreach>
ORDER BY opv.order_plate_id DESC, opv.veneer_side ASC
</select>
<select id="selectGoodsPlateList" resultMap="PlateVeneerMap">
SELECT
<include refid="PlateVeneerColumns"/>
FROM order_plate_veneer opv
JOIN order_goods og ON og.order_id = opv.order_id
AND og.id = opv.order_goods_id
WHERE opv.deleted = false
AND og.deleted = false
AND og.goods_id IN
<foreach collection="goodsIds" item="goodsId" open="(" close=")" separator=",">
#{goodsId}
</foreach>
ORDER BY opv.order_plate_id DESC, opv.veneer_side ASC
</select>
</mapper>
@@ -70,6 +70,14 @@ plate.is.source=小板:{0} 為來源板,無法刪除
plate.attr.group.exists=名稱、材質、顏色、厚度、品牌組合已存在,請檢查後提交 plate.attr.group.exists=名稱、材質、顏色、厚度、品牌組合已存在,請檢查後提交
veneer.not.exist=貼皮不存在 veneer.not.exist=貼皮不存在
veneer.decompose.scope.required=訂單ID列表和板材商品編碼不能同時為空
veneer.decompose.side.required=A面和B面貼皮至少選擇一個
veneer.decompose.plate.status.changed=板件分解狀態已變更,請重新整理後再試
veneer.decompose.plate.no.required=板件編號不能為空
veneer.decompose.outer.margin.min=外擴餘量不能小於0
veneer.reselect.record.required=請選擇需要重選貼皮的資料
veneer.reselect.source.required=請選擇新的貼皮
veneer.reselect.record.status.changed=板件貼皮資料狀態已變更,請重新整理後再試
veneer.no.exist=貼皮編號已存在 veneer.no.exist=貼皮編號已存在
veneer.import.required.lack=第{0}行存在帶*必填項為空,請檢查檔案 veneer.import.required.lack=第{0}行存在帶*必填項為空,請檢查檔案
@@ -70,6 +70,14 @@ plate.is.source=Plate {0} is a source plate and cannot be deleted
plate.attr.group.exists=Combination of name, material, color, thickness, and brand already exists plate.attr.group.exists=Combination of name, material, color, thickness, and brand already exists
veneer.not.exist=veneer not exist veneer.not.exist=veneer not exist
veneer.decompose.scope.required=Order ID list and goods code cannot both be empty
veneer.decompose.side.required=At least one veneer must be selected for side A or B
veneer.decompose.plate.status.changed=Plate decomposition status has changed. Please refresh and retry
veneer.decompose.plate.no.required=Plate numbers cannot be empty
veneer.decompose.outer.margin.min=Outer margin cannot be less than 0
veneer.reselect.record.required=Please select records for veneer reselection
veneer.reselect.source.required=Please select a new veneer
veneer.reselect.record.status.changed=Plate veneer data has changed. Please refresh and retry
veneer.no.exist=veneer no already exists veneer.no.exist=veneer no already exists
veneer.import.required.lack=The required field is empty in line {0}, please check the file veneer.import.required.lack=The required field is empty in line {0}, please check the file
@@ -70,6 +70,14 @@ plate.is.source=小板:{0} 为源小板,无法删除
plate.attr.group.exists=当前名称、材质、颜色、厚度、品牌的组合已存在,请检查后提交 plate.attr.group.exists=当前名称、材质、颜色、厚度、品牌的组合已存在,请检查后提交
veneer.not.exist=贴皮不存在 veneer.not.exist=贴皮不存在
veneer.decompose.scope.required=订单ID列表和板材商品编码不能同时为空
veneer.decompose.side.required=A面和B面贴皮至少选择一个
veneer.decompose.plate.status.changed=板件分解状态已变更,请刷新后重试
veneer.decompose.plate.no.required=板件编号不能为空
veneer.decompose.outer.margin.min=外扩余量不能小于0
veneer.reselect.record.required=请选择需要重选贴皮的数据
veneer.reselect.source.required=请选择新的贴皮
veneer.reselect.record.status.changed=板件贴皮数据状态已变更,请刷新后重试
veneer.no.exist=贴皮编号已存在 veneer.no.exist=贴皮编号已存在
veneer.import.required.lack=第{0}行存在带*必填项为空,请检查文件 veneer.import.required.lack=第{0}行存在带*必填项为空,请检查文件