排产相关-sjx

develop-QA
sunjianxi 1 day ago
parent e7c7984aa6
commit b19099a417
  1. 62
      blade-service-api/blade-scheduling-api/src/main/java/org/springblade/scheduling/pojo/enums/WorkOrderEnum.java
  2. 161
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/controller/OutsourceProcessController.java
  3. 2
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/dto/WorkOrderDto.java
  4. 74
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/entity/OutsourceProcessEntity.java
  5. 6
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/entity/YieldOrderCraftEntity.java
  6. 93
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/excel/OutsourceProcessExcel.java
  7. 64
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/mapper/OutsourceProcessMapper.java
  8. 37
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/mapper/OutsourceProcessMapper.xml
  9. 35
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/mapper/WorkOrderMapper.xml
  10. 62
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/service/IOutsourceProcessService.java
  11. 24
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/service/impl/EquipResourceServiceImpl.java
  12. 63
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/service/impl/OutsourceProcessServiceImpl.java
  13. 381
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/service/impl/WorkOrderServiceImpl.java
  14. 46
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/vo/OutsourceProcessVO.java
  15. 60
      blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/wrapper/OutsourceProcessWrapper.java

@ -0,0 +1,62 @@
package org.springblade.scheduling.pojo.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.core.tool.utils.StringPool;
import java.util.Arrays;
/**
* 车间订单枚举
*
* @author lqk
* @date 2025-12-19 9:25
*/
@Getter
@AllArgsConstructor
public enum WorkOrderEnum {
EMPTY(StringPool.EMPTY, -1),
/**
* 状态枚举
*/
STATUS_PRODUCT_WAITING("待生产", 1),
STATUS_PRODUCTING("生产中", 2),
STATUS_INSPECTIONING("检验中", 3),
STATUS_COMPLETED("已完工", 4),
STATUS_ADJUDICATING("审理中", 5),
STATUS_SCRAP("已报废", 6),
STATUS_REWORK("已返工", 7)
;
final String name;
final int category;
/**
* 匹配枚举值
*
* @param name 名称
* @return BladeUserEnum
*/
public static WorkOrderEnum of(String name) {
return Arrays.stream(WorkOrderEnum.values())
.filter(userEnum -> userEnum.getName().equalsIgnoreCase(name != null ? name : "web"))
.findFirst()
// 在没有找到匹配项时返回默认值
.orElse(WorkOrderEnum.EMPTY);
}
/**
* 根据值获取名称
*
* @param category
* @return
*/
public static String getName(int category) {
WorkOrderEnum item = Arrays.stream(WorkOrderEnum.values())
.filter(enumItem -> enumItem.getCategory() == category)
.findFirst()
.orElse(null);
return ObjectUtil.isEmpty(item) ? StringPool.EMPTY : item.getName();
}
}

@ -0,0 +1,161 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.scheduling.scheduling.controller;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;
import jakarta.validation.Valid;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.annotation.IsAdmin;
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.scheduling.scheduling.entity.OutsourceProcessEntity;
import org.springblade.scheduling.scheduling.excel.OutsourceProcessExcel;
import org.springblade.scheduling.scheduling.service.IOutsourceProcessService;
import org.springblade.scheduling.scheduling.vo.OutsourceProcessVO;
import org.springblade.scheduling.scheduling.wrapper.OutsourceProcessWrapper;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.tool.constant.BladeConstant;
import java.util.Map;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
/**
* 外协工序表 控制器
*
* @author BladeX
* @since 2025-12-24
*/
@RestController
@AllArgsConstructor
@RequestMapping("/outsourceProcess")
@Tag(name = "外协工序表", description = "外协工序表接口")
public class OutsourceProcessController extends BladeController {
private final IOutsourceProcessService outsourceProcessService;
/**
* 外协工序表 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入OutsourceProcess")
public R<OutsourceProcessVO> detail(OutsourceProcessEntity OutsourceProcess) {
OutsourceProcessEntity detail = outsourceProcessService.getOne(Condition.getQueryWrapper(OutsourceProcess));
return R.data(OutsourceProcessWrapper.build().entityVO(detail));
}
/**
* 外协工序表 分页
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入OutsourceProcess")
public R<IPage<OutsourceProcessVO>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> OutsourceProcess, Query query) {
IPage<OutsourceProcessEntity> pages = outsourceProcessService.page(Condition.getPage(query), Condition.getQueryWrapper(OutsourceProcess, OutsourceProcessEntity.class));
return R.data(OutsourceProcessWrapper.build().pageVO(pages));
}
/**
* 外协工序表 自定义分页
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
@Operation(summary = "分页", description = "传入OutsourceProcess")
public R<IPage<OutsourceProcessVO>> page(OutsourceProcessVO OutsourceProcess, Query query) {
IPage<OutsourceProcessVO> pages = outsourceProcessService.selectOutsourceProcessPage(Condition.getPage(query), OutsourceProcess);
return R.data(pages);
}
/**
* 外协工序表 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入OutsourceProcess")
public R save(@Valid @RequestBody OutsourceProcessEntity OutsourceProcess) {
return R.status(outsourceProcessService.save(OutsourceProcess));
}
/**
* 外协工序表 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入OutsourceProcess")
public R update(@Valid @RequestBody OutsourceProcessEntity OutsourceProcess) {
return R.status(outsourceProcessService.updateById(OutsourceProcess));
}
/**
* 外协工序表 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入OutsourceProcess")
public R submit(@Valid @RequestBody OutsourceProcessEntity OutsourceProcess) {
return R.status(outsourceProcessService.saveOrUpdate(OutsourceProcess));
}
/**
* 外协工序表 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(outsourceProcessService.deleteLogic(Func.toLongList(ids)));
}
/**
* 导出数据
*/
@IsAdmin
@GetMapping("/export")
@ApiOperationSupport(order = 9)
@Operation(summary = "导出数据", description = "传入OutsourceProcess")
public void export(@Parameter(hidden = true) @RequestParam Map<String, Object> OutsourceProcess, BladeUser bladeUser, HttpServletResponse response) {
QueryWrapper<OutsourceProcessEntity> queryWrapper = Condition.getQueryWrapper(OutsourceProcess, OutsourceProcessEntity.class);
//if (!AuthUtil.isAdministrator()) {
// queryWrapper.lambda().eq(OutsourceProcess::getTenantId, bladeUser.getTenantId());
//}
//queryWrapper.lambda().eq(OutsourceProcessEntity::getIsDeleted, BladeConstant.DB_NOT_DELETED);
List<OutsourceProcessExcel> list = outsourceProcessService.export(queryWrapper);
ExcelUtil.export(response, "外协工序表数据" + DateUtil.time(), "外协工序表数据表", list, OutsourceProcessExcel.class);
}
}

@ -40,5 +40,7 @@ public class WorkOrderDto {
private Integer schedulingCount;
private String schedulingRate;
private String productIdent;
private String receiveTime;
private String priorityAps;
}

@ -0,0 +1,74 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.scheduling.scheduling.entity;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import com.baomidou.mybatisplus.annotation.TableName;
import java.math.BigDecimal;
import java.util.Date;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.tenant.mp.TenantEntity;
import java.io.Serial;
/**
* 外协工序表 实体类
*
* @author BladeX
* @since 2025-12-24
*/
@Data
@TableName("MES_OUTSOURCE_PROCESS")
@Schema(description = "MesOutsourceProcess对象")
@EqualsAndHashCode(callSuper = true)
public class OutsourceProcessEntity extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 工序id
*/
@Schema(description = "工序id")
private String processId;
/**
* 工序名称
*/
@Schema(description = "工序名称")
private String processName;
/**
* 时间
*/
@Schema(description = "时间")
private Integer days;
/**
* 备注
*/
@Schema(description = "备注")
private String remarks;
}

@ -122,4 +122,10 @@ public class YieldOrderCraftEntity extends TenantEntity {
@Schema(description = "作业中心")
private Long workCenterId;
/**
* 是否外协
*/
@Schema(description = "是否外协")
private Boolean isOutsource;
}

@ -0,0 +1,93 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.scheduling.scheduling.excel;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import java.io.Serializable;
import java.io.Serial;
/**
* 外协工序表 Excel实体类
*
* @author BladeX
* @since 2025-12-24
*/
@Data
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class OutsourceProcessExcel implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ColumnWidth(20)
@ExcelProperty("ID")
private BigDecimal id;
/**
* 工序id
*/
@ColumnWidth(20)
@ExcelProperty("工序id")
private BigDecimal processId;
/**
* 工序名称
*/
@ColumnWidth(20)
@ExcelProperty("工序名称")
private String processName;
/**
* 时间
*/
@ColumnWidth(20)
@ExcelProperty("时间")
private Long days;
/**
* 备注
*/
@ColumnWidth(20)
@ExcelProperty("备注")
private String remarks;
/**
* 是否已删除
*/
@ColumnWidth(20)
@ExcelProperty("是否已删除")
private Long isDeleted;
}

@ -0,0 +1,64 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.scheduling.scheduling.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import org.springblade.scheduling.scheduling.entity.OutsourceProcessEntity;
import org.springblade.scheduling.scheduling.excel.OutsourceProcessExcel;
import org.springblade.scheduling.scheduling.vo.OutsourceProcessVO;
import java.util.List;
/**
* 外协工序表 Mapper 接口
*
* @author BladeX
* @since 2025-12-24
*/
public interface OutsourceProcessMapper extends BaseMapper<OutsourceProcessEntity> {
/**
* 自定义分页
*
* @param page 分页参数
* @param OutsourceProcess 查询参数
* @return List<OutsourceProcessVO>
*/
List<OutsourceProcessVO> selectOutsourceProcessPage(IPage page, OutsourceProcessVO outsourceProcess);
/**
* 获取导出数据
*
* @param queryWrapper 查询条件
* @return List<OutsourceProcessExcel>
*/
List<OutsourceProcessExcel> export(@Param("ew") Wrapper<OutsourceProcessEntity> queryWrapper);
}

@ -0,0 +1,37 @@
<?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="org.springblade.scheduling.scheduling.mapper.OutsourceProcessMapper">
<!-- 通用查询映射结果 -->
<resultMap id="outsourceProcessResultMap" type="org.springblade.scheduling.scheduling.entity.OutsourceProcessEntity">
<result column="ID" property="id"/>
<result column="PROCESS_ID" property="processId"/>
<result column="PROCESS_NAME" property="processName"/>
<result column="DAYS" property="days"/>
<result column="REMARKS" property="remarks"/>
<result column="CREATE_USER" property="createUser"/>
<result column="CREATE_DEPT" property="createDept"/>
<result column="CREATE_TIME" property="createTime"/>
<result column="UPDATE_USER" property="updateUser"/>
<result column="UPDATE_TIME" property="updateTime"/>
<result column="STATUS" property="status"/>
<result column="IS_DELETED" property="isDeleted"/>
</resultMap>
<select id="selectOutsourceProcessPage" resultMap="outsourceProcessResultMap">
select * from MES_OUTSOURCE_PROCESS
<where>
is_deleted = 0
<if test="param2.processId !=null">
and process_id = #{param2.processId}
</if>
</where>
</select>
<select id="export" resultType="org.springblade.scheduling.scheduling.excel.OutsourceProcessExcel">
SELECT * FROM MES_OUTSOURCE_PROCESS ${ew.customSqlSegment}
</select>
</mapper>

@ -92,6 +92,7 @@
a.batch_no AS "batchNo",
a.make_qty AS "makeQty",
a.card_no AS "cardNO",
g.priority_aps AS "priorityAps",
g.product_ident AS "productIdent",
f.name AS "currentProcessName",
d.name AS "processName",
@ -115,9 +116,9 @@
LEFT JOIN BS_PROCESS_SET f on e.pps_id = f.id
LEFT JOIN MES_YIELD_ORDER g on g.id = a.yo_id
<where>
a.is_deleted = 0 and b.is_deleted = 0
a.is_deleted = 0 and b.is_deleted = 0 and a.status in (1,2,3,5)
<if test="startTime !=null and startTime != ''">
and (to_char(b.start_time,'YYYY-MM-DD') = #{startTime} or (b.start_time <![CDATA[ < ]]> to_date(CONCAT(#{startTime},' 00:00:00'),'YYYY-MM-DD HH24:MI:SS') and b.end_time <![CDATA[ > ]]> to_date(CONCAT(#{startTime},' 23:59:59'),'YYYY-MM-DD HH24:MI:SS')))
and (to_char(b.start_time,'YYYY-MM-DD') = #{startTime} or to_char(b.end_time,'YYYY-MM-DD') = #{startTime} or (b.start_time <![CDATA[ < ]]> to_date(CONCAT(#{startTime},' 00:00:00'),'YYYY-MM-DD HH24:MI:SS') and b.end_time <![CDATA[ > ]]> to_date(CONCAT(#{startTime},' 23:59:59'),'YYYY-MM-DD HH24:MI:SS')))
</if>
<if test="woCode !=null and woCode != ''">
and a.wo_code = #{woCode}
@ -131,8 +132,20 @@
<if test="processName !=null and processName != ''">
and d.name = #{processName}
</if>
<if test="partCode !=null and partCode != ''">
and a.part_code = #{partCode}
</if>
<if test="batchNo !=null and batchNo != ''">
and a.batch_no = #{batchNo}
</if>
<if test="receiveTime !=null and receiveTime != ''">
and g.receive_time = #{receiveTime}
</if>
<if test="planStatus !=null and planStatus != ''">
and b.status = #{planStatus}
</if>
</where>
order by a.WO_CODE,b.start_time
order by b.start_time,a.WO_CODE
</select>
<select id="getMaxByCodePattern" resultType="java.lang.String">
@ -206,9 +219,9 @@
LEFT JOIN BS_TEAM_SET g on c.MAKE_TEAM = g.ID
LEFT JOIN MES_WORK_PLAN h on h.wo_id = a.id
<where>
a.is_deleted = 0 and h.is_deleted = 0
a.is_deleted = 0 and h.is_deleted = 0 and a.status in (1,2,3,5)
<if test="startTime !=null and startTime != ''">
and (to_char(h.start_time,'YYYY-MM-DD') = #{startTime} or (h.start_time <![CDATA[ < ]]> to_date(CONCAT(#{startTime},' 00:00:00'),'YYYY-MM-DD HH24:MI:SS') and h.end_time <![CDATA[ > ]]> to_date(CONCAT(#{startTime},' 23:59:59'),'YYYY-MM-DD HH24:MI:SS')))
and (to_char(h.start_time,'YYYY-MM-DD') = #{startTime} or to_char(h.end_time,'YYYY-MM-DD') = #{startTime} or (h.start_time <![CDATA[ < ]]> to_date(CONCAT(#{startTime},' 00:00:00'),'YYYY-MM-DD HH24:MI:SS') and h.end_time <![CDATA[ > ]]> to_date(CONCAT(#{startTime},' 23:59:59'),'YYYY-MM-DD HH24:MI:SS')))
</if>
<if test="woCode !=null and woCode != ''">
and a.wo_code = #{woCode}
@ -219,6 +232,18 @@
<if test="processName !=null and processName != ''">
and d.name = #{processName}
</if>
<if test="partCode !=null and partCode != ''">
and a.part_code = #{partCode}
</if>
<if test="batchNo !=null and batchNo != ''">
and a.batch_no = #{batchNo}
</if>
<if test="receiveTime !=null and receiveTime != ''">
and b.receive_time = #{receiveTime}
</if>
<if test="planStatus !=null and planStatus != ''">
and h.status = #{planStatus}
</if>
</where>
GROUP BY
a.WO_CODE,

@ -0,0 +1,62 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.scheduling.scheduling.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.scheduling.scheduling.entity.OutsourceProcessEntity;
import org.springblade.scheduling.scheduling.excel.OutsourceProcessExcel;
import org.springblade.scheduling.scheduling.vo.OutsourceProcessVO;
import java.util.List;
/**
* 外协工序表 服务类
*
* @author BladeX
* @since 2025-12-24
*/
public interface IOutsourceProcessService extends BaseService<OutsourceProcessEntity> {
/**
* 自定义分页
*
* @param page 分页参数
* @param OutsourceProcess 查询参数
* @return IPage<OutsourceProcessVO>
*/
IPage<OutsourceProcessVO> selectOutsourceProcessPage(IPage<OutsourceProcessVO> page, OutsourceProcessVO outsourceProcess);
/**
* 导出数据
*
* @param queryWrapper 查询条件
* @return List<OutsourceProcessExcel>
*/
List<OutsourceProcessExcel> export(Wrapper<OutsourceProcessEntity> queryWrapper);
}

@ -32,6 +32,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.scheduling.scheduling.entity.EquipAbilityEntity;
import org.springblade.scheduling.scheduling.entity.EquipResourceEntity;
@ -80,21 +81,16 @@ public class EquipResourceServiceImpl extends BaseServiceImpl<EquipResourceMappe
public void initEquipResource(){
//获取包括今天在内未来3天
Date date = new Date();
String today = DateFormatUtils.format(date,"yyyy-MM-dd");
String tomorrow = DateFormatUtils.format(DateUtils.addDays(date,1),"yyyy-MM-dd");
String dayAfterTomorrow = DateFormatUtils.format(DateUtils.addDays(date,2),"yyyy-MM-dd");
List<EquipResourceEntity> list1 = this.list(Wrappers.<EquipResourceEntity>lambdaQuery().eq(EquipResourceEntity::getDateTime,today));
List<EquipResourceEntity> list2 = this.list(Wrappers.<EquipResourceEntity>lambdaQuery().eq(EquipResourceEntity::getDateTime,tomorrow));
List<EquipResourceEntity> list3 = this.list(Wrappers.<EquipResourceEntity>lambdaQuery().eq(EquipResourceEntity::getDateTime,dayAfterTomorrow));
if(CollectionUtils.isEmpty(list1)){
generateData(today);
}
if(CollectionUtils.isEmpty(list2)){
generateData(tomorrow);
}
if(CollectionUtils.isEmpty(list3)){
generateData(dayAfterTomorrow);
for(int i=0;i<7;i++){
String today = DateFormatUtils.format(DateUtils.addDays(date,i),"yyyy-MM-dd");
List<EquipResourceEntity> list = this.list(Wrappers.<EquipResourceEntity>lambdaQuery().eq(EquipResourceEntity::getDateTime,today));
if(CollectionUtils.isEmpty(list)){
generateData(today);
}
}
//删除3天之前的数据
List<EquipResourceEntity> deleteList = this.list(Wrappers.<EquipResourceEntity>lambdaQuery().le(EquipResourceEntity::getDateTime,DateFormatUtils.format(DateUtils.addDays(date,-3),"yyyy-MM-dd")));
this.removeByIds(deleteList.stream().map(BaseEntity::getId).collect(Collectors.toList()));
}
@Override

@ -0,0 +1,63 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.scheduling.scheduling.service.impl;
import org.springblade.scheduling.scheduling.entity.OutsourceProcessEntity;
import org.springblade.scheduling.scheduling.excel.OutsourceProcessExcel;
import org.springblade.scheduling.scheduling.mapper.OutsourceProcessMapper;
import org.springblade.scheduling.scheduling.service.IOutsourceProcessService;
import org.springblade.scheduling.scheduling.vo.OutsourceProcessVO;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseServiceImpl;
import java.util.List;
/**
* 外协工序表 服务实现类
*
* @author BladeX
* @since 2025-12-24
*/
@Service
public class OutsourceProcessServiceImpl extends BaseServiceImpl<OutsourceProcessMapper, OutsourceProcessEntity> implements IOutsourceProcessService {
@Override
public IPage<OutsourceProcessVO> selectOutsourceProcessPage(IPage<OutsourceProcessVO> page, OutsourceProcessVO outsourceProcess) {
return page.setRecords(baseMapper.selectOutsourceProcessPage(page, outsourceProcess));
}
@Override
public List<OutsourceProcessExcel> export(Wrapper<OutsourceProcessEntity> queryWrapper) {
List<OutsourceProcessExcel> OutsourceProcessList = baseMapper.export(queryWrapper);
//OutsourceProcessList.forEach(OutsourceProcess -> {
// OutsourceProcess.setTypeName(DictCache.getValue(DictEnum.YES_NO, OutsourceProcess.getType()));
//});
return OutsourceProcessList;
}
}

@ -81,6 +81,8 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
private final IPersonAbilityService personAbilityService;
private final IEquipResourceService equipResourceService;
private final IPersonResourceService personResourceService;
private final IOutsourceProcessService outsourceProcessService;
private final IProcessSetService processSetService;
@Value("${business.oldMes.url}")
private String oldMesUrl;
@ -115,7 +117,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
public void scheduling() {
//查询待排产订单,状态是3
List<YieldOrderEntity> list =
yieldOrderService.list(Wrappers.<YieldOrderEntity>lambdaQuery().eq(BaseEntity::getStatus, YieldOrderEnum.STATUS_APS.getCategory()).isNotNull(YieldOrderEntity::getWorkCenterId).isNotNull(YieldOrderEntity::getReleaseDate));
yieldOrderService.list(Wrappers.<YieldOrderEntity>lambdaQuery().in(BaseEntity::getStatus, YieldOrderEnum.STATUS_APS.getCategory(),YieldOrderEnum.STATUS_PROCESS_ERROR.getCategory()).isNotNull(YieldOrderEntity::getWorkCenterId).isNotNull(YieldOrderEntity::getReleaseDate));
log.info("待排产订单数量为:" + list.size());
if (CollectionUtils.isNotEmpty(list)) {
//校验已排产订单
@ -133,6 +135,12 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
mainProducerList.forEach(item -> {
mainProducerMap.put(item.getProcessId(), item.getMainProducer());
});
//初始化工序
List<ProcessSetEntity> processList = processSetService.list();
Map<Long, String> processMap = new HashMap<>();
processList.forEach(item -> {
processMap.put(item.getId(), item.getName());
});
//计算cr值
calculateCr(list);
//根据作业中心将订单分组,并根据优先级、cr值、订单需求数量、计划下达时间4个维度进行组内排序
@ -161,7 +169,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
new LinkedBlockingQueue<>(),
r -> new Thread(r, "scheduling-thread-" + System.currentTimeMillis()));
map.forEach((workcenter, orders) -> {
threadPool.execute(() -> allocateResources(orders, personAbilityMap, mainProducerMap, planMap));
threadPool.execute(() -> allocateResources(orders, personAbilityMap, mainProducerMap, planMap, processMap));
});
}
@ -322,7 +330,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
* @since 2025/12/1 18:08
**/
@Transactional(rollbackFor = Exception.class)
public void allocateResources(List<YieldOrderEntity> list, Map<String, PersonAbilityEntity> personAbilityMap, Map<Long, String> mainProducerMap, Map<String, List<WorkPlanEntity>> planMap) {
public void allocateResources(List<YieldOrderEntity> list, Map<String, PersonAbilityEntity> personAbilityMap, Map<Long, String> mainProducerMap, Map<String, List<WorkPlanEntity>> planMap, Map<Long, String> processMap) {
List<WorkOrderEntity> workOrderList = new ArrayList<>();
for (YieldOrderEntity order : list) {
try {
@ -331,8 +339,10 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
List<WorkPlanEntity> workPlanList = new ArrayList<>();
//查询所有工序
List<YieldOrderCraftEntity> craftList = yieldOrderCraftService.list(Wrappers.<YieldOrderCraftEntity>lambdaQuery().eq(YieldOrderCraftEntity::getYoId, order.getId()).ne(YieldOrderCraftEntity::getCaId, 27).orderByAsc(YieldOrderCraftEntity::getProcessNo));
List<Long> workCenterList = craftList.stream().filter(item -> item.getWorkCenterId() != null).map(YieldOrderCraftEntity::getWorkCenterId).collect(Collectors.toList());
if (workCenterList.size() != craftList.size()) {
//过滤非外协工序
List<YieldOrderCraftEntity> craftList1 = craftList.stream().filter(item -> item.getIsOutsource() == false).collect(Collectors.toList());
List<Long> workCenterList = craftList1.stream().filter(item -> item.getWorkCenterId() != null).map(YieldOrderCraftEntity::getWorkCenterId).collect(Collectors.toList());
if (workCenterList.size() != craftList1.size()) {
order.setErrorInfo("工序信息不完整,含有未匹配作业中心的工序");
order.setStatus(YieldOrderEnum.STATUS_PROCESS_ERROR.getCategory());
yieldOrderService.updateById(order);
@ -346,131 +356,169 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
workPlanList = planMap.get(order.getYoCode());
prevProcessEnd = prevProcessEnd.compareTo(workPlanList.get(workPlanList.size() - 1).getEndTime()) > 0 ? prevProcessEnd : workPlanList.get(workPlanList.size() - 1).getEndTime();
}
//处理外协工序,外协可能多个工序连续的,共享开始结束时间
Map<Long,List<YieldOrderCraftEntity>> outSourceMap = craftList.stream().filter(item -> item.getIsOutsource() == true).collect(Collectors.groupingBy(YieldOrderCraftEntity::getOcId));
Map<Long,String> ppsIdMap = new HashMap<>();
for (Map.Entry<Long, List<YieldOrderCraftEntity>> entry : outSourceMap.entrySet()) {
String ppsIdStr = entry.getValue().stream()
.map(entity -> String.valueOf(entity.getPpsId())) // long → String
// 等价写法:.map(entity -> Long.toString(entity.getPpsId()))
.collect(Collectors.joining(",")); // 逗号分隔拼接
ppsIdMap.put(entry.getKey(),ppsIdStr);
}
for (int i = 0; i < craftList.size(); i++) {
YieldOrderCraftEntity craft = craftList.get(i);
if ("设备".equals(mainProducerMap.get(craft.getPpsId()))) {
//根据作业中心查询所有设备
List<EquipAbilityEntity> equipAbilityList = equipAbilityService.list(Wrappers.<EquipAbilityEntity>lambdaQuery().in(EquipAbilityEntity::getWorkCenterId, craft.getWorkCenterId()).eq(EquipAbilityEntity::getCraftId, craft.getCaId()));
if (CollectionUtils.isEmpty(equipAbilityList)) {
order.setErrorInfo("设备未匹配到对应的设备能力");
order.setStatus(YieldOrderEnum.STATUS_PROCESS_ERROR.getCategory());
yieldOrderService.updateById(order);
isSchecuding = false;
break;
//如果是外协的话,去查询外协工序时间,若未查询到先默认3天,跳过该工序的排产
if(craft.getIsOutsource()){
String ppsIdStr = ppsIdMap.get(craft.getOcId());
OutsourceProcessEntity outsourceProcess = outsourceProcessService.getOne(Wrappers.<OutsourceProcessEntity>lambdaQuery().eq(OutsourceProcessEntity::getProcessId,ppsIdStr));
BigDecimal totalTime = new BigDecimal(0);
if(outsourceProcess != null){
//外协多工序需要把时间平分,方便处理
prevProcessEnd = prevProcessEnd.plusMinutes((long)((double)outsourceProcess.getDays()/ppsIdStr.split(",").length*24*60));
totalTime = totalTime.add(BigDecimal.valueOf((long)((double)outsourceProcess.getDays()/ppsIdStr.split(",").length*24*60)));
}else{
prevProcessEnd = prevProcessEnd.plusDays(3);
totalTime = totalTime.add(BigDecimal.valueOf(3*24*60));
}
Map<Integer, List<EquipAbilityEntity>> equipAbilityMap = equipAbilityList.stream().collect(Collectors.groupingBy(EquipAbilityEntity::getEquipOrder));
//匹配设备资源
//获取下一个整数点
LocalDateTime dateTime = getNextIntegerTime(prevProcessEnd);
for (Map.Entry<Integer, List<EquipAbilityEntity>> entry : equipAbilityMap.entrySet()) {
//根据时间点获取所有设备资源
List<EquipResourceEntity> equipResourceList = equipResourceService.list(Wrappers.<EquipResourceEntity>lambdaQuery().eq(EquipResourceEntity::getCraftId, craft.getCaId()).eq(EquipResourceEntity::getWorkCenterId, craft.getWorkCenterId()).ge(EquipResourceEntity::getStartTime, dateTime).eq(EquipResourceEntity::getIsUsed, 0).in(EquipResourceEntity::getEquipOrder, entry.getKey()));
if (CollectionUtils.isEmpty(equipResourceList)) {
WorkPlanEntity workPlan = new WorkPlanEntity();
workPlan.setWoId(order.getId());
workPlan.setCaId(craft.getCaId());
workPlan.setPpsId(craft.getPpsId());
workPlan.setWorkQty(order.getYpQty());
workPlan.setHourQuota(totalTime);
workPlan.setWorkCenterId(craft.getWorkCenterId());
workPlan.setOrders(craft.getProcessNo());
workPlan.setOem("0");
workPlan.setTestQty(0);
workPlan.setQualifiedQty(0);
workPlan.setUnqualifiedQty(0);
workPlan.setScrapQty(0);
workPlanList.add(workPlan);
}else{
if ("设备".equals(mainProducerMap.get(craft.getPpsId()))) {
//根据作业中心查询所有设备
List<EquipAbilityEntity> equipAbilityList = equipAbilityService.list(Wrappers.<EquipAbilityEntity>lambdaQuery().in(EquipAbilityEntity::getWorkCenterId, craft.getWorkCenterId()).eq(EquipAbilityEntity::getCraftId, craft.getCaId()));
if (CollectionUtils.isEmpty(equipAbilityList)) {
order.setErrorInfo("工序:"+processMap.get(craft.getPpsId()) +"设备未匹配到对应的设备能力");
order.setStatus(YieldOrderEnum.STATUS_PROCESS_ERROR.getCategory());
order.setErrorInfo("工序:" + craft.getPpsId() + "未匹配到对应的设备资源");
yieldOrderService.updateById(order);
isSchecuding = false;
break;
}
//设备资源按照时间段分组并按时间排序,然后再每个组内按照剩余产能倒序排序
Map<LocalDateTime, List<EquipResourceEntity>> equipResourceMap = equipResourceList.stream()
.collect(Collectors.groupingBy(
EquipResourceEntity::getStartTime, // 分组字段:startTime
// 用TreeMap接收,指定startTime降序(分组的排序)
TreeMap::new,
// 组内收集器:按restCapacity降序排序
Collectors.collectingAndThen(
Collectors.toList(),
list1 -> list1.stream()
.sorted(Comparator.comparing(
EquipResourceEntity::getRestCapacity,
// restCapacity 降序比较器(BigDecimal专用)
Comparator.reverseOrder()
))
.collect(Collectors.toList())
)
));
//计算生产所需产能,需将m2换算成dm2
BigDecimal sumCapacity = order.getYpArea().multiply(BigDecimal.valueOf(order.getYpQty()));
//需要判断设备额定生产能力是否满足订单总产能,如果不满足,则需要把总产能进行拆分
List<BigDecimal> capacityList = capacitySplit(equipResourceMap, sumCapacity);
for (BigDecimal capacity : capacityList) {
for (Map.Entry<LocalDateTime, List<EquipResourceEntity>> entry1 : equipResourceMap.entrySet()) {
Boolean isOccupied = false;
List<EquipResourceEntity> resourceList = entry1.getValue();
for (EquipResourceEntity equipResource : resourceList) {
//如果产能最大的设备都不满足,后面的设备就不需要判断了
if (equipResource.getRestCapacity().compareTo(capacity) < 0) {
break;
} else {
//生成车间订单
WorkPlanEntity workPlan = new WorkPlanEntity();
workPlan.setStartTime(equipResource.getStartTime());
if (entry.getKey() == 1) {
workPlan.setEndTime(equipResource.getStartTime().plusMinutes(equipResource.getStandardTime().longValue()));
Map<Integer, List<EquipAbilityEntity>> equipAbilityMap = equipAbilityList.stream().collect(Collectors.groupingBy(EquipAbilityEntity::getEquipOrder));
//匹配设备资源
//获取下一个整数点
LocalDateTime dateTime = getNextIntegerTime(prevProcessEnd);
for (Map.Entry<Integer, List<EquipAbilityEntity>> entry : equipAbilityMap.entrySet()) {
//根据时间点获取所有设备资源
List<EquipResourceEntity> equipResourceList = equipResourceService.list(Wrappers.<EquipResourceEntity>lambdaQuery().eq(EquipResourceEntity::getCraftId, craft.getCaId()).eq(EquipResourceEntity::getWorkCenterId, craft.getWorkCenterId()).ge(EquipResourceEntity::getStartTime, dateTime).eq(EquipResourceEntity::getIsUsed, 0).in(EquipResourceEntity::getEquipOrder, entry.getKey()));
if (CollectionUtils.isEmpty(equipResourceList)) {
order.setStatus(YieldOrderEnum.STATUS_PROCESS_ERROR.getCategory());
order.setErrorInfo("工序:" + processMap.get(craft.getPpsId()) + "未匹配到对应的设备资源");
yieldOrderService.updateById(order);
isSchecuding = false;
break;
}
//设备资源按照时间段分组并按时间排序,然后再每个组内按照剩余产能倒序排序
Map<LocalDateTime, List<EquipResourceEntity>> equipResourceMap = equipResourceList.stream()
.collect(Collectors.groupingBy(
EquipResourceEntity::getStartTime, // 分组字段:startTime
// 用TreeMap接收,指定startTime降序(分组的排序)
TreeMap::new,
// 组内收集器:按restCapacity降序排序
Collectors.collectingAndThen(
Collectors.toList(),
list1 -> list1.stream()
.sorted(Comparator.comparing(
EquipResourceEntity::getRestCapacity,
// restCapacity 降序比较器(BigDecimal专用)
Comparator.reverseOrder()
))
.collect(Collectors.toList())
)
));
//计算生产所需产能,需将m2换算成dm2
BigDecimal sumCapacity = order.getYpArea().multiply(BigDecimal.valueOf(order.getYpQty()));
//需要判断设备额定生产能力是否满足订单总产能,如果不满足,则需要把总产能进行拆分
List<BigDecimal> capacityList = capacitySplit(equipResourceMap, sumCapacity);
for (BigDecimal capacity : capacityList) {
for (Map.Entry<LocalDateTime, List<EquipResourceEntity>> entry1 : equipResourceMap.entrySet()) {
Boolean isOccupied = false;
List<EquipResourceEntity> resourceList = entry1.getValue();
for (EquipResourceEntity equipResource : resourceList) {
//如果产能最大的设备都不满足,后面的设备就不需要判断了
if (equipResource.getRestCapacity().compareTo(capacity) < 0) {
break;
} else {
workPlan.setEndTime(equipResource.getEndTime());
//生成车间订单
WorkPlanEntity workPlan = new WorkPlanEntity();
workPlan.setStartTime(equipResource.getStartTime());
if (entry.getKey() == 1) {
workPlan.setEndTime(equipResource.getStartTime().plusMinutes(equipResource.getStandardTime().longValue()));
} else {
workPlan.setEndTime(equipResource.getEndTime());
}
workPlan.setWorkQty(order.getYpQty());
workPlan.setCaId(craft.getCaId());
workPlan.setPpsId(craft.getPpsId());
workPlan.setMakeTeam(equipResource.getTeamId());
workPlan.setWorkCenterId(craft.getWorkCenterId());
workPlan.setOrders(craft.getProcessNo());
workPlan.setWoId(order.getId());
workPlan.setOem("0");
workPlan.setTestQty(0);
workPlan.setQualifiedQty(0);
workPlan.setUnqualifiedQty(0);
workPlan.setScrapQty(0);
workPlan.setHourQuota(BigDecimal.valueOf(ChronoUnit.MINUTES.between(workPlan.getStartTime(), workPlan.getEndTime())));
workPlan.setEquipCode(equipResource.getEquipCode());
workPlan.setEquipName(equipResource.getEquipName());
workPlan.setEquipResourceId(equipResource.getId());
workPlanList.add(workPlan);
//更新剩余产能
equipResource.setRestCapacity(equipResource.getRestCapacity().subtract(capacity));
equipResource.setIsUsed("1");
//如果剩余产能占总产能不足20%,则修改为已占用
// if(equipResource.getRestCapacity().divide(equipResource.getTotalCapacity(),2,RoundingMode.HALF_UP).compareTo(BigDecimal.valueOf(0.2)) < 0){
//
// }
//同一个设备可能有多个工艺能力,同一时间只能做一个工艺能力的零件,所以需要把当前设备所有工艺能力的剩余产能都更新调
LambdaUpdateWrapper<EquipResourceEntity> equipWrapper = new LambdaUpdateWrapper<>();
equipWrapper.eq(EquipResourceEntity::getEquipCode, equipResource.getEquipCode());
equipWrapper.eq(EquipResourceEntity::getDateTime, equipResource.getDateTime());
equipWrapper.eq(EquipResourceEntity::getPeriod, equipResource.getPeriod());
equipWrapper.eq(EquipResourceEntity::getStartTime, equipResource.getStartTime());
equipWrapper.eq(EquipResourceEntity::getEndTime, equipResource.getEndTime());
equipResourceService.update(equipResource, equipWrapper);
//该设备后续所有开始时间小于当前结束时间的时间段都变为不可用
LambdaUpdateWrapper<EquipResourceEntity> updateWrapper = new LambdaUpdateWrapper();
updateWrapper.lt(EquipResourceEntity::getStartTime, equipResource.getEndTime());
updateWrapper.gt(EquipResourceEntity::getStartTime, equipResource.getStartTime());
updateWrapper.eq(EquipResourceEntity::getEquipCode, equipResource.getEquipCode());
EquipResourceEntity equipResource1 = new EquipResourceEntity();
equipResource1.setIsUsed("1");
equipResourceService.update(equipResource1, updateWrapper);
//当前工序的结束时间作为下一工序的开始时间
prevProcessEnd = workPlan.getEndTime();
dateTime = workPlan.getEndTime();
isOccupied = true;
break;
}
workPlan.setWorkQty(order.getYpQty());
workPlan.setCaId(craft.getCaId());
workPlan.setPpsId(craft.getPpsId());
workPlan.setMakeTeam(equipResource.getTeamId());
workPlan.setWorkCenterId(craft.getWorkCenterId());
workPlan.setOrders(craft.getProcessNo());
workPlan.setWoId(order.getId());
workPlan.setOem("0");
workPlan.setTestQty(0);
workPlan.setQualifiedQty(0);
workPlan.setUnqualifiedQty(0);
workPlan.setScrapQty(0);
workPlan.setHourQuota(BigDecimal.valueOf(ChronoUnit.MINUTES.between(workPlan.getStartTime(), workPlan.getEndTime())));
workPlan.setEquipCode(equipResource.getEquipCode());
workPlan.setEquipName(equipResource.getEquipName());
workPlan.setEquipResourceId(equipResource.getId());
workPlanList.add(workPlan);
//更新剩余产能
equipResource.setRestCapacity(equipResource.getRestCapacity().subtract(capacity));
equipResource.setIsUsed("1");
//如果剩余产能占总产能不足20%,则修改为已占用
// if(equipResource.getRestCapacity().divide(equipResource.getTotalCapacity(),2,RoundingMode.HALF_UP).compareTo(BigDecimal.valueOf(0.2)) < 0){
//
// }
//同一个设备可能有多个工艺能力,同一时间只能做一个工艺能力的零件,所以需要把当前设备所有工艺能力的剩余产能都更新调
LambdaUpdateWrapper<EquipResourceEntity> equipWrapper = new LambdaUpdateWrapper<>();
equipWrapper.eq(EquipResourceEntity::getEquipCode, equipResource.getEquipCode());
equipWrapper.eq(EquipResourceEntity::getDateTime, equipResource.getDateTime());
equipWrapper.eq(EquipResourceEntity::getPeriod, equipResource.getPeriod());
equipWrapper.eq(EquipResourceEntity::getStartTime, equipResource.getStartTime());
equipWrapper.eq(EquipResourceEntity::getEndTime, equipResource.getEndTime());
equipResourceService.update(equipResource, equipWrapper);
//该设备后续所有开始时间小于当前结束时间的时间段都变为不可用
LambdaUpdateWrapper<EquipResourceEntity> updateWrapper = new LambdaUpdateWrapper();
updateWrapper.lt(EquipResourceEntity::getStartTime, equipResource.getEndTime());
updateWrapper.gt(EquipResourceEntity::getStartTime, equipResource.getStartTime());
updateWrapper.eq(EquipResourceEntity::getEquipCode, equipResource.getEquipCode());
EquipResourceEntity equipResource1 = new EquipResourceEntity();
equipResource1.setIsUsed("1");
equipResourceService.update(equipResource1, updateWrapper);
//当前工序的结束时间作为下一工序的开始时间
prevProcessEnd = workPlan.getEndTime();
dateTime = workPlan.getEndTime();
isOccupied = true;
}
if (isOccupied) {
break;
}
}
if (isOccupied) {
break;
}
}
}
}
if (!isSchecuding) {
break;
}
if (!isSchecuding) {
break;
}
} else if ("人".equals(mainProducerMap.get(craft.getPpsId()))) {
//匹配人资源
} else if ("人".equals(mainProducerMap.get(craft.getPpsId()))) {
//匹配人资源
/* String personAbility = craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId();
if (personAbilityMap.containsKey(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId())) {
@ -481,32 +529,32 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
isSchecuding = false;
break;
}*/
WorkPlanEntity workPlan = new WorkPlanEntity();
BigDecimal totalTime = new BigDecimal(0);
PersonAbilityEntity ability = personAbilityMap.get(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId());
//镀后检验和镀后接收先按半小时计算
if (ability != null) {
if ("镀后检验".equals(ability.getProcessName()) || "镀后接收".equals(ability.getProcessName())) {
totalTime = BigDecimal.valueOf(30);
workPlan.setStartTime(prevProcessEnd.plusMinutes(30));
workPlan.setEndTime(prevProcessEnd.plusMinutes(60));
if ("镀后接收".equals(ability.getProcessName())) {
workPlan.setMakeTeam(Long.valueOf(64));
}
if ("镀后检验".equals(ability.getProcessName())) {
workPlan.setMakeTeam(Long.valueOf(65));
}
prevProcessEnd = workPlan.getEndTime();
} else {
if ("0".equals(ability.getType())) {
totalTime = totalTime.add(BigDecimal.valueOf(order.getYpQty()).multiply(ability.getStandardTime()).add(ability.getPrepareTime()));
WorkPlanEntity workPlan = new WorkPlanEntity();
BigDecimal totalTime = new BigDecimal(0);
PersonAbilityEntity ability = personAbilityMap.get(craft.getWorkCenterId() + "-" + craft.getPpsId() + "-" + craft.getCaId());
//镀后检验和镀后接收先按半小时计算
if (ability != null) {
if ("镀后检验".equals(ability.getProcessName()) || "镀后接收".equals(ability.getProcessName())) {
totalTime = BigDecimal.valueOf(30);
workPlan.setStartTime(prevProcessEnd.plusMinutes(30));
workPlan.setEndTime(prevProcessEnd.plusMinutes(60));
if ("镀后接收".equals(ability.getProcessName())) {
workPlan.setMakeTeam(Long.valueOf(64));
}
if ("镀后检验".equals(ability.getProcessName())) {
workPlan.setMakeTeam(Long.valueOf(65));
}
prevProcessEnd = workPlan.getEndTime();
} else {
totalTime = totalTime.add(ability.getStandardTime()).add(ability.getPrepareTime());
if ("0".equals(ability.getType())) {
totalTime = totalTime.add(BigDecimal.valueOf(order.getYpQty()).multiply(ability.getStandardTime()).add(ability.getPrepareTime()));
} else {
totalTime = totalTime.add(ability.getStandardTime()).add(ability.getPrepareTime());
}
}
}
//通过加锁的方式保证每次查询到的人力资源都是最新的
//通过加锁的方式保证每次查询到的人力资源都是最新的
/*Long craftId = craft.getCaId();
Lock craftLock = getCraftLock(craftId);
craftLock.lock(); // 加本地锁,同一工艺ID串行执行
@ -573,34 +621,30 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
craftLock.unlock(); // 释放本地锁
}*/
} else {
//没有人员能力的先默认30分钟
totalTime = BigDecimal.valueOf(30);
workPlan.setStartTime(prevProcessEnd);
workPlan.setEndTime(prevProcessEnd.plusMinutes(30));
prevProcessEnd = workPlan.getEndTime();
}
}
workPlan.setWoId(order.getId());
workPlan.setCaId(craft.getCaId());
workPlan.setPpsId(craft.getPpsId());
workPlan.setWorkQty(order.getYpQty());
workPlan.setHourQuota(totalTime);
workPlan.setWorkCenterId(craft.getWorkCenterId());
workPlan.setOrders(craft.getProcessNo());
workPlan.setOem("0");
workPlan.setTestQty(0);
workPlan.setQualifiedQty(0);
workPlan.setUnqualifiedQty(0);
workPlan.setScrapQty(0);
workPlanList.add(workPlan);
workPlan.setWoId(order.getId());
workPlan.setCaId(craft.getCaId());
workPlan.setPpsId(craft.getPpsId());
workPlan.setWorkQty(order.getYpQty());
workPlan.setHourQuota(totalTime);
workPlan.setWorkCenterId(craft.getWorkCenterId());
workPlan.setOrders(craft.getProcessNo());
workPlan.setOem("0");
workPlan.setTestQty(0);
workPlan.setQualifiedQty(0);
workPlan.setUnqualifiedQty(0);
workPlan.setScrapQty(0);
workPlanList.add(workPlan);
} else {
//未匹配到设备和人力资源,将工序状态改为6,标识为未排产
craft.setStatus(YieldOrderEnum.STATUS_PROCESS_ERROR.getCategory());
yieldOrderCraftService.updateById(craft);
} else {
//未匹配到设备和人力资源,将工序状态改为6,标识为未排产
craft.setStatus(YieldOrderEnum.STATUS_PROCESS_ERROR.getCategory());
yieldOrderCraftService.updateById(craft);
}
}
if (!isSchecuding) {
break;
}
@ -695,7 +739,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
//根据设备的计划推算其他人力工序的开始结束时间
public void WorkPlanTimeCalculator(List<WorkPlanEntity> list) {
//根据作业中心分组
Map<Long, List<WorkPlanEntity>> workPlanMap = list.stream().collect(Collectors.groupingBy(WorkPlanEntity::getWorkCenterId));
Map<Long, List<WorkPlanEntity>> workPlanMap = list.stream().filter(item -> item.getWorkCenterId() != null).collect(Collectors.groupingBy(WorkPlanEntity::getWorkCenterId));
for (Map.Entry<Long, List<WorkPlanEntity>> entry : workPlanMap.entrySet()) {
List<WorkPlanEntity> workPlanList = entry.getValue();
int startIndex = -1;
@ -746,8 +790,19 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
current.setMakeTeam(prev.getMakeTeam());
}
}
for (int i = 0; i < list.size(); i++) {
//特殊处理,一个作业中心只有人力资源的情况
for(int i=0;i<list.size();i++){
if(list.get(i).getStartTime() == null && list.get(i).getEndTime() == null){
if(i!=0 && list.get(i-1).getEndTime() != null){
list.get(i).setStartTime(list.get(i-1).getEndTime());
list.get(i).setEndTime(list.get(i).getStartTime().plusMinutes(list.get(i).getHourQuota().longValue()));
continue;
}
if(i!=list.size()-1 && list.get(i+1).getStartTime() != null){
list.get(i).setEndTime(list.get(i+1).getStartTime());
list.get(i).setStartTime(list.get(i).getEndTime().minusMinutes(list.get(i).getHourQuota().longValue()));
}
}
}
}

@ -0,0 +1,46 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.scheduling.scheduling.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.scheduling.scheduling.entity.OutsourceProcessEntity;
import java.io.Serial;
/**
* 外协工序表 视图实体类
*
* @author BladeX
* @since 2025-12-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class OutsourceProcessVO extends OutsourceProcessEntity {
@Serial
private static final long serialVersionUID = 1L;
}

@ -0,0 +1,60 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.scheduling.scheduling.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.scheduling.scheduling.entity.OutsourceProcessEntity;
import org.springblade.scheduling.scheduling.vo.OutsourceProcessVO;
import java.util.Objects;
/**
* 外协工序表 包装类,返回视图层所需的字段
*
* @author BladeX
* @since 2025-12-24
*/
public class OutsourceProcessWrapper extends BaseEntityWrapper<OutsourceProcessEntity, OutsourceProcessVO> {
public static OutsourceProcessWrapper build() {
return new OutsourceProcessWrapper();
}
@Override
public OutsourceProcessVO entityVO(OutsourceProcessEntity outsourceProcess) {
OutsourceProcessVO OutsourceProcessVO = Objects.requireNonNull(BeanUtil.copyProperties(outsourceProcess, OutsourceProcessVO.class));
//User createUser = UserCache.getUser(OutsourceProcess.getCreateUser());
//User updateUser = UserCache.getUser(OutsourceProcess.getUpdateUser());
//OutsourceProcessVO.setCreateUserName(createUser.getName());
//OutsourceProcessVO.setUpdateUserName(updateUser.getName());
return OutsourceProcessVO;
}
}
Loading…
Cancel
Save