From fdd86bfb09f03f84added6bebbaa10f285608342 Mon Sep 17 00:00:00 2001 From: liweidong-hj Date: Sat, 25 Apr 2026 16:13:21 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E8=AE=A1=E5=88=92=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/LauncherConstant.java | 4 +-- .../desk/order/pojo/dto/YieldOrderDto.java | 36 +++++++++++++++++++ .../desk/order/pojo/dto/YieldPlanDto.java | 35 ++++++++++++++++++ .../service/impl/DsTaskingServiceImpl.java | 10 ++++++ .../controller/YieldOrderController.java | 8 +++-- .../order/controller/YieldPlanController.java | 5 +-- .../desk/order/mapper/YieldOrderMapper.java | 5 ++- .../desk/order/mapper/YieldOrderMapper.xml | 12 ++++++- .../desk/order/mapper/YieldPlanMapper.java | 4 ++- .../desk/order/mapper/YieldPlanMapper.xml | 11 +++++- .../order/service/IYieldOrderService.java | 8 +++-- .../desk/order/service/IYieldPlanService.java | 5 +-- .../service/impl/YieldOrderServiceImpl.java | 8 +++-- .../service/impl/YieldPlanServiceImpl.java | 5 +-- .../src/main/resources/application-dev.yml | 4 +++ 15 files changed, 139 insertions(+), 21 deletions(-) create mode 100644 blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/order/pojo/dto/YieldOrderDto.java create mode 100644 blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/order/pojo/dto/YieldPlanDto.java diff --git a/blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java b/blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java index 3ef40cfd..ffabff7b 100644 --- a/blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java +++ b/blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java @@ -12,9 +12,9 @@ public interface LauncherConstant { /** * nacos 命名空间 */ -// String NACOS_NAMESPACE = "feaf627f-a847-463b-8b73-24a0538f526e"; + String NACOS_NAMESPACE = "feaf627f-a847-463b-8b73-24a0538f526e"; // 生产环境 - String NACOS_NAMESPACE = "db3f4da1-ae19-4104-8c17-6d9b8f069401"; +// String NACOS_NAMESPACE = "db3f4da1-ae19-4104-8c17-6d9b8f069401"; // 测试环境 // String NACOS_NAMESPACE = "6cdd0310-0d61-4f54-891a-7fb06224d9b8"; diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/order/pojo/dto/YieldOrderDto.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/order/pojo/dto/YieldOrderDto.java new file mode 100644 index 00000000..c798085d --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/order/pojo/dto/YieldOrderDto.java @@ -0,0 +1,36 @@ +package org.springblade.desk.order.pojo.dto; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springblade.desk.order.pojo.entity.YieldOrder; + +import java.io.Serial; + +/** + * 生产订单-视图类 + * + * @author lqk + */ +@Data +public class YieldOrderDto extends YieldOrder { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 排序字段 + */ + private String orderByField; + /** + * true: 升序,false: 降序 + */ + private boolean isAsc; + +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/order/pojo/dto/YieldPlanDto.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/order/pojo/dto/YieldPlanDto.java new file mode 100644 index 00000000..3f7905b4 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/order/pojo/dto/YieldPlanDto.java @@ -0,0 +1,35 @@ +package org.springblade.desk.order.pojo.dto; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import org.springblade.desk.order.pojo.entity.YieldPlan; + +import java.io.Serial; + +/** + * 生产计划-视图类 + * + * @author lqk + */ +@Data +public class YieldPlanDto extends YieldPlan { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 排序字段 + */ + private String orderByField; + /** + * true: 升序,false: 降序 + */ + private boolean isAsc; + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/DsTaskingServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/DsTaskingServiceImpl.java index 379874ce..14b9e6b2 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/DsTaskingServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/dashboard/service/impl/DsTaskingServiceImpl.java @@ -36,7 +36,9 @@ import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.tool.api.R; import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.SpringUtil; +import org.springblade.desk.basic.pojo.entity.LocallyPlatedPart; import org.springblade.desk.basic.service.ICraftAbilityService; +import org.springblade.desk.basic.service.ILocallyPlatedPartService; import org.springblade.desk.common.constant.BizTypeConstant; import org.springblade.desk.common.service.IMesNotifyMessageService; import org.springblade.desk.dashboard.constant.DsPartConstant; @@ -166,6 +168,9 @@ public class DsTaskingServiceImpl extends BaseServiceImpl selectAssignList(IPage page, DsTaskingVO dsTasking) { List dsTaskingVOS = baseMapper.selectDsTaskingPage(page, dsTasking); @@ -787,6 +792,11 @@ public class DsTaskingServiceImpl extends BaseServiceImpl> pageElectroplate(@Parameter(hidden = true) YieldOrder entity, Query query) { + public R> pageElectroplate(@Parameter(hidden = true) YieldOrderDto entity, Query query) { IPage page = yieldOrderService.selectPageElectroplate(Condition.getPage(query), entity); return R.data(YieldOrderWrapper.build().pageVO(page)); } @@ -85,7 +87,7 @@ public class YieldOrderController extends BladeController { @Parameter(name = "status", description = "状态", in = ParameterIn.QUERY, schema = @Schema(type = "int")) }) @Operation(summary = "分页查询列表-烧结", description = "") - public R> pageSintering(@Parameter(hidden = true) YieldOrder entity, Query query) { + public R> pageSintering(@Parameter(hidden = true) YieldOrderDto entity, Query query) { IPage page = yieldOrderService.selectPageSintering(Condition.getPage(query), entity); return R.data(YieldOrderWrapper.build().pageVO(page)); } @@ -101,7 +103,7 @@ public class YieldOrderController extends BladeController { in = ParameterIn.QUERY, schema = @Schema(type = "string")) }) @Operation(summary = "分页-异常订单", description = "") - public R> pageException(@Parameter(hidden = true) YieldOrder entity, Query query) { + public R> pageException(@Parameter(hidden = true) YieldOrderDto entity, Query query) { IPage page = Condition.getPage(query); page.setRecords(new ArrayList<>()); diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/controller/YieldPlanController.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/controller/YieldPlanController.java index 2d0e086b..f72f8e05 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/controller/YieldPlanController.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/controller/YieldPlanController.java @@ -15,6 +15,7 @@ import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Query; import org.springblade.core.tool.api.R; import org.springblade.core.tool.utils.Func; +import org.springblade.desk.order.pojo.dto.YieldPlanDto; import org.springblade.desk.order.pojo.entity.YieldPlan; import org.springblade.desk.order.pojo.enums.YieldPlanEnum; import org.springblade.desk.order.pojo.vo.YieldPlanVo; @@ -51,7 +52,7 @@ public class YieldPlanController extends BladeController { @Parameter(name = "status", description = "状态", in = ParameterIn.QUERY, schema = @Schema(type = "int")) }) @Operation(summary = "分页查询列表-电镀", description = "") - public R> pageElectroplate(@Parameter(hidden = true) YieldPlan entity, Query query) { + public R> pageElectroplate(@Parameter(hidden = true) YieldPlanDto entity, Query query) { IPage page = yieldPlanService.selectPageElectroplate(Condition.getPage(query), entity); return R.data(YieldPlanWrapper.build().pageVO(page)); } @@ -66,7 +67,7 @@ public class YieldPlanController extends BladeController { @Parameter(name = "status", description = "状态", in = ParameterIn.QUERY, schema = @Schema(type = "int")) }) @Operation(summary = "分页查询列表-烧结", description = "") - public R> pageSintering(@Parameter(hidden = true) YieldPlan entity, Query query) { + public R> pageSintering(@Parameter(hidden = true) YieldPlanDto entity, Query query) { IPage page = yieldPlanService.selectPageSintering(Condition.getPage(query), entity); return R.data(YieldPlanWrapper.build().pageVO(page)); } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/mapper/YieldOrderMapper.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/mapper/YieldOrderMapper.java index 5fec8f8c..520ea692 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/mapper/YieldOrderMapper.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/mapper/YieldOrderMapper.java @@ -2,8 +2,11 @@ package org.springblade.desk.order.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Param; +import org.springblade.desk.order.pojo.dto.YieldOrderDto; import org.springblade.desk.order.pojo.entity.YieldOrder; import org.springblade.desk.order.pojo.enums.YieldOrderEnum; +import org.springblade.desk.order.pojo.vo.YieldOrderVo; import java.util.List; @@ -23,7 +26,7 @@ public interface YieldOrderMapper extends BaseMapper { * @param yieldTypeList * @return */ - List selectPage(IPage page, YieldOrder entity, List yieldTypeList); + List selectPage(IPage page, @Param("entity") YieldOrderDto entity, List yieldTypeList); /** * 自定义分页 - 用于需求申报 diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/mapper/YieldOrderMapper.xml b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/mapper/YieldOrderMapper.xml index f1d7e63e..09f72f9b 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/mapper/YieldOrderMapper.xml +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/mapper/YieldOrderMapper.xml @@ -67,7 +67,17 @@ AND release_date to_date(concat(#{entity.releaseDateEnd},' 23:59:59'),'YYYY-MM-DD HH24:MI:SS') - order by CREATE_TIME desc + + + + ORDER BY ${entity.orderByField} + ASC + DESC + + + ORDER BY CREATE_TIME DESC + + + WITH STEP_DATA AS ( + SELECT + t.ID, + t.STANDARD_TYPE, + t.PROCESS_ID, + t.PART_NO, + t.SETTLEMENT_PRICE, + t.SETTLEMENT_UNIT, + t.STEP_TYPE, + t.STEP, + t.STEP_UNIT, + t.STEP_SETTLEMENT_PRICE, + t.STEP_SETTLEMENT_UNIT, + t.CREATE_USER, + t.CREATE_DEPT, + t.CREATE_TIME, + t.UPDATE_USER, + t.UPDATE_TIME, + t.STATUS, + t.IS_DELETED, + ps.NAME as PROCESS_NAME + FROM BS_SALARY_STANDARD t + LEFT JOIN BS_PROCESS_SET ps ON t.PROCESS_ID = ps.ID and ps.is_deleted = 0 + + t.is_deleted = 0 + + and ps.name like concat(concat('%', #{bsSalaryStandard.processName}),'%') + + + ), + STEP_NUMBERS AS ( SELECT LEVEL AS n FROM DUAL CONNECT BY LEVEL 100 ) SELECT + ID, + STANDARD_TYPE, + PROCESS_ID, + PART_NO, + SETTLEMENT_PRICE, + SETTLEMENT_UNIT, + STEP_TYPE, + STEP, + STEP_UNIT, + STEP_SETTLEMENT_PRICE, + STEP_SETTLEMENT_UNIT, + CREATE_USER, + CREATE_DEPT, + CREATE_TIME, + UPDATE_USER, + UPDATE_TIME, + STATUS, + IS_DELETED, + PROCESS_NAME, + minStep, + maxStep, + PRICE + FROM + ( + SELECT + ID, + STANDARD_TYPE, + PROCESS_ID, + PART_NO, + SETTLEMENT_PRICE, + SETTLEMENT_UNIT, + STEP_TYPE, + STEP, + STEP_UNIT, + STEP_SETTLEMENT_PRICE, + STEP_SETTLEMENT_UNIT, + CREATE_USER, + CREATE_DEPT, + CREATE_TIME, + UPDATE_USER, + UPDATE_TIME, + STATUS, + IS_DELETED, + PROCESS_NAME, + NULL AS minStep, + NULL AS maxStep, + TO_NUMBER(STEP_SETTLEMENT_PRICE) AS PRICE + FROM + STEP_DATA + WHERE + STEP_TYPE IN ( 1, 2 ) UNION ALL + SELECT + sd.ID, + sd.STANDARD_TYPE, + sd.PROCESS_ID, + sd.PART_NO, + sd.SETTLEMENT_PRICE, + sd.SETTLEMENT_UNIT, + sd.STEP_TYPE, + sd.STEP, + sd.STEP_UNIT, + sd.STEP_SETTLEMENT_PRICE, + sd.STEP_SETTLEMENT_UNIT, + sd.CREATE_USER, + sd.CREATE_DEPT, + sd.CREATE_TIME, + sd.UPDATE_USER, + sd.UPDATE_TIME, + sd.STATUS, + sd.IS_DELETED, + sd.PROCESS_NAME, + CASE + WHEN sn.n = 1 THEN + 0 ELSE TO_NUMBER( REGEXP_SUBSTR( sd.STEP, '[^ ]+', 1, sn.n - 1 ) ) + END AS minStep, + CASE + WHEN sn.n REGEXP_COUNT ( sd.STEP, ' ' ) + 1 THEN + TO_NUMBER( REGEXP_SUBSTR( sd.STEP, '[^ ]+', 1, sn.n ) ) ELSE NULL + END AS maxStep, + TO_NUMBER( REGEXP_SUBSTR( sd.STEP_SETTLEMENT_PRICE, '[^ ]+', 1, sn.n ) ) AS PRICE + FROM + STEP_DATA sd + JOIN STEP_NUMBERS sn ON sn.n REGEXP_COUNT ( sd.STEP_SETTLEMENT_PRICE, ' ' ) + 1 + WHERE + sd.STEP_TYPE = 3 + ) + ORDER BY + ID, + minStep NULLS FIRST + + + \ No newline at end of file diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/dto/BsSalaryCalculationDTO.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/dto/BsSalaryCalculationDTO.java new file mode 100644 index 00000000..433a3096 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/dto/BsSalaryCalculationDTO.java @@ -0,0 +1,103 @@ +package org.springblade.desk.efficiency.pojo.dto; + +import lombok.Data; + +import java.io.Serial; + +@Data +public class BsSalaryCalculationDTO { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 订单号 + */ + private String woCode; + + /** + * 流程卡号 + */ + private String cardNo; + /** + * 开始时间 + */ + private String startDate; + + /** + * 结束时间 + */ + private String endDate; + + /** + * 产品型号 + */ + private String productType; + + /** + * 镀种 + */ + private String plate; + + /** + * 作业中心名称 + */ + private String wcName; + + /** + * 作业中心ID + */ + private String wcId; + + /** + * 作业中心ID + */ + private String wcIds; + + /** + * 工序ID + */ + private String ppsId; + + /** + * 工序ID + */ + private String ppsIds; + + /** + * 工序名称 + */ + private String ppsName; + + /** + * 生产标识 + */ + private String prodIdent; + + /** + * 生产标识 + */ + private String prodIdents; + + /** + * 最小单批数量 + */ + private String minSingleBatchNo; + + /** + * 最大单批数量 + */ + private String maxSingleBatchNo; + + /** + * 最小总面积 + */ + private String minTotalArea; + + /** + * 最大总面积 + */ + private String maxTotalArea; + + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/entity/BsSalaryStandardEntity.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/entity/BsSalaryStandardEntity.java new file mode 100644 index 00000000..4cbf7dfb --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/entity/BsSalaryStandardEntity.java @@ -0,0 +1,84 @@ +package org.springblade.desk.efficiency.pojo.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.core.mp.base.BaseEntity; + +import java.math.BigDecimal; + +/** + * 薪资标准 实体类 + * + * @author BladeX + * @since 2026-04-23 + */ +@Data +@TableName("BS_SALARY_STANDARD") +@Schema(description = "BsSalaryStandard对象") +@EqualsAndHashCode(callSuper = true) +public class BsSalaryStandardEntity extends BaseEntity { + + /** + * 规则类型 + */ + @Schema(description = "规则类型") + private String standardType; + + /** + * 工序ID + */ + @Schema(description = "工序ID") + private Long processId; + + /** + * 零件号 + */ + @Schema(description = "零件号") + private String partNo; + + /** + * 工人结算价 + */ + @Schema(description = "工人结算价") + private BigDecimal settlementPrice; + + /** + * 工人结算单位 + */ + @Schema(description = "工人结算单位") + private String settlementUnit; + + /** + * 阶梯类型 + */ + @Schema(description = "阶梯类型") + private String stepType; + + /** + * 阶梯 + */ + @Schema(description = "阶梯") + private String step; + + /** + * 阶梯单位 + */ + @Schema(description = "阶梯单位") + private String stepUnit; + + /** + * 阶梯结算价 + */ + @Schema(description = "阶梯结算价") + private String stepSettlementPrice; + + /** + * 阶梯结算单位 + */ + @Schema(description = "阶梯结算单位") + private String stepSettlementUnit; + + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/vo/BsSalaryCalculationVO.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/vo/BsSalaryCalculationVO.java new file mode 100644 index 00000000..5a31d07c --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/vo/BsSalaryCalculationVO.java @@ -0,0 +1,163 @@ +package org.springblade.desk.efficiency.pojo.vo; + +import lombok.Data; + +import java.io.Serial; + +@Data +public class BsSalaryCalculationVO { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 订单号 + */ + private String woCode; + + /** + * 零件号 + */ + private String partCode; + + /** + * 零件名称 + */ + private String partName; + + /** + * 批次号 + */ + private String batchNo; + + /** + * 使用部门 + */ + private String useDept; + + /** + * 镀种 + */ + private String plate; + + /** + * 作业中心 + */ + private String wcName; + + /** + * 班组 + */ + private String team; + + /** + * 工序 + */ + private String ppsName; + + /** + * 定额工时 + */ + private String hourQuota; + + /** + * 准备工时 + */ + private String hourPrepar; + + /** + * 工时额定单位 + */ + private String hqUnit; + + /** + * 报工数 + */ + private String workQty; + + /** + * 总工时 + */ + private String hourTotal; + + /** + * 责任人 + */ + private String worker; + + /** + * 厚度 + */ + private String plateThickness; + + /** + * 产品系列 + */ + private String productType; + + /** + * 生产标识 + */ + private String prodIdent; + + /** + * 单批数量 + */ + private String singleBatchNo; + + /** + * 入库数量 + */ + private String putQuantity; + + /** + * 报废数量 + */ + private String scrapQty; + + /** + * 消耗数量 + */ + private String lossQty; + + /** + * 试验数量 + */ + private String testQty; + + /** + * 单件面积(dm²) + */ + private String poArea; + + /** + * 总面积(d㎡) + */ + private String totalArea; + + /** + * 镀后入库时间 + */ + private String putStoreTime; + + /** + * 金额 + */ + private String wpMoney; + + /** + * 基础薪资金额 + */ + private String baseAmount; + + /** + * 补贴薪资金额 + */ + private String subsidyAmount; + + /** + * 总薪资金额 + */ + private String totalAmount; + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/vo/BsSalaryStandardVO.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/vo/BsSalaryStandardVO.java new file mode 100644 index 00000000..061f0ce4 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/pojo/vo/BsSalaryStandardVO.java @@ -0,0 +1,38 @@ +package org.springblade.desk.efficiency.pojo.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.desk.efficiency.pojo.entity.BsSalaryStandardEntity; + +import java.io.Serial; +import java.math.BigDecimal; + +@Data +@EqualsAndHashCode(callSuper = true) +public class BsSalaryStandardVO extends BsSalaryStandardEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 工序名称 + */ + private String processName; + + /** + * 阶梯下限 + */ + private BigDecimal minStep; + + /** + * 阶梯上限 + */ + private BigDecimal maxStep; + + /** + * 阶梯价格 + */ + private BigDecimal price; + + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/service/IBsSalaryStandardService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/service/IBsSalaryStandardService.java new file mode 100644 index 00000000..211c6d31 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/service/IBsSalaryStandardService.java @@ -0,0 +1,34 @@ +package org.springblade.desk.efficiency.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.core.mp.base.BaseService; +import org.springblade.desk.efficiency.pojo.entity.BsSalaryStandardEntity; +import org.springblade.desk.efficiency.pojo.vo.BsSalaryStandardVO; + +/** + * 薪资规则 服务类 + * + * @author BladeX + * @since 2026-04-20 + */ +public interface IBsSalaryStandardService extends BaseService { + + /** + * 自定义分页 + * + * @param page 分页参数 + * @param bsSalaryStandard 查询参数 + * @return IPage + */ + IPage selectBsSalaryStandardPage(IPage page, BsSalaryStandardVO bsSalaryStandard); + + /** + * 查询匹配的薪资标准 + * + * @param processId 工序ID + * @param partNo 零件号 + * @param standardType 薪资标准类型 + * @return + */ + BsSalaryStandardEntity getStandard(Long processId, String partNo, String standardType); +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/service/impl/BsEfficiencyTempServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/service/impl/BsEfficiencyTempServiceImpl.java index a20a3d00..f3a5b53c 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/service/impl/BsEfficiencyTempServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/service/impl/BsEfficiencyTempServiceImpl.java @@ -61,6 +61,12 @@ public class BsEfficiencyTempServiceImpl extends BaseServiceImpl implements IBsSalaryStandardService { + + @Override + public IPage selectBsSalaryStandardPage(IPage page, BsSalaryStandardVO bsSalaryStandard) { + return page.setRecords(baseMapper.selectBsSalaryStandardPage(page, bsSalaryStandard)); + } + + @Override + public BsSalaryStandardEntity getStandard(Long processId, String partNo, String standardType) { + List standardList = this.list(new LambdaQueryWrapper().eq(BsSalaryStandardEntity::getProcessId, processId).in(BsSalaryStandardEntity::getStandardType, Arrays.asList(standardType, "1"))); + BsSalaryStandardEntity bsSalaryStandardEntity = BsSalaryUtil.matchBestRule(standardList, partNo, Integer.getInteger(standardType)); + return bsSalaryStandardEntity; + } + +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/util/BsSalaryUtil.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/util/BsSalaryUtil.java new file mode 100644 index 00000000..c8baf826 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/efficiency/util/BsSalaryUtil.java @@ -0,0 +1,163 @@ +package org.springblade.desk.efficiency.util; + +import org.springblade.desk.efficiency.enums.BsSalaryStandardEnum; +import org.springblade.desk.efficiency.pojo.entity.BsSalaryStandardEntity; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class BsSalaryUtil { + + /** + * 最终入口方法:返回匹配到的唯一最高优先级规则 + * + * @param ruleList 从数据库查出的规则(按工序+类型) + * @param inputPartNo 前端输入的零件号(如 4005) + * @param standardType 2军品 3非军品 + * @return 唯一匹配规则 + */ + public static BsSalaryStandardEntity matchBestRule(List ruleList, String inputPartNo, Integer standardType) { + if (ruleList == null || ruleList.isEmpty()) return null; + + return ruleList.stream() + .filter(rule -> isMatch(rule.getPartNo(), inputPartNo)) + .sorted(comparator(standardType)) // 按优先级排序 + .findFirst() + .orElse(null); + } + + /** + * 【核心】零件号匹配方法 + * + * @param rulePartNo 规则:100 200 300 400% + * @param inputPartNo 输入:4005 + */ + private static boolean isMatch(String rulePartNo, String inputPartNo) { + // 规则为空 → 直接匹配(兜底) + if (!StringUtils.hasText(rulePartNo)) { + return true; + } + // 按空格拆分规则段 + String[] parts = rulePartNo.split("\\s+"); + for (String part : parts) { + if (matchSinglePart(part, inputPartNo)) { + return true; // 任意一段匹配就成功 + } + } + return false; + } + + /** + * 单段匹配:支持 % 通配符 + * 400% → ^400.*$ + */ + private static boolean matchSinglePart(String rulePart, String input) { + if (!StringUtils.hasText(rulePart) || !StringUtils.hasText(input)) { + return false; + } + // 把 % 转成正则 .* (只允许后缀%) + String regex = rulePart.replace("%", ".*"); + return Pattern.matches(regex, input); + } + + /** + * 优先级排序器 + */ + private static Comparator comparator(Integer salaryType) { + return (r1, r2) -> { + int p1 = getPriority(r1, salaryType); + int p2 = getPriority(r2, salaryType); + return Integer.compare(p1, p2); // 小的在前 + }; + } + + /** + * 计算优先级:数字越小越优先 + */ + private static int getPriority(BsSalaryStandardEntity rule, Integer standardType) { + boolean isEmpty = !StringUtils.hasText(rule.getPartNo()); + boolean isMatch = isMatch(rule.getPartNo(), "dummy"); // 外层已过滤 + if (standardType == 2) { // 军品 + if (Integer.parseInt(rule.getStandardType()) == 2 && isMatch) return 1; + if (Integer.parseInt(rule.getStandardType()) == 2 && isEmpty) return 2; + if (Integer.parseInt(rule.getStandardType()) == 1 && isMatch) return 3; + if (Integer.parseInt(rule.getStandardType()) == 1 && isEmpty) return 4; + } else { // 非军品 + if (Integer.parseInt(rule.getStandardType()) == 3 && isMatch) return 1; + if (Integer.parseInt(rule.getStandardType()) == 3 && isEmpty) return 2; + if (Integer.parseInt(rule.getStandardType()) == 1 && isMatch) return 3; + if (Integer.parseInt(rule.getStandardType()) == 1 && isEmpty) return 4; + } + return 99; + } + + + /** + * 计算阶梯价格 + * + * @param stepStr + * @param stepPriceStr + * @param count + * @return + */ + public static BigDecimal calcStepAmount(String stepStr, String stepPriceStr, BigDecimal count, String stepSettlementUnit, BigDecimal settlementPrice) { + // 空值校验 + if (!StringUtils.hasText(stepStr) || !StringUtils.hasText(stepPriceStr) || count == null || count.compareTo(BigDecimal.ZERO) <= 0) { + return BigDecimal.ZERO; + } + + // 解析阶梯区间 + List stepList = Arrays.stream(stepStr.split(" ")) + .filter(StringUtils::hasText) + .map(BigDecimal::new) + .collect(Collectors.toList()); + // 解析阶梯价格 + List priceList = Arrays.stream(stepPriceStr.split(" ")) + .filter(StringUtils::hasText) + .map(BigDecimal::new) + .collect(Collectors.toList()); + + // 格式非法:价格必须比阶梯多1位 + if (priceList.size() != stepList.size() + 1) { + return BigDecimal.ZERO; + } + BigDecimal totalAmount = BigDecimal.ZERO; + BigDecimal remain = count; + BigDecimal preStep = BigDecimal.ZERO; + // 遍历每一档阶梯 + BigDecimal one = new BigDecimal(1); + for (int i = 0; i < stepList.size() && remain.compareTo(BigDecimal.ZERO) > 0; i++) { + BigDecimal currStep = stepList.get(i).subtract(one); + BigDecimal stepDiff = currStep.subtract(preStep); + // 当前区间实际耗用数量 + BigDecimal useNum = remain.min(stepDiff); + // 累加金额 + if (BsSalaryStandardEnum.STEP_SETTLEMENT_UNIT_BATCH.getCode().equals(stepSettlementUnit)) { + totalAmount = totalAmount.add(priceList.get(i)); + } + if (BsSalaryStandardEnum.STEP_SETTLEMENT_UNIT_MULTIPLE.getCode().equals(stepSettlementUnit)) { + totalAmount = totalAmount.add(useNum.multiply(priceList.get(i)).multiply(settlementPrice)); + } + // 剩余数量 + remain = remain.subtract(useNum); + // 记录上一档阶梯 + preStep = currStep; + } + // 超出所有阶梯的部分,取最后一档价格 + if (remain.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal lastPrice = priceList.get(priceList.size() - 1); + if (BsSalaryStandardEnum.STEP_SETTLEMENT_UNIT_BATCH.getCode().equals(stepSettlementUnit)) { + totalAmount = totalAmount.add(lastPrice); + } + if (BsSalaryStandardEnum.STEP_SETTLEMENT_UNIT_MULTIPLE.getCode().equals(stepSettlementUnit)) { + totalAmount = totalAmount.add(remain.multiply(lastPrice).multiply(settlementPrice)); + } + } + return totalAmount; + } +} \ No newline at end of file diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkPlanMapper.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkPlanMapper.java index ad0586ed..fdc84f3e 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkPlanMapper.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkPlanMapper.java @@ -5,6 +5,8 @@ import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.springblade.desk.dashboard.pojo.entity.DsPartRelationEntity; import org.springblade.desk.dashboard.pojo.entity.DsPartSub; +import org.springblade.desk.efficiency.pojo.dto.BsSalaryCalculationDTO; +import org.springblade.desk.efficiency.pojo.vo.BsSalaryCalculationVO; import org.springblade.desk.produce.pojo.dto.MesRbFilePreserveDetailDTO; import org.springblade.desk.produce.pojo.entity.*; import org.springblade.desk.produce.pojo.vo.*; @@ -89,4 +91,6 @@ public interface WorkPlanMapper extends BaseMapper { List getByRfpsIdMesNew(Long id); List getWorkOrderProcess(String cardNo); + + List selectBsSalaryCalculationPage(IPage page, BsSalaryCalculationDTO bsSalaryCalculation); } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkPlanMapper.xml b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkPlanMapper.xml index fa8c69a6..6d2101c6 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkPlanMapper.xml +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/mapper/WorkPlanMapper.xml @@ -437,4 +437,123 @@ ORDER BY wp.ORDERS ASC + + diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/IWorkOrderService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/IWorkOrderService.java index e42f562e..023c77a8 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/IWorkOrderService.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/IWorkOrderService.java @@ -270,6 +270,12 @@ public interface IWorkOrderService extends BaseService { */ Map queryAllocationMess(AllocationMessPageDTO dto); + /** + * 薪资计算 + * @param woId + */ + void salaryCalculation(Long woId); + /** * 查询配套统计信息 * @param dto 查询条件 diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/IWorkPlanService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/IWorkPlanService.java index 66a8ee8f..045b4957 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/IWorkPlanService.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/IWorkPlanService.java @@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import org.springblade.common.exception.BusinessException; import org.springblade.core.mp.base.BaseService; import org.springblade.core.secure.BladeUser; +import org.springblade.desk.efficiency.pojo.dto.BsSalaryCalculationDTO; +import org.springblade.desk.efficiency.pojo.vo.BsSalaryCalculationVO; import org.springblade.desk.produce.pojo.entity.WorkOrder; import org.springblade.desk.produce.pojo.entity.WorkPlan; import org.springblade.desk.produce.pojo.vo.ProduceMonitorWorkPlanVO; @@ -57,4 +59,6 @@ public interface IWorkPlanService extends BaseService { void workPlanEnd(Long wpId, Date putStoreTime, Double makeQty); List getWorkOrderProcess(String cardNo); + + IPage selectBsSalaryCalculationPage(IPage page, BsSalaryCalculationDTO bsSalaryCalculation); } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java index ba0be64b..212dc136 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java @@ -40,6 +40,10 @@ import org.springblade.desk.device.pojo.entity.RackSetEntity; import org.springblade.desk.device.service.IEquipmentService; import org.springblade.desk.device.service.IFeiBaSetService; import org.springblade.desk.device.service.IRackSetService; +import org.springblade.desk.efficiency.enums.BsSalaryStandardEnum; +import org.springblade.desk.efficiency.pojo.entity.BsSalaryStandardEntity; +import org.springblade.desk.efficiency.service.IBsSalaryStandardService; +import org.springblade.desk.efficiency.util.BsSalaryUtil; import org.springblade.desk.energy.util.HttpRequestService; import org.springblade.desk.logistics.pojo.dto.AllocationMessPageDTO; import org.springblade.desk.logistics.pojo.vo.AllocationMessVO; @@ -61,7 +65,9 @@ import org.springblade.desk.quality.service.*; import org.springblade.desk.util.date.DateUtils; import org.springblade.erpdata.feign.IErpDataLogisticsClient; import org.springblade.erpdata.feign.IErpDataProduceClient; +import org.springblade.scheduling.pojo.entity.QualityGradeEntity; import org.springblade.scheduling.pojo.entity.WorkOrderEntity; +import org.springblade.scheduling.pojo.entity.WorkPlanEntity; import org.springblade.system.cache.DictCache; import org.springblade.system.cache.UserCache; import org.springblade.system.feign.IDictClient; @@ -184,6 +190,10 @@ public class WorkOrderServiceImpl extends BaseServiceImpl selectWorkOrderPage(IPage page, WorkOrderDTO workOrder) { return page.setRecords(baseMapper.selectWorkOrderPage(page, workOrder)); @@ -2793,4 +2803,106 @@ public class WorkOrderServiceImpl extends BaseServiceImpl qualityGrades = qualityGradeService.list(new LambdaQueryWrapper().eq(QualityGradeEntity::getQualityGrade, yieldOrder.getProductIdent())); + if (!CollectionUtils.isEmpty(qualityGrades)) { + if (!StringUtils.isEmpty(qualityGrades.get(0).getType())) { + boolean hasOne = Arrays.asList(qualityGrades.get(0).getType().split(",")).contains("1"); + if (hasOne) { + // 军品 + standardType = "2"; + } + } + } + List updList = new ArrayList<>(); + List workPlanList = workPlanService.selectByWoId(woId); + for (WorkPlanEntity workPlanEntity : workPlanList) { + if (!"0".equals(StringUtils.trim(workPlanEntity.getOem())) || workPlanEntity.getWorkQty() <= 0) { + continue; + } + BsSalaryStandardEntity standard = bsSalaryStandardService.getStandard(workPlanEntity.getPpsId(), yieldOrder.getPartCode(), standardType); + if (standard == null) { + continue; + } + // 基础薪资金额 + BigDecimal baseAmount = new BigDecimal(0); + // 补贴薪资金额 + BigDecimal subsidyAmount = new BigDecimal(0); + // 面积 + BigDecimal ypArea = new BigDecimal(yieldOrder.getYpArea()); + // 数量 + BigDecimal workQty = new BigDecimal(workPlanEntity.getWorkQty()); + // 计算基础薪资金额 + if (BsSalaryStandardEnum.SETTLEMENT_UNIT_PIECE.getCode().equals(standard.getSettlementUnit())) { + // 件 = 工人结算价 * 数量 + baseAmount = standard.getSettlementPrice().multiply(workQty); + } + if (BsSalaryStandardEnum.SETTLEMENT_UNIT_BATCH.getCode().equals(standard.getSettlementUnit())) { + // 批 = 工人结算价 + baseAmount = standard.getSettlementPrice(); + } + if (BsSalaryStandardEnum.SETTLEMENT_UNIT_AREA.getCode().equals(standard.getSettlementUnit())) { + // 面积 = 工人结算价 * 数量 * 面积 + baseAmount = standard.getSettlementPrice().multiply(ypArea).multiply(workQty); + } + // 计算补贴薪资金额 + if (BsSalaryStandardEnum.STEP_TYPE_NON.getCode().equals(standard.getStepType())) { + // 无补贴 = 0 + subsidyAmount = new BigDecimal(0); + } + if (BsSalaryStandardEnum.STEP_TYPE_FIXED.getCode().equals(standard.getStepType())) { + BigDecimal stepSettlementPrice = new BigDecimal(standard.getStepSettlementPrice()); + BigDecimal stepBasePrice = new BigDecimal(0); + // 固定补贴按批 = 阶梯结算价 + if (BsSalaryStandardEnum.STEP_SETTLEMENT_UNIT_BATCH.getCode().equals(standard.getStepSettlementUnit())) { + subsidyAmount = stepSettlementPrice; + } + if (BsSalaryStandardEnum.STEP_SETTLEMENT_UNIT_MULTIPLE.getCode().equals(standard.getStepSettlementUnit())) { + // 固定补贴按件 = 阶梯结算价 * 数量 + if (BsSalaryStandardEnum.STEP_UNIT_PIECE.getCode().equals(standard.getStepUnit())) { + stepBasePrice = stepSettlementPrice.multiply(workQty); + } + // 固定补贴按面积 = 阶梯结算价 * 数量 * 面积 + if (BsSalaryStandardEnum.STEP_UNIT_AREA.getCode().equals(standard.getStepUnit())) { + stepBasePrice = stepSettlementPrice.multiply(ypArea).multiply(workQty); + } + // 固定补贴按倍 = 固定补贴金额 * 工人结算价格 + subsidyAmount = stepBasePrice.multiply(standard.getSettlementPrice()); + } + } + if (BsSalaryStandardEnum.STEP_TYPE_STEP.getCode().equals(standard.getStepType())) { + if (BsSalaryStandardEnum.STEP_UNIT_PIECE.getCode().equals(standard.getStepUnit())) { + subsidyAmount = BsSalaryUtil.calcStepAmount(standard.getStep(), standard.getStepSettlementPrice(), workQty, standard.getStepSettlementUnit(), standard.getSettlementPrice()); + } + if (BsSalaryStandardEnum.STEP_UNIT_AREA.getCode().equals(standard.getStepUnit())) { + subsidyAmount = BsSalaryUtil.calcStepAmount(standard.getStep(), standard.getStepSettlementPrice(), workQty.multiply(ypArea), standard.getStepSettlementUnit(), standard.getSettlementPrice()); + } + } + WorkPlan upd = new WorkPlan(); + upd.setId(workPlanEntity.getId()); + upd.setBaseAmount(baseAmount); + upd.setSubsidyAmount(subsidyAmount); + updList.add(upd); + } + if (!CollectionUtils.isEmpty(updList)) { + workPlanService.saveOrUpdateBatch(updList); + } + } catch (Exception e) { + log.error("订单:" + woId + ",薪资计算错误", e); + } + + } } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkPlanServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkPlanServiceImpl.java index 0c48360f..f2307cdd 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkPlanServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkPlanServiceImpl.java @@ -21,6 +21,10 @@ import org.springblade.desk.dashboard.pojo.entity.BsTeamSetEntity; import org.springblade.desk.dashboard.pojo.entity.DsProcessMeasuringToolEntity; import org.springblade.desk.dashboard.pojo.entity.DsProcessProjectEntity; import org.springblade.desk.dashboard.service.*; +import org.springblade.desk.efficiency.pojo.dto.BsSalaryCalculationDTO; +import org.springblade.desk.efficiency.pojo.vo.BsSalaryCalculationVO; +import org.springblade.desk.order.pojo.entity.YieldOrder; +import org.springblade.desk.order.service.IYieldOrderService; import org.springblade.desk.produce.mapper.PlateAroundMapper; import org.springblade.desk.produce.mapper.WorkPlanMapper; import org.springblade.desk.produce.pojo.entity.*; @@ -318,4 +322,9 @@ public class WorkPlanServiceImpl extends BaseServiceImpl getWorkOrderProcess(String cardNo) { return baseMapper.getWorkOrderProcess(cardNo); } + + @Override + public IPage selectBsSalaryCalculationPage(IPage page, BsSalaryCalculationDTO bsSalaryCalculation) { + return page.setRecords(baseMapper.selectBsSalaryCalculationPage(page, bsSalaryCalculation)); + } } diff --git a/blade-service/blade-desk/src/main/resources/Excel/efficiency/工资维护标准.xls b/blade-service/blade-desk/src/main/resources/Excel/efficiency/工资维护标准.xls new file mode 100644 index 0000000000000000000000000000000000000000..2097718e4793d6979ea37ef38691e8094d424b10 GIT binary patch literal 20992 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 literal 0 HcmV?d00001