# ATS 批量排产报工接口文档 ## 版本信息 - **版本号**:v2.0.002 - **创建日期**:2026-02-27 - **更新说明**:通过开关参数灵活控制计划、工单、报工单的生成 - **测试地址**: - 前端:http://192.168.1.244:80 - 后端:http://192.168.1.244:8080 --- ## 快速开始 ### 核心概念 接口支持通过开关参数灵活控制三个业务模块的生成: | 模块 | 开关参数 | 默认值 | 说明 | |------|---------|--------|------| | 生产计划 | `plan.isGeneratePlan` | `1` | `0`=不生成,`1`=生成 | | 生产工单 | `workOrder.isGenerateWorkOrder` | `1` | `0`=不生成,`1`=生成 | | 报工单 | `reportWorkOrder.isGenerateReportWorkOrder` | `1` | `0`=不生成,`1`=生成 | **核心规则**: - **不传对象** = 使用默认值(生成) - **传了对象但不传开关** = 使用默认值(生成) - **传了开关=0** = 明确不生成 - **传了开关=1** = 明确生成 - **传了空字符串 ""** = 使用默认值 - **传了空数组 []** = 使用默认值 - **传了 null** = 使用默认值 **示例**: ```json // 不传plan对象 → 默认生成计划 {"orderNumbers": ["SO001"], "workOrder": {...}} // 传了plan但不传开关 → 默认生成计划 {"orderNumbers": ["SO001"], "plan": {"assignedUserIds": "101"}} // 传了开关=0 → 不生成计划 {"orderNumbers": ["SO001"], "plan": {"isGeneratePlan": 0}} // 传了空字符串 → 使用默认值 {"orderNumbers": ["SO001"], "plan": {"assignedUserIds": ""}} // 从工序路线获取 // 传了空数组 → 使用默认值 {"orderNumbers": ["SO001"], "reportWorkOrder": {"reporters": []}} // 从工序路线获取 ``` --- ## 常用场景 ### 场景1:全部生成(默认) ```json { "orderNumbers": ["SO202602270001"] } ``` **结果**:生成计划 → 生成工单 → 生成报工单 --- ### 场景2:只生成工单 ```json { "orderNumbers": ["SO202602270001"], "plan": { "isGeneratePlan": 0 }, "workOrder": { "routeId": 1005, "processStartTime": "2026-02-27 08:00:00" }, "reportWorkOrder": { "isGenerateReportWorkOrder": 0 } } ``` **结果**:只生成工单,工单状态保持"未完成" **说明**: - `plan.isGeneratePlan=0` 明确不生成计划 - `workOrder` 传了对象但没传开关,默认生成工单 - `reportWorkOrder.isGenerateReportWorkOrder=0` 明确不生成报工单 --- ### 场景3:只生成报工单(订单已有工单) ```json { "orderNumbers": ["SO202602270001"], "plan": { "isGeneratePlan": 0 }, "workOrder": { "isGenerateWorkOrder": 0 }, "reportWorkOrder": { "reporters": [ {"operatorId": 101, "reportTime": "2026-02-27 10:00:00"} ] } } ``` **结果**:为已有工单生成报工单,工单状态变为"已完成" **说明**: - `plan.isGeneratePlan=0` 明确不生成计划 - `workOrder.isGenerateWorkOrder=0` 明确不生成工单 - `reportWorkOrder` 传了对象但没传开关,默认生成报工单 --- ### 场景4:生成工单+报工单(不生成计划) ```json { "orderNumbers": ["SO202602270001"], "plan": { "isGeneratePlan": 0 } } ``` **结果**:生成工单 → 生成报工单(不生成计划) **说明**:通过设置 `isGeneratePlan=0` 明确不生成计划,workOrder和reportWorkOrder使用默认值1,会生成工单和报工单 --- ### 场景5:空值使用默认值 ```json { "orderNumbers": ["SO202602270001"], "plan": { "isGeneratePlan": 1, "assignedUserIds": "" }, "workOrder": { "isGenerateWorkOrder": 1, "processStartTime": "" }, "reportWorkOrder": { "isGenerateReportWorkOrder": 1, "reporters": [] } } ``` **结果**:全部生成,所有空值参数都使用系统默认值 **说明**: - `assignedUserIds: ""` → 从工序路线获取所有报工人(去重) - `processStartTime: ""` → 使用当前时间 - `reporters: []` → 从工序路线获取每个工序的报工人 --- ## 接口详情 ### 1. 批量自动完成接口 **POST** `http://192.168.1.244:8080/production/autoComplete/batchAutoComplete` #### 请求参数 ##### 必填参数 | 参数 | 类型 | 说明 | |------|------|------| | `orderNumbers` | Array\ | 销售订单编号列表 | ##### 可选参数 - plan(生产计划) | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `isGeneratePlan` | Integer | `1` | `0`=不生成,`1`=生成 | | `assignedUserIds` | String | 工序路线所有报工人(去重) | 负责人ID,逗号分隔,如 `"101,102"`;不传、传null或传空字符串 `""` 时,自动从工序路线中获取所有工序的报工人(去重)作为计划负责人 | ##### 可选参数 - workOrder(生产工单) | 参数 | 类型 | 默认值 | 说明 | |------|------|------|------| | `isGenerateWorkOrder` | Integer | `1` | `0`=不生成,`1`=生成 | | `routeId` | Long | 自动选择 | 工序路线ID;不传、传null时自动选择 | | `processStartTime` | String | 自动生成 | 首道工序开始时间,格式 `yyyy-MM-dd HH:mm:ss`;不传、传null或传空字符串 `""` 时使用当前时间 | **工序路线选择优先级**: 1. `workOrder.routeId`(最高优先级) 2. 订单明细配置的路线 3. 物料默认路线 4. 无路线则返回错误 ##### 可选参数 - reportWorkOrder(报工单) | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `isGenerateReportWorkOrder` | Integer | `1` | `0`=不生成,`1`=生成 | | `reporters` | Array | 工序路线的报工人 | 报工人列表;不传、传null或传空数组 `[]` 时,自动从工序路线中获取每个工序的报工人 | **reporters 子字段**: | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `operatorId` | Long | 是 | 报工人用户ID | | `reportTime` | String | 是 | 报工时间,格式 `yyyy-MM-dd HH:mm:ss` | **说明**: - 系统通过订单编号反查关联工单 - 只对未完成的工单创建报工记录 - **不传reporters、传null或传空数组 `[]` 时**:系统自动从工序路线中获取每个工序配置的报工人,按工序顺序为每个工单生成报工记录(每个工序一个报工人) - **传1条reporter时**:该报工人对所有未完成工单均生成报工记录 - **传多条reporters时**:按工序顺序与未完成工单一一映射 --- #### 完整请求示例 ```json { "orderNumbers": ["SO202602270001", "SO202602270002"], "plan": { "isGeneratePlan": 1, "assignedUserIds": "101,102" }, "workOrder": { "isGenerateWorkOrder": 1, "routeId": 1005, "processStartTime": "2026-02-27 08:00:00" }, "reportWorkOrder": { "isGenerateReportWorkOrder": 1, "reporters": [ {"operatorId": 101, "reportTime": "2026-02-27 10:00:00"}, {"operatorId": 102, "reportTime": "2026-02-27 14:00:00"} ] } } ``` --- #### 响应结果(立即返回) ```json { "code": 200, "msg": "任务已提交,正在后台处理", "data": { "taskId": "TASK_20260227_001", "totalCount": 2, "estimatedSeconds": 10, "status": "PENDING", "message": "任务已创建,预计需要10秒完成" } } ``` --- ### 2. 任务状态查询接口 **GET** `http://192.168.1.244:8080/production/autoComplete/taskStatus/{taskId}` #### 请求示例 ``` GET /production/autoComplete/taskStatus/TASK_20260227_001 ``` #### 响应示例(处理中) ```json { "code": 200, "msg": "查询成功", "data": { "taskId": "TASK_20260227_001", "status": "PROCESSING", "totalCount": 50, "processedCount": 25, "successCount": 23, "failedCount": 2, "percentage": 50, "message": "正在处理中,已完成50%" } } ``` #### 响应示例(已完成) ```json { "code": 200, "msg": "查询成功", "data": { "taskId": "TASK_20260227_001", "status": "COMPLETED", "totalCount": 50, "processedCount": 50, "successCount": 48, "failedCount": 2, "percentage": 100, "message": "任务已完成", "result": { "successOrders": ["SO001", "SO002"], "failedOrders": ["SO025", "SO038"], "failureReasons": { "SO025": "订单不存在", "SO038": "物料未配置工序路线" } } } } ``` --- ## 辅助接口 ### 3. 库存式生产自动创建订单 **POST** `http://192.168.1.244:8080/production/plan/autoCreateOrder` 用于库存式生产(MTS),自动生成以"生产备货"为客户的销售订单。 #### 请求参数 | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `materialId` | Long | 是 | 产品ID | | `materialName` | String | 建议 | 产品名称 | | `totalQuantity` | BigDecimal | 是 | 生产数量(必须 > 0) | | `endTime` | String | 是 | 交货日期,格式 `yyyy-MM-dd HH:mm:ss` | #### 请求示例 ```json { "materialId": 101, "materialName": "产品A", "totalQuantity": 100, "endTime": "2026-03-31 18:00:00" } ``` #### 响应示例 ```json { "code": 200, "msg": "订单创建成功", "data": { "orderId": 999, "orderNumber": "PL20260227001" } } ``` --- ### 4. 按用户查询报工单 **GET** `http://192.168.1.244:8080/production/report/list` #### 查询参数 | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `reportUserName` | String | 是 | 报工人姓名(模糊匹配) | | `reportTimeQuery[0]` | String | 否 | 报工时间起,格式 `yyyy-MM-dd` | | `reportTimeQuery[1]` | String | 否 | 报工时间止,格式 `yyyy-MM-dd` | | `workOrderId` | Long | 否 | 工单ID | | `pageNum` | Integer | 否 | 页码(默认1) | | `pageSize` | Integer | 否 | 每页条数(默认10) | #### 请求示例 ``` GET /production/report/list?reportUserName=张三&reportTimeQuery[0]=2026-02-01&reportTimeQuery[1]=2026-02-27 ``` #### 响应示例 ```json { "code": 200, "msg": "查询成功", "rows": [ { "id": 501, "reportUserId": 1, "reportUserName": "张三", "reportTime": "2026-02-27 10:00:00", "reportQuantity": 50, "qualifiedQuantity": 50, "workOrderId": 301, "status": "A" } ], "total": 1 } ``` --- ## 业务规则 ### 开关控制规则 **核心原则**:所有开关默认值都是 `1`(生成),只有明确设置为 `0` 才不生成 1. **不传任何对象**:使用默认值,全部生成(计划+工单+报工单) ```json {"orderNumbers": ["SO001"]} ``` 2. **传了对象但不传开关**:使用默认值,该业务生成 ```json {"orderNumbers": ["SO001"], "plan": {"assignedUserIds": "101"}} // plan没有传isGeneratePlan,默认为1,生成计划 ``` 3. **传了开关=0**:明确不生成 ```json {"orderNumbers": ["SO001"], "plan": {"isGeneratePlan": 0}} // 明确设置为0,不生成计划 ``` 4. **传了开关=1**:明确生成(与默认行为相同) ```json {"orderNumbers": ["SO001"], "plan": {"isGeneratePlan": 1}} // 明确设置为1,生成计划 ``` ### 依赖关系 | 场景 | 说明 | |------|------| | 报工单依赖工单 | 如果 `isGenerateWorkOrder=0` 且 `isGenerateReportWorkOrder=1`,则只为已有工单生成报工单;如果订单无工单,跳过该订单 | | 计划独立 | 计划的生成不依赖工单和报工单 | | 工单独立 | 工单可以单独生成,不依赖计划和报工单 | ### 异步处理流程 1. **提交任务**(<1秒):验证参数 → 创建任务记录 → 立即返回任务ID 2. **异步执行**(后台):循环处理订单 → 每5个订单更新一次进度 3. **查询状态**(<100ms):根据任务ID查询实时进度 ### 性能说明 | 订单数 | 预计耗时 | 数据库更新次数 | |--------|---------|--------------| | 5个 | ~5秒 | 4次 | | 10个 | ~10秒 | 5次 | | 50个 | ~50秒 | 13次 | | 100个 | ~100秒 | 23次 | **并发限制**: - 线程池大小:10个线程 - 最大并发任务数:10个 - 单个任务最大执行时间:5分钟 - 建议:单次批量不超过100个订单 --- ## 场景速查表 | 场景 | 参数配置示例 | 结果 | |------|------------|------| | 全部生成 | `{}` 不传任何对象 | 计划+工单+报工单 | | 只生成计划 | `{plan: {}, workOrder: {isGenerateWorkOrder: 0}, report: {isGenerateReportWorkOrder: 0}}` | 只生成计划 | | 只生成工单 | `{plan: {isGeneratePlan: 0}, workOrder: {}, report: {isGenerateReportWorkOrder: 0}}` | 只生成工单 | | 只生成报工单 | `{plan: {isGeneratePlan: 0}, workOrder: {isGenerateWorkOrder: 0}, report: {}}` | 只为已有工单生成报工单 | | 工单+报工单 | `{plan: {isGeneratePlan: 0}}` | 生成工单和报工单 | | 计划+工单 | `{report: {isGenerateReportWorkOrder: 0}}` | 生成计划和工单 | **说明**: - 开关默认值都是1(生成) - 不传对象 = 使用默认值1 = 生成 - 传了对象但不传开关 = 使用默认值1 = 生成 - 只有明确设置开关=0才不生成 --- ## 版本历史 | 版本号 | 日期 | 变更说明 | |--------|------|---------| | v2.0.000 | 2026-02-24 | 初始版本,支持基础批量排产 | | v2.0.002 | 2026-02-27 | 新增开关参数,支持灵活控制计划、工单、报工单的生成 | --- ## 注意事项 1. **认证方式**:接口已配置匿名访问,无需认证 2. **异步执行**:接口立即返回任务ID,实际处理在后台进行 3. **进度查询**:通过任务状态查询接口轮询获取进度 4. **错误处理**:单个订单失败不影响其他订单,最终返回详细的成功/失败列表 5. **工序路线**:优先使用 `workOrder.routeId`,其次使用订单/物料配置的路线 6. **默认值逻辑**: - **计划负责人**:不传 `plan.assignedUserIds`、传null或传空字符串 `""` 时,系统自动从工序路线中获取所有工序的报工人(去重)作为计划负责人 - **工序开始时间**:不传 `workOrder.processStartTime`、传null或传空字符串 `""` 时,系统使用当前时间 - **报工单报工人**:不传 `reportWorkOrder.reporters`、传null或传空数组 `[]` 时,系统自动从工序路线中获取每个工序配置的报工人,按工序顺序生成报工记录 7. **空值处理规则**: - 字符串类型:`null`、`""`(空字符串)、不传 → 都使用默认值 - 数组类型:`null`、`[]`(空数组)、不传 → 都使用默认值 - 数值类型:`null`、不传 → 使用默认值