顾乔芝士网

持续更新的前后端开发技术栈

DeepSeek帮我写代码:实现流程制造工序级自动排产(APS)

近期一个客户提出一个想法,他们想要将某一个车间,由原本的手动人工排产,升级为系统自动排产。一听这个话题,这不就是APS么,客户又提出能不能根据现有的条件,先简单的给一个demo,看看算法实现的效果。

原本是想自己亲自动手,后来一想,是不是DeepSeek可以帮我搞定呢,先上结果(部分是作者君自行调整后的内容)。

代码切片

// 产品 工序
@Data
public class Process {
    private final String name;
    public Process(String name) { this.name = name; }
}
@Data
public class Product {
    private String name;
    public Product(String name) {
        this.name = name;
    }
}
// 工艺路线
public class ProcessRoute {
    private String product;
    private LinkedList<Process> processes = new LinkedList<>();

    public ProcessRoute(Product product, LinkedList<Process> processes) {
        this.product = product.getName();
        this.processes = processes;
    }

    public ProcessRoute(String product, LinkedList<Process> processes) {
        this.product = product;
        this.processes = processes;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public LinkedList<Process> getProcesses() {
        return processes;
    }

    public void setProcesses(LinkedList<Process> processes) {
        this.processes = processes;
    }

    public Process findPre(String process){
        Process pre = null;
        Process now = null;
        LinkedList<Process> processes = new LinkedList<>(this.processes);
        while (true) {
            now = processes.poll();
            if (null == now) {
                return null;
            }
            if (now.getName().equals(process)) {
                return pre;
            }else {
                pre = now;
            }
        }
    }

    public Process findNxt(String process) {
        Process nxt = null;
        Process now = null;
        LinkedList<Process> processes = new LinkedList<>(this.processes);
        while (true) {
            now = processes.poll();
            if (null == now) {
                return null;
            }
            if (now.getName().equals(process)) {
                return processes.poll();
            }
        }
    }
}
// 工序产能
public class ProcessCapacity {
    private String process;
    private Map<String, Integer> productCapacity;

    public ProcessCapacity(Process process) {
        this.process = process.getName();
        this.productCapacity = new HashMap<>();
    }

    public ProcessCapacity(String process) {
        this.process = process;
        this.productCapacity = new HashMap<>();
    }

    public String getProcess() {
        return process;
    }

    public void setProcess(String process) {
        this.process = process;
    }

    public Map<String, Integer> getProductCapacity() {
        return productCapacity;
    }

    public void setProductCapacity(Map<String, Integer> productCapacity) {
        this.productCapacity = productCapacity;
    }

    public ProcessCapacity addProductCapacity(Product product, Integer capacity){
        this.productCapacity.put(product.getName(), capacity);
        return this;
    }
}
// 主计划
public class MainOrder {
    private static final DateTimeFormatter DATE_FORMATTER =
            DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final Random random = ThreadLocalRandom.current();

    private static int i = 1;

    private String orderNo;
    private String product;
    private int count;
    private int finishCount;

    private LocalDate lastDay;

    public MainOrder(LocalDate date, String product, int count) {
        this.orderNo = generateOrderId(date);
        this.product = product;
        this.count = count;
        this.lastDay = date.plusDays(random.nextInt(50) + 15);
    }

    // 生成订单ID(符合DDMMYYYY-XXXX格式)
    private String generateOrderId(LocalDate date) {
        i = i + 1;
        return DATE_FORMATTER.format(date) +
                "-" + String.format("%04d", i);
    }


    private ProcessRoute processRoute;

    public String getOrderNo() {
        return orderNo;
    }

    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public ProcessRoute getProcessRoute() {
        return processRoute;
    }

    public void setProcessRoute(ProcessRoute processRoute) {
        this.processRoute = processRoute;
    }

    public int getFinishCount() {
        return finishCount;
    }

    public void setFinishCount(int finishCount) {
        this.finishCount = finishCount;
    }

    public LocalDate getLastDay() {
        return lastDay;
    }

    public void setLastDay(LocalDate lastDay) {
        this.lastDay = lastDay;
    }

    @Override
    public String toString() {
        return "MainOrder{" +
                "orderNo='" + orderNo + '\'' +
                ", product='" + product + '\'' +
                ", count=" + count +
                ", finishCount=" + finishCount +
                ", lastDay=" + lastDay +
                ", processRoute=" + processRoute +
                '}';
    }

    public void addFinish(int count) {
        this.finishCount = this.finishCount + count;
    }
}
// 工序生产任务
@Data
@Accessors(chain = true)
public class ProcessTask {
    private static int i = 0;

    private String mainOrderNo;
    private String taskNo;

    private String product;
    private String process;
    private int taskCount;
    private int finishCount = 0;

    private boolean finish;

    private LocalDate lastDate;

    public boolean isFinish() {
        return finishCount >= taskCount;
    }

    public ProcessTask initByMainOrder(MainOrder mainOrder) {
        return this.setMainOrderNo(mainOrder.getOrderNo())
                .setProduct(mainOrder.getProduct())
                .setProcess(processRouteMap.get(mainOrder.getProduct()).getProcesses().peek().getName())
                .setLastDate(mainOrder.getLastDay())
                .setTaskCount(mainOrder.getCount())
                .initTaskNo();
    }

    public ProcessTask initTaskNo() {
        i++;
        this.taskNo = this.mainOrderNo + "-" + i;
        return this;
    }

    public int getRemainCount(){
        return taskCount - finishCount;
    }
    public boolean needPlan(){
        return taskCount>finishCount;
    }
    public void addFinish(int count){
        this.finishCount = this.finishCount + count;
    }
}
// 工序日计划
@Data
@Accessors(chain = true)
public class ProcessPlan {

    private static final DateTimeFormatter DATE_FORMATTER =
            DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final Random random = ThreadLocalRandom.current();

    private static int i = 1;

    private String mainOrderNo;
    private String taskNo;
    private String planNo;

    private String product;
    private String process;
    private int planCount;

    private LocalDate planDate;
    private LocalDate lastDate;

    // 生成订单ID(符合DDMMYYYY-XXXX格式)
    private String generateOrderId(LocalDate date) {
        i = i + 1;
        return DATE_FORMATTER.format(date) +
                "-" + String.format("%04d", i);
    }


    public ProcessPlan initByTask(ProcessTask task, LocalDate date, int planCount) {
        return this.setProcess(task.getProcess())
                .setTaskNo(task.getTaskNo())
                .setMainOrderNo(task.getMainOrderNo())
                .setProduct(task.getProduct())
                .setLastDate(task.getLastDate())
                .setPlanDate(date)
                .setPlanCount(planCount)
                .setPlanNo(generateOrderId(date));
    }
}


模拟执行


// demo模拟内容
/**
 * Demo可以进一步扩展的内容
 *  1、目前是工序产能,没有机台的产能,可以进一步拆解为机器产能,再合并到工序产能
 *  2、目前按照计划100%完成,没有考虑计划可能未完成的情况,这部分可以与实际报工数据结合
 *  3、每日计划没有按照产品进行计划合并,导致存在换线的情况(实操中可以不换线),这里可以优化
 */
public class Main {
    private static final DateTimeFormatter DATE_FORMATTER =
            DateTimeFormatter.ofPattern("yyyy年MM月dd日");
    public static Map<String, Product> productMap = new HashMap<>();
    public static List<Product> productList = new ArrayList<>();
    public static Map<String, Process> processMap = new HashMap<>();
    public static Map<String, ProcessRoute> processRouteMap = new HashMap<>();
    public static Map<String, ProcessCapacity> processCapacityMap = new HashMap<>();

    public static List<MainOrder> mainOrderList = new ArrayList<>();
    public static List<ProcessTask> processTaskList = new ArrayList<>();
    public static List<ProcessPlan> processPlanList = new ArrayList<>();

    public static Map<LocalDate, List<ProcessPlan>> daliyProcessPlanMap = new HashMap<>();
    public static Map<String, List<ProcessPlan>> processPlanMap = new HashMap<>();
    public static Map<String, List<ProcessTask>> processTaskMap = new HashMap<>();

    public static Random random = ThreadLocalRandom.current();

    static {
        // 准备 产品数据、工序、产品工艺、工序产能
        // 产品
        Product product1 = new Product("电线1");
        Product product2 = new Product("电线2");
        Product product3 = new Product("电线3");

        productMap.put(product1.getName(), product1);
        productMap.put(product2.getName(), product2);
        productMap.put(product3.getName(), product3);

        productList.addAll(productMap.values());

        // 工序
        Process process1 = new Process("1束丝");
        Process process2 = new Process("2绝缘挤出");
        Process process3 = new Process("3成缆");
        Process process4 = new Process("4护套挤出");
        Process process5 = new Process("5产检");

        processMap.put(process1.getName(), process1);
        processMap.put(process2.getName(), process2);
        processMap.put(process3.getName(), process3);
        processMap.put(process4.getName(), process4);
        processMap.put(process5.getName(), process5);

        // 产品工艺
        LinkedList<Process> processes = new LinkedList<>();
        processes.offer(process1);
        processes.offer(process2);
        processes.offer(process3);
        processes.offer(process4);
        processes.offer(process5);

        ProcessRoute processRoute1 = new ProcessRoute(product1, processes);
        ProcessRoute processRoute2 = new ProcessRoute(product2, processes);
        ProcessRoute processRoute3 = new ProcessRoute(product3, processes);

        processRouteMap.put(processRoute1.getProduct(), processRoute1);
        processRouteMap.put(processRoute2.getProduct(), processRoute2);
        processRouteMap.put(processRoute3.getProduct(), processRoute3);

        // 工序产能
        ProcessCapacity processCapacity1 = new ProcessCapacity(process1)
                .addProductCapacity(product1, 12000)
                .addProductCapacity(product2, 9000)
                .addProductCapacity(product3, 10000);

        ProcessCapacity processCapacity2 = new ProcessCapacity(process2)
                .addProductCapacity(product1, 9000)
                .addProductCapacity(product2, 10000)
                .addProductCapacity(product3, 12000);

        ProcessCapacity processCapacity3 = new ProcessCapacity(process3)
                .addProductCapacity(product1, 10000)
                .addProductCapacity(product2, 12000)
                .addProductCapacity(product3, 9000);

        ProcessCapacity processCapacity4 = new ProcessCapacity(process4)
                .addProductCapacity(product1, 12000)
                .addProductCapacity(product2, 10000)
                .addProductCapacity(product3, 9000);

        ProcessCapacity processCapacity5 = new ProcessCapacity(process5)
                .addProductCapacity(product1, 10000)
                .addProductCapacity(product2, 10000)
                .addProductCapacity(product3, 10000);

        processCapacityMap.put(processCapacity1.getProcess(), processCapacity1);
        processCapacityMap.put(processCapacity2.getProcess(), processCapacity2);
        processCapacityMap.put(processCapacity3.getProcess(), processCapacity3);
        processCapacityMap.put(processCapacity4.getProcess(), processCapacity4);
        processCapacityMap.put(processCapacity5.getProcess(), processCapacity5);

    }

    public static void generateMainOrder(LocalDate date){
        // 随机追加几个
        int size = random.nextInt(3) + 1;
        if (mainOrderList.isEmpty()){
            size = random.nextInt(5) + 7;
        }

        System.out.println("每日新增主订单数据: \t , 日期: " + DATE_FORMATTER.format(date));
        System.out.println("主计划单号 \t 产品 \t 计划生产数量 \t 完成数量 \t 交期 \t ");
        for (int i = 0; i < size; i++) {
            int count = random.nextInt(3000) + 3000;
            int sub = random.nextInt(productList.size());
            String product = productList.get(sub).getName();

            MainOrder mainOrder = new MainOrder(date, product, count);

            System.out.printf("%s \t %s \t %d \t %d \t %s \t ",
                    mainOrder.getOrderNo(), mainOrder.getProduct(), mainOrder.getCount(),
                    mainOrder.getFinishCount(), DATE_FORMATTER.format(mainOrder.getLastDay()));
            System.out.println();
            mainOrderList.add(mainOrder);

            // 将MainOrder 分解到 第一个工序任务池
            ProcessTask processTask = new ProcessTask().initByMainOrder(mainOrder);
            processTaskList.add(processTask);
            List<ProcessTask> orDefault = processTaskMap.getOrDefault(processTask.getProcess(), new ArrayList<>());
            orDefault.add(processTask);
            processTaskMap.put(processTask.getProcess(), orDefault);

        }
        System.out.println();
    }

    public static void generateProcessPlan(LocalDate date){
        processMap.forEach((key, process) -> {
            String name = process.getName();
            // 从对应的工序任务池中获取任务
            List<ProcessTask> processTaskPool = processTaskMap.getOrDefault(name, new ArrayList<>());
            List<ProcessTask> collect = processTaskPool.stream().filter(ProcessTask::needPlan).sorted(Comparator.comparing(ProcessTask::getLastDate)).collect(Collectors.toList());

            Map<String, Integer> productCapacity = processCapacityMap.get(name).getProductCapacity();

            BigDecimal nowProcessCapacity = BigDecimal.ZERO;
            BigDecimal fullProcessCapacity = BigDecimal.ONE;
            for (ProcessTask processTask : collect) {
                String product = processTask.getProduct();
                BigDecimal oneOfCapacity = BigDecimal.ONE.divide(new BigDecimal(productCapacity.get(product)), 18, RoundingMode.DOWN);
                BigDecimal remainCapacity = fullProcessCapacity.subtract(nowProcessCapacity);
                BigDecimal nowCount = remainCapacity.multiply(new BigDecimal(productCapacity.get(product))).setScale(0, RoundingMode.DOWN);
                if (nowCount.intValue() == 0) {
                    break;
                }
                if (processTask.getRemainCount() > nowCount.intValue()) {
                    genTaskToPlan(processTask, date, nowCount.intValue(), name);
                    break;
                } else {
                    genTaskToPlan(processTask, date, processTask.getRemainCount(), name);
                    nowProcessCapacity = nowProcessCapacity.add(oneOfCapacity.multiply(new BigDecimal(processTask.getRemainCount())));
                }
            }
        });
    }

    private static void genTaskToPlan(ProcessTask processTask, LocalDate date, int planCount, String name) {
        ProcessPlan plan = new ProcessPlan().initByTask(processTask, date, planCount);
        processPlanList.add(plan);
        List<ProcessPlan> orDefault = processPlanMap.getOrDefault(name, new ArrayList<>());
        orDefault.add(plan);
        processPlanMap.put(name, orDefault);

        List<ProcessPlan> orDefault1 = daliyProcessPlanMap.getOrDefault(date, new ArrayList<>());
        orDefault1.add(plan);
        daliyProcessPlanMap.put(date, orDefault1);
    }

    public static void main(String[] args) {
        LocalDate date = LocalDate.now();
        LocalDate lastDate = date.plusDays(15);
      
      // 模拟每日重复
        while (date.isBefore(lastDate)){
            // 准备 主订单  随机生成
            generateMainOrder(date);

            // 依次按照产能对工序进行计划排产
            generateProcessPlan(date);

            // 输出每日计划内容
            List<ProcessPlan> processPlans = daliyProcessPlanMap.getOrDefault(date, new ArrayList<>());
            processPlans.sort((o1, o2) -> {
                int compareTo = o1.getProcess().compareTo(o2.getProcess());
                if (compareTo == 0) {
                    return o1.getProduct().compareTo(o2.getProduct());
                }
                return compareTo;
            });
            System.out.println("每日工序生产计划: \t , 日期: " + DATE_FORMATTER.format(date));
            System.out.println("工序 \t 计划单号 \t 产品 \t 计划生产数量 \t 主计划单号 \t 工序任务号 \t");
            processPlans.forEach(item ->{
                System.out.printf("%s \t %s \t %s \t %d \t %s \t %s \t",
                        item.getProcess(), item.getPlanNo(), item.getProduct(),
                        item.getPlanCount(), item.getMainOrderNo(), item.getTaskNo()
                );
                System.out.println();
            });
            System.out.println();

            // 按照完全完成的状态,推进到下一个工序
            processPlans.forEach(item ->{
                ProcessTask processTask = processTaskList.stream().filter(p -> p.getTaskNo().equals(item.getTaskNo())).findFirst().get();
                processTask.addFinish(item.getPlanCount());

                ProcessRoute processRoute = processRouteMap.get(item.getProduct());
                Process nxtProcess = processRoute.findNxt(item.getProcess());
                if (null == nxtProcess) {
                    // 追加到MainOrder完成
                    MainOrder mainOrder = mainOrderList.stream().filter(p -> p.getOrderNo().equals(item.getMainOrderNo())).findFirst().get();
                    mainOrder.addFinish(item.getPlanCount());
                } else {
                    ProcessTask task = new ProcessTask()
                            .setTaskCount(item.getPlanCount())
                            .setMainOrderNo(item.getMainOrderNo())
                            .setProduct(item.getProduct())
                            .setLastDate(item.getLastDate())
                            .setProcess(nxtProcess.getName())
                            .initTaskNo();
                    processTaskList.add(task);
                    List<ProcessTask> orDefault = processTaskMap.getOrDefault(nxtProcess.getName(), new ArrayList<>());
                    orDefault.add(task);
                    processTaskMap.put(nxtProcess.getName(), orDefault);
                }
            });
            // 输出每日结果 - 工序任务池情况
            processTaskList.sort((o1, o2) -> {
                int compareTo = o1.getProcess().compareTo(o2.getProcess());
                if (compareTo == 0) {
                    return o1.getLastDate().compareTo(o2.getLastDate());
                }
                return compareTo;
            });
            System.out.println("每日工序任务池情况: \t , 日期: " + DATE_FORMATTER.format(date));
            System.out.println("工序 \t 任务单号 \t 主计划单号 \t 产品 \t 计划生产数量 \t 完成数量 \t 交期 \t ");
            processTaskList.forEach(item ->{
                System.out.printf("%s \t %s \t %s \t %s \t %d \t %d \t %s \t ",
                        item.getProcess(),
                        item.getTaskNo(),item.getMainOrderNo(), item.getProduct(), item.getTaskCount(),
                        item.getFinishCount(), DATE_FORMATTER.format(item.getLastDate()));
                System.out.println();
            });
            System.out.println();

            // 输出每日结果 - 主计划
            mainOrderList.sort(Comparator.comparing(MainOrder::getLastDay));
            System.out.println("每日生产主计划完成情况: \t , 日期: " + DATE_FORMATTER.format(date));
            System.out.println("主计划单号 \t 产品 \t 计划生产数量 \t 完成数量 \t 交期 \t ");
            mainOrderList.forEach(item ->{
                System.out.printf("%s \t %s \t %d \t %d \t %s \t ",
                        item.getOrderNo(), item.getProduct(), item.getCount(),
                        item.getFinishCount(), DATE_FORMATTER.format(item.getLastDay()));
                System.out.println();
            });
            System.out.println();

            date = date.plusDays(1);

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

执行结果

// 程序运行结果:
每日新增主订单数据: 	 , 日期: 2025年03月05日
主计划单号 	 产品 	 计划生产数量 	 完成数量 	 交期 	 
20250305-0002 	 电线3 	 5154 	 0 	 2025年03月22日 	 
20250305-0003 	 电线3 	 3967 	 0 	 2025年04月22日 	 
20250305-0004 	 电线1 	 4837 	 0 	 2025年03月20日 	 
20250305-0005 	 电线2 	 4842 	 0 	 2025年04月07日 	 
20250305-0006 	 电线2 	 4548 	 0 	 2025年04月06日 	 
20250305-0007 	 电线3 	 5579 	 0 	 2025年03月30日 	 
20250305-0008 	 电线1 	 5618 	 0 	 2025年03月24日 	 

每日工序生产计划: 	 , 日期: 2025年03月05日
工序 	 计划单号 	 产品 	 计划生产数量 	 主计划单号 	 工序任务号 	
1束丝 	 20250305-0002 	 电线1 	 4837 	 20250305-0004 	 20250305-0004-3 	
1束丝 	 20250305-0004 	 电线1 	 978 	 20250305-0008 	 20250305-0008-7 	
1束丝 	 20250305-0003 	 电线3 	 5154 	 20250305-0002 	 20250305-0002-1 	

每日工序任务池情况: 	 , 日期: 2025年03月05日
工序 	 任务单号 	 主计划单号 	 产品 	 计划生产数量 	 完成数量 	 交期 	 
1束丝 	 20250305-0004-3 	 20250305-0004 	 电线1 	 4837 	 4837 	 2025年03月20日 	 
1束丝 	 20250305-0002-1 	 20250305-0002 	 电线3 	 5154 	 5154 	 2025年03月22日 	 
1束丝 	 20250305-0008-7 	 20250305-0008 	 电线1 	 5618 	 978 	 2025年03月24日 	 
1束丝 	 20250305-0007-6 	 20250305-0007 	 电线3 	 5579 	 0 	 2025年03月30日 	 
1束丝 	 20250305-0006-5 	 20250305-0006 	 电线2 	 4548 	 0 	 2025年04月06日 	 
1束丝 	 20250305-0005-4 	 20250305-0005 	 电线2 	 4842 	 0 	 2025年04月07日 	 
1束丝 	 20250305-0003-2 	 20250305-0003 	 电线3 	 3967 	 0 	 2025年04月22日 	 
2绝缘挤出 	 20250305-0004-8 	 20250305-0004 	 电线1 	 4837 	 0 	 2025年03月20日 	 
2绝缘挤出 	 20250305-0002-10 	 20250305-0002 	 电线3 	 5154 	 0 	 2025年03月22日 	 
2绝缘挤出 	 20250305-0008-9 	 20250305-0008 	 电线1 	 978 	 0 	 2025年03月24日 	 

每日生产主计划完成情况: 	 , 日期: 2025年03月05日
主计划单号 	 产品 	 计划生产数量 	 完成数量 	 交期 	 
20250305-0004 	 电线1 	 4837 	 0 	 2025年03月20日 	 
20250305-0002 	 电线3 	 5154 	 0 	 2025年03月22日 	 
20250305-0008 	 电线1 	 5618 	 0 	 2025年03月24日 	 
20250305-0007 	 电线3 	 5579 	 0 	 2025年03月30日 	 
20250305-0006 	 电线2 	 4548 	 0 	 2025年04月06日 	 
20250305-0005 	 电线2 	 4842 	 0 	 2025年04月07日 	 
20250305-0003 	 电线3 	 3967 	 0 	 2025年04月22日 	 


与DeepSeek交流过程

具体与DeepSeek交流过程部分截图附在下方:











这一次,虽然没有给出完整的样例,但是DeepSeek给出了相对完整的思路,只是在深入到很细节的业务场景时,目前以AI的能力还是存在局限。虽都在说,AI来了,程序员的也要大结局了,但是根据实际情况来看,AI来了,可能应该是程序员的春天来了才对!

如果你也喜欢这篇文章,给我们点个赞吧~


#发优质内容享分成# #deepseek# #程序员# #ai# #APS排产系统#

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言