智慧实物管理系统相关功能优化

This commit is contained in:
2025-12-05 16:04:35 +08:00
parent f338e53883
commit 2c21c1560e
25 changed files with 2708 additions and 46 deletions

View File

@@ -0,0 +1,47 @@
# WCS系统与WMS/AGV对接流程图
## 流程说明
```mermaid
graph TD
A[WMS创建任务] --> B{判断任务类型}
B -->|入库/上架| C[WMS调用WCS /API/Ruku接口]
B -->|出库/下架| D[WMS调用WCS /API/Chuku接口]
C --> E[WCS接收任务请求]
D --> E
E --> F[WCS验证任务参数]
F --> G{参数验证结果}
G -->|验证失败| H[WCS返回错误信息给WMS]
G -->|验证成功| I[WCS创建内部任务]
I --> J[WCS控制立体库设备执行任务]
J --> K[设备执行中...]
K --> L{任务执行结果}
L -->|执行成功| M[WCS更新任务状态]
L -->|执行失败| N[WCS记录异常并重试]
M --> O[WCS回调WMS状态更新]
N --> P{重试次数达到上限}
P -->|是| Q[WCS回调WMS失败状态]
P -->|否| J
O --> R[WMS接收状态更新]
Q --> R
H --> R
R --> S{是否需要AGV配合}
S -->|是| T[WMS调度AGV]
S -->|否| U[任务完成]
T --> U
```
## 流程步骤说明
1. **任务创建**WMS系统创建入库或出库任务
2. **接口调用**根据任务类型调用WCS相应接口
3. **参数验证**WCS系统验证接收到的任务参数
4. **任务执行**WCS系统控制立体库设备执行任务
5. **状态反馈**WCS系统向WMS系统反馈任务执行状态
6. **AGV配合**根据需要WMS系统调度AGV进行配合操作

View File

@@ -0,0 +1,343 @@
# WCS系统与WMS/AGV对接业务文档
## 项目概述
### 项目背景
WCSWarehouse Control System仓库控制系统作为自动化立体仓库的核心控制系统负责与WMS仓库管理系统和AGV自动导引车系统进行对接实现货物的自动化入库、出库、移库等操作。
### 项目目标
- 实现WCS系统与WMS系统的无缝对接
- 实现WCS系统与AGV系统的协调作业
- 提供标准化接口,确保三方系统稳定运行
- 实现出入库、移库等核心业务流程
## WCS系统核心功能
### 1. 入库/上架功能
- 接收WMS系统的入库任务
- 控制立体库设备执行上架操作
- 实时反馈任务执行状态给WMS系统
### 2. 出库/下架功能
- 接收WMS系统的出库任务
- 控制立体库设备执行下架操作
- 实时反馈任务执行状态给WMS系统
### 3. 库位管理功能
- 管理立体库所有库位状态
- 实时更新库位占用情况
- 提供库位查询接口
### 4. 任务调度功能
- 任务队列管理
- 任务优先级调度
- 设备资源分配
## WCS系统对外接口
### 1. 入库/上架接口(/API/Ruku
#### 接口说明
WMS系统调用此接口创建入库/上架任务
#### 请求方式
POST
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| TaskID | String | 是 | 任务ID |
| TrayNo | String | 否 | 托盘号 |
| Materialstatus | Integer | 是 | 物料状态0: 空托盘1: 有货) |
| MaterialCode | String | 否 | 物料编码Materialstatus为1时必填 |
| Specification | String | 否 | 规格 |
| Quantity | String | 否 | 数量 |
| Mlocation | String | 是 | 目标库位 |
| Tlocation | String | 是 | 来源库位 |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| result | String | 结果("success"表示成功) |
| errorMessage | String | 错误消息 |
### 2. 出库/下架接口(/API/Chuku
#### 接口说明
WMS系统调用此接口创建出库/下架任务
#### 请求方式
POST
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| TaskID | String | 是 | 任务ID |
| TaskType | Integer | 是 | 任务类型1: 出库) |
| Mlocation | String | 是 | 来源库位 |
| TrayNo | String | 否 | 托盘号 |
| Materialstatus | Integer | 是 | 物料状态0: 空托盘1: 有货) |
| outBack | Integer | 是 | 固定值1 |
| MaterialCode | String | 否 | 物料编码Materialstatus为1时必填 |
| Specification | String | 否 | 规格 |
| Quantity | String | 否 | 数量 |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| result | String | 结果("success"表示成功) |
| errorMessage | String | 错误消息 |
## WCS系统开发工作内容
### 1. 接口开发工作
#### 1.1 入库/上架接口开发
- **工作内容**:开发 `/API/Ruku` 接口处理WMS入库任务请求
- **技术实现**
- HTTP POST接口开发
- JSON数据解析
- 业务参数验证
- 任务创建与调度
- 响应格式化
- **预计工时**16小时
#### 1.2 出库/下架接口开发
- **工作内容**:开发 `/API/Chuku` 接口处理WMS出库任务请求
- **技术实现**
- HTTP POST接口开发
- JSON数据解析
- 业务参数验证
- 任务创建与调度
- 响应格式化
- **预计工时**16小时
#### 1.3 任务状态回调接口开发
- **工作内容**实现WCS任务状态回调机制
- **技术实现**
- 状态变更触发器
- HTTP回调请求
- 状态同步机制
- **预计工时**24小时
### 2. 业务逻辑开发工作
#### 2.1 货物上架逻辑实现
- **工作内容**:实现完整的货物上架业务流程
- **技术实现**
- 库位分配算法
- 设备控制指令生成
- 执行状态跟踪
- 异常处理机制
- **预计工时**32小时
#### 2.2 货物下架逻辑实现
- **工作内容**:实现完整的货物下架业务流程
- **技术实现**
- 货物定位算法
- 设备控制指令生成
- 执行状态跟踪
- 异常处理机制
- **预计工时**32小时
#### 2.3 任务调度与排队机制
- **工作内容**:实现多任务排队调度算法
- **技术实现**
- 任务队列管理
- 优先级调度算法
- 设备资源分配
- 任务冲突解决
- **预计工时**24小时
### 3. 系统集成开发工作
#### 3.1 与WMS系统接口对接
- **工作内容**确保WCS与WMS系统稳定通信
- **技术实现**
- 接口协议实现
- 数据格式转换
- 通信安全机制
- 错误重试机制
- **预计工时**20小时
#### 3.2 与AGV系统协调机制
- **工作内容**实现WCS与AGV系统的任务协调
- **技术实现**
- 协调接口开发
- 状态同步机制
- 任务交接处理
- **预计工时**16小时
### 4. 数据管理开发工作
#### 4.1 任务数据存储与管理
- **工作内容**:开发任务数据的存储和管理功能
- **技术实现**
- 数据库表设计
- 数据访问层开发
- 数据一致性保证
- 数据清理机制
- **预计工时**20小时
#### 4.2 库位状态数据维护
- **工作内容**:实现库位状态的实时维护
- **技术实现**
- 库位状态表设计
- 状态变更处理
- 数据同步机制
- 状态查询接口
- **预计工时**16小时
### 5. 监控与维护开发工作
#### 5.1 系统运行状态监控
- **工作内容**:开发系统运行状态监控功能
- **技术实现**
- 监控指标定义
- 监控接口开发
- 异常告警机制
- **预计工时**12小时
#### 5.2 异常处理与恢复机制
- **工作内容**:开发完善的异常处理和任务恢复机制
- **技术实现**
- 异常类型定义
- 异常处理策略
- 任务恢复机制
- 日志记录系统
- **预计工时**20小时
## 系统对接流程图
```mermaid
graph TD
A[WMS创建任务] --> B{判断任务类型}
B -->|入库/上架| C[WMS调用WCS /API/Ruku接口]
B -->|出库/下架| D[WMS调用WCS /API/Chuku接口]
C --> E[WCS接收任务请求]
D --> E
E --> F[WCS验证任务参数]
F --> G{参数验证结果}
G -->|验证失败| H[WCS返回错误信息给WMS]
G -->|验证成功| I[WCS创建内部任务]
I --> J[WCS控制立体库设备执行任务]
J --> K[设备执行中...]
K --> L{任务执行结果}
L -->|执行成功| M[WCS更新任务状态]
L -->|执行失败| N[WCS记录异常并重试]
M --> O[WCS回调WMS状态更新]
N --> P{重试次数达到上限}
P -->|是| Q[WCS回调WMS失败状态]
P -->|否| J
O --> R[WMS接收状态更新]
Q --> R
H --> R
R --> S{是否需要AGV配合}
S -->|是| T[WMS调度AGV]
S -->|否| U[任务完成]
T --> U
```
## 项目实施计划
### 第一阶段接口开发预计2周
- 完成入库/上架接口开发
- 完成出库/下架接口开发
- 完成基础数据模型设计
### 第二阶段业务逻辑开发预计3周
- 完成货物上架逻辑开发
- 完成货物下架逻辑开发
- 完成任务调度机制开发
### 第三阶段系统集成预计2周
- 完成与WMS系统对接
- 完成与AGV系统协调
- 完成监控功能开发
### 第四阶段测试与优化预计1周
- 系统集成测试
- 性能优化
- 异常处理完善
## 项目交付物
1. **技术文档**
- 接口规范文档
- 部署手册
- 运维手册
2. **软件系统**
- WCS系统核心程序
- 数据库脚本
- 配置文件
3. **测试报告**
- 单元测试报告
- 集成测试报告
- 性能测试报告
## 项目价值体现
### 1. 技术价值
- 提供标准化接口,实现系统间无缝对接
- 实现复杂的任务调度算法
- 确保系统高可用性和稳定性
### 2. 业务价值
- 实现仓库作业自动化
- 提高仓储效率和准确性
- 降低人工成本
### 3. 服务价值
- 专业的技术开发服务
- 完善的系统集成方案
- 持续的技术支持服务
## 风险与应对
### 1. 技术风险
- **风险**:接口兼容性问题
- **应对**:提前进行接口规范确认
### 2. 集成风险
- **风险**:三方系统集成复杂度高
- **应对**:分阶段集成测试
### 3. 性能风险
- **风险**:高并发场景下系统性能
- **应对**:性能测试与优化
## 服务收费标准
基于上述开发工作内容WCS系统与WMS/AGV对接服务包含以下收费项目
### 1. 接口开发服务40小时
- 入库/上架接口16小时
- 出库/下架接口16小时
- 任务状态回调接口8小时
### 2. 业务逻辑开发88小时
- 货物上架逻辑32小时
- 货物下架逻辑32小时
- 任务调度机制24小时
### 3. 系统集成服务36小时
- 与WMS系统对接20小时
- 与AGV系统协调16小时
### 4. 数据管理开发36小时
- 任务数据管理20小时
- 库位状态维护16小时
### 5. 监控维护开发32小时
- 系统监控12小时
- 异常处理机制20小时
**总计开发工时232小时**

View File

@@ -0,0 +1,17 @@
package com.zg.project.wisdom.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "qwen-ocr")
@Data
public class QwenOcrRemoteProperties {
/**
* 远程 OCR 服务的完整地址
* 例如http://192.168.1.5:8087/ocr/extractErpByBase64
*/
private String baseUrl;
}

View File

@@ -43,6 +43,7 @@ public class AuditSignatureController extends BaseController
* 上传签字图片到 MinIO
*/
@PostMapping("/upload")
@Log(title = "签字图片上传", businessType = BusinessType.INSERT)
public AjaxResult uploadSignature(@RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return AjaxResult.error("上传文件不能为空");
@@ -56,6 +57,7 @@ public class AuditSignatureController extends BaseController
}
// 上传图片接收base64格式 zhangjinbo
@PostMapping("/uploadBase64")
@Log(title = "签字图片上传", businessType = BusinessType.INSERT)
public AjaxResult uploadSignatureBase64(@RequestBody Map<String, String> param) {
String imgStr = param.get("imgStr");
// return AjaxResult.success("上传成功").put("url", imgStr);
@@ -150,6 +152,7 @@ public class AuditSignatureController extends BaseController
* 审核操作(通过 / 驳回)
*/
@PostMapping("/audit")
@Log(title = "审批记录", businessType = BusinessType.UPDATE)
public AjaxResult audit(@RequestBody AuditSignature audit) {
try {
auditSignatureService.audit(audit);

View File

@@ -2,6 +2,11 @@ package com.zg.project.wisdom.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson2.JSON;
import com.zg.common.utils.StringUtils;
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -123,4 +128,39 @@ public class GysJhController extends BaseController
{
return toAjax(gysJhService.deleteGysJhByIds(ids));
}
/**
* 供应计划导入(带字段映射)
*
* 前端 form-data 结构示例:
* - file: 选中的 excel 文件
* - mapping[0].label = wlNo
* - mapping[0].prop = E
* - mapping[1].label = wlMs
* - mapping[1].prop = F
* ...
*/
@PreAuthorize("@ss.hasPermi('wisdom:gysJh:import')")
@Log(title = "供应计划导入", businessType = BusinessType.IMPORT)
@PostMapping(
value = "/importByMapping",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
)
public AjaxResult importByMapping(@RequestPart("file") MultipartFile file,
@RequestParam("mapping") String mappingJson) throws Exception {
if (file == null || file.isEmpty()) {
return AjaxResult.error("导入文件不能为空");
}
if (StringUtils.isBlank(mappingJson)) {
return AjaxResult.error("字段映射不能为空");
}
// 把 JSON 字符串转成 List<ExcelFieldMapping>
List<ExcelFieldMapping> mapping =
JSON.parseArray(mappingJson, ExcelFieldMapping.class);
int rows = gysJhService.importByMapping(file, mapping);
return AjaxResult.success("成功导入 " + rows + " 条记录");
}
}

View File

@@ -1,5 +1,7 @@
package com.zg.project.wisdom.controller;
import com.zg.framework.aspectj.lang.annotation.Log;
import com.zg.framework.aspectj.lang.enums.BusinessType;
import com.zg.framework.web.domain.AjaxResult;
import com.zg.project.wisdom.domain.dto.PhotoDeleteDTO;
import com.zg.project.wisdom.service.PhotoService;
@@ -38,6 +40,7 @@ public class PhotoController {
* 返回:每张图片的可访问 URL 列表
*/
@PostMapping(value = "/upload/batch", consumes = "multipart/form-data")
@Log(title = "照片上传", businessType = BusinessType.INSERT)
public AjaxResult uploadBatch(@RequestPart("files") List<MultipartFile> files,
@RequestParam("photoType") String photoType,
@RequestParam("billNo") String billNo,
@@ -88,12 +91,13 @@ public class PhotoController {
* @return
*/
@PostMapping(value = "/delete", consumes = "application/json")
// @PreAuthorize("@ss.hasPermi('wisdom:photo:remove')")
@Log(title = "照片删除", businessType = BusinessType.DELETE)
public AjaxResult delete(@Validated @RequestBody PhotoDeleteDTO dto) {
Map<String, Object> result = photoService.deleteByUrls(dto.getUrls());
return AjaxResult.success("删除完成", result);
}
@GetMapping("/deleteById")
@Log(title = "照片删除", businessType = BusinessType.DELETE)
public AjaxResult deleteById(@RequestParam("id") Integer id){
return AjaxResult.success(photoService.deleteById(id));
}

View File

@@ -9,6 +9,7 @@ import com.github.pagehelper.PageHelper;
import com.zg.project.wisdom.domain.dto.*;
import com.zg.project.wisdom.domain.vo.DeliveryBillVO;
import com.zg.project.wisdom.domain.vo.PcodeQtyVO;
import com.zg.project.wisdom.service.QwenOcrRemoteService;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
@@ -21,6 +22,7 @@ import com.zg.framework.web.controller.BaseController;
import com.zg.framework.web.domain.AjaxResult;
import com.zg.common.utils.poi.ExcelUtil;
import com.zg.framework.web.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;
/**
* 库存单据主Controller
@@ -35,6 +37,9 @@ public class RkInfoController extends BaseController
@Autowired
private IRkInfoService rkInfoService;
@Autowired
private QwenOcrRemoteService qwenOcrRemoteService;
/**
* 查询出库,借料,待审批,撤销出入库单据主列表
@@ -47,7 +52,6 @@ public class RkInfoController extends BaseController
return getDataTable(list);
}
// @PreAuthorize("@ss.hasPermi('wisdom:stock:stat')")
@GetMapping("/pcode/{pcode}")
public AjaxResult listRkInfoByPcode(@PathVariable String pcode) {
List<RkInfo> rows = rkInfoService.listRkInfoByPcode(pcode);
@@ -128,7 +132,6 @@ public class RkInfoController extends BaseController
* @return
*/
@GetMapping("/warning/stock/over20")
@PreAuthorize("@ss.hasPermi('wisdom:stock:warning')")
public AjaxResult getOverdueStockTopList() {
int total = rkInfoService.countOverdueStock();
List<RkInfo> list = rkInfoService.selectTopOverdueStock(20);
@@ -144,7 +147,7 @@ public class RkInfoController extends BaseController
* @return
*/
@PutMapping("/deleteByCkBillNo")
@PreAuthorize("@ss.hasPermi('wisdom:stock:deleteByBillNo')")
@Log(title = "库存单据主", businessType = BusinessType.UPDATE)
public AjaxResult deleteByCkBillNo(@RequestBody Map<String, String> body) {
String billNoCk = body.get("billNoCk");
if (billNoCk == null || billNoCk.trim().isEmpty()) {
@@ -161,7 +164,7 @@ public class RkInfoController extends BaseController
* 根据主键ID撤销入库
*/
@PostMapping("/cancel")
@PreAuthorize("@ss.hasPermi('wisdom:stock:deleteByBillNo')")
@Log(title = "库存单据主", businessType = BusinessType.UPDATE)
public AjaxResult deleteById(@RequestBody RkCancelDTO dto) {
rkInfoService.deleteRkInfoById(dto);
return AjaxResult.success("撤销成功");
@@ -171,7 +174,7 @@ public class RkInfoController extends BaseController
* 根据主键ID撤销出库
*/
@PostMapping("/cancelById/{id}")
@PreAuthorize("@ss.hasPermi('wisdom:stock:deleteByBillNo')")
@Log(title = "库存单据主", businessType = BusinessType.UPDATE)
public AjaxResult cancelOutStockById(@PathVariable Long id) {
rkInfoService.cancelOutStockById(id);
return AjaxResult.success("撤销出库成功");
@@ -183,7 +186,7 @@ public class RkInfoController extends BaseController
* 出入库撤销记录删除
*/
@PostMapping("/deleteByIds")
@PreAuthorize("@ss.hasPermi('wisdom:stock:deleteById')")
@Log(title = "库存单据主", businessType = BusinessType.UPDATE)
public AjaxResult deleteByIds(@RequestBody Long[] ids) {
return AjaxResult.success(rkInfoService.deleteRkInfoByIds(ids));
}
@@ -192,7 +195,7 @@ public class RkInfoController extends BaseController
* 根据ids恢复出库或入库
*/
@PostMapping("/revertByIds")
@PreAuthorize("@ss.hasPermi('wisdom:stock:deleteById')")
@Log(title = "库存单据主", businessType = BusinessType.UPDATE)
public AjaxResult revertByIds(@RequestBody Long[] ids) {
rkInfoService.revertByIds(ids);
return AjaxResult.success();
@@ -302,14 +305,39 @@ public class RkInfoController extends BaseController
@PostMapping("/updateDeliveryStatus")
@Log(title = "更新配送状态", businessType = BusinessType.UPDATE)
public AjaxResult updateDeliveryStatus(@RequestBody RkDeliveryUpdateDTO dto) {
if (dto.getBillNoCk() == null) {
return AjaxResult.error("出库单据号不能为空");
if (dto.getIds() == null || dto.getIds().isEmpty()) {
return AjaxResult.error("rk_info 主键ID集合不能为空");
}
if (dto.getIsDelivery() == null) {
return AjaxResult.error("配送状态不能为空");
}
int rows = rkInfoService.updateDeliveryStatus(dto.getBillNoCk(), dto.getIsDelivery());
int rows = rkInfoService.updateDeliveryStatus(dto.getIds(), dto.getIsDelivery());
return AjaxResult.success(rows);
}
/**
* 上传图片,识别采购订单号(ERP)
*
* 前端调用示例multipart/form-data
* POST /wisdom/ocr/extractErp
* file: <图片文件>
*/
@PostMapping("/extractErp")
public AjaxResult extractErp(@RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return AjaxResult.error("上传文件不能为空");
}
String erpOrderNo = qwenOcrRemoteService.extractErpOrderNo(file);
return AjaxResult.success(erpOrderNo);
}
}

View File

@@ -0,0 +1,14 @@
package com.zg.project.wisdom.domain.dto;
import lombok.Data;
@Data
public class ExcelFieldMapping {
/** 后端字段名,如 wlNo、sapNo */
private String label;
/** Excel 列,如 A、B、C、AA */
private String prop;
}

View File

@@ -0,0 +1,62 @@
package com.zg.project.wisdom.domain.dto;
import java.util.List;
/**
* 供应计划导入DTO - 支持自定义映射关系
*
* @author zg
* @date 2025-12-01
*/
public class GysJhImportDTO {
/**
* 映射关系对象
*/
public static class MappingItem {
private String label; // 字段标识名
private String prop; // Excel列标识如A、B、C等
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop = prop;
}
}
/**
* 映射关系数组
*/
private List<MappingItem> mapping;
/**
* 操作人
*/
private String operName;
public List<MappingItem> getMapping() {
return mapping;
}
public void setMapping(List<MappingItem> mapping) {
this.mapping = mapping;
}
public String getOperName() {
return operName;
}
public void setOperName(String operName) {
this.operName = operName;
}
}

View File

@@ -2,8 +2,14 @@ package com.zg.project.wisdom.domain.dto;
import lombok.Data;
import java.util.List;
@Data
public class RkDeliveryUpdateDTO {
private String billNoCk;
private Integer isDelivery; // 0否 1是 2配送中 3已完成
/** rk_info 主键ID集合 */
private List<Long> ids;
/** 配送状态0否 1是 2配送中 3已完成 */
private Integer isDelivery;
}

View File

@@ -86,15 +86,13 @@ public interface GysJhMapper
void resetGysJhStatusBySapNos(List<String> sapNos);
/**
* 根据sapNo和xmNo和wlNo查询
* @param sapNo
* @param xmNo
* @param wlNo
* @return
* 【已注释】根据SAP订单号、项目号和物料号检查是否已存在唯一性校验
* @param sapNo SAP订单号
* @param xmNo 项目号
* @param wlNo 物料号
* @return 是否存在
*/
boolean existsByUniqueKeys(@Param("sapNo") String sapNo,
@Param("xmNo") String xmNo,
@Param("wlNo") String wlNo);
// boolean existsByUniqueKeys(@Param("sapNo") String sapNo, @Param("xmNo") String xmNo, @Param("wlNo") String wlNo);
/**
* 批量修改状态

View File

@@ -236,7 +236,8 @@ public interface RkInfoMapper
* 修改出库单据状态
*/
int updateDeliveryStatus(@Param("billNoCk") String billNoCk,
int updateDeliveryStatus(@Param("ids") List<Long> ids,
@Param("isDelivery") Integer isDelivery);
/**

View File

@@ -2,6 +2,8 @@ package com.zg.project.wisdom.service;
import java.util.List;
import com.zg.project.wisdom.domain.GysJh;
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
import org.springframework.web.multipart.MultipartFile;
/**
* 供应计划Service接口
@@ -73,4 +75,10 @@ public interface IGysJhService
* @return
*/
List<GysJh> getBySapNo(String sapNo);
/**
* 按字段映射导入供应计划
*/
int importByMapping(MultipartFile file, List<ExcelFieldMapping> mapping) throws Exception;
}

View File

@@ -175,12 +175,11 @@ public interface IRkInfoService
void appendToExistingBill(PcRkInfoBatchDTO dto);
/**
* 修改出库单的配送状态
* @param billNoCk
* @param isDelivery
* @return
* 按 rk_info 主键ID集合修改配送状态
* @param ids rk_info.id 集合
* @param isDelivery 配送状态
*/
int updateDeliveryStatus(String billNoCk, Integer isDelivery);
int updateDeliveryStatus(List<Long> ids, Integer isDelivery);
/**
* 获取指定出库单的配送信息

View File

@@ -0,0 +1,98 @@
package com.zg.project.wisdom.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zg.project.wisdom.config.QwenOcrRemoteProperties;
import okhttp3.*;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Base64;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@Service
public class QwenOcrRemoteService {
private final QwenOcrRemoteProperties properties;
private final ObjectMapper objectMapper = new ObjectMapper();
private final OkHttpClient httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(25, TimeUnit.SECONDS)
.writeTimeout(25, TimeUnit.SECONDS)
.build();
public QwenOcrRemoteService(QwenOcrRemoteProperties properties) {
this.properties = properties;
}
/**
* 接收上传的图片文件,转成 Base64 后,
* 调用 250 上的 /ocr/extractErpByBase64 接口,返回采购订单号(ERP)
*/
public String extractErpOrderNo(MultipartFile file) {
try {
// 1. 读取文件字节
byte[] bytes = file.getBytes();
// 2. 推断 contentType
String contentType = file.getContentType();
if (contentType == null || contentType.isEmpty()) {
String name = file.getOriginalFilename();
if (name != null && name.toLowerCase().endsWith(".png")) {
contentType = "image/png";
} else {
contentType = "image/jpeg";
}
}
// 3. 转成 Base64并加上 data: 前缀
String base64 = Base64.getEncoder().encodeToString(bytes);
String imageBase64 = "data:" + contentType + ";base64," + base64;
// 4. 组装 JSON 请求体:{ "imageBase64": "data:image/jpeg;base64,xxxx" }
String json = objectMapper.createObjectNode()
.put("imageBase64", imageBase64)
.toString();
RequestBody body = RequestBody.create(
MediaType.parse("application/json"),
json
);
String url = properties.getBaseUrl(); // yml 里配置的 /ocr/extractErpByBase64
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 5. 发送 HTTP 请求
Response response = httpClient.newCall(request).execute();
try {
if (!response.isSuccessful()) {
String errorBody = response.body() != null ? response.body().string() : "no error body";
throw new RuntimeException("调用远程 OCR 服务失败HTTP 状态码:" +
response.code() + ",错误信息:" + errorBody);
}
String resp = Objects.requireNonNull(response.body()).string();
JsonNode rootNode = objectMapper.readTree(resp);
// 远程服务返回:{ success: true, found: true/false, erpOrderNo: "0101398982" }
JsonNode erpNode = rootNode.get("erpOrderNo");
if (erpNode == null || erpNode.isNull()) {
return "";
}
return erpNode.asText("");
} finally {
response.close();
}
} catch (IOException e) {
throw new RuntimeException("调用远程 OCR 服务异常:" + e.getMessage(), e);
}
}
}

View File

@@ -1,14 +1,22 @@
package com.zg.project.wisdom.service.impl;
import java.util.List;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import com.zg.common.exception.ServiceException;
import com.zg.common.utils.DateUtils;
import com.zg.common.utils.SecurityUtils;
import com.zg.common.utils.StringUtils;
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zg.project.wisdom.mapper.GysJhMapper;
import com.zg.project.wisdom.domain.GysJh;
import com.zg.project.wisdom.service.IGysJhService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
/**
* 供应计划Service业务层处理
@@ -115,15 +123,15 @@ public class GysJhServiceImpl implements IGysJhService
for (GysJh jh : jhList) {
try {
// 唯一性校验:订单号 + 项目号 + 物料号
boolean exists = gysJhMapper.existsByUniqueKeys(jh.getSapNo(), jh.getXmNo(), jh.getWlNo());
if (exists) {
failureNum++;
failureMsg.append("<br/>订单号:").append(jh.getSapNo())
.append(",项目号:").append(jh.getXmNo())
.append(",物料号:").append(jh.getWlNo())
.append(" 已存在,跳过导入。");
continue;
}
// boolean exists = gysJhMapper.existsByUniqueKeys(jh.getSapNo(), jh.getXmNo(), jh.getWlNo());
// if (exists) {
// failureNum++;
// failureMsg.append("<br/>订单号:").append(jh.getSapNo())
// .append(",项目号:").append(jh.getXmNo())
// .append(",物料号:").append(jh.getWlNo())
// .append(" 已存在,跳过导入。");
// continue;
// }
jh.setCreateBy(operName);
jh.setStatus("0");
@@ -157,4 +165,225 @@ public class GysJhServiceImpl implements IGysJhService
public List<GysJh> getBySapNo(String sapNo) {
return gysJhMapper.getBySapNo(sapNo);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int importByMapping(MultipartFile file, List<ExcelFieldMapping> mapping) throws Exception {
List<GysJh> list = parseExcel(file, mapping);
if (list == null || list.isEmpty()) {
return 0;
}
for (GysJh item : list) {
gysJhMapper.insertGysJh(item);
}
return list.size();
}
/**
* 解析 Excel -> GysJh 列表
*/
private List<GysJh> parseExcel(MultipartFile file, List<ExcelFieldMapping> mappingList) throws Exception {
List<GysJh> result = new ArrayList<>();
try (InputStream is = file.getInputStream();
Workbook workbook = WorkbookFactory.create(is)) {
Sheet sheet = workbook.getSheetAt(0);
if (sheet == null) {
return result;
}
// 1. 把映射转换成:字段名 -> 列索引
Map<String, Integer> fieldColumnIndex = new HashMap<>();
for (ExcelFieldMapping m : mappingList) {
if (m == null) {
continue;
}
String label = m.getLabel(); // wlNo / jhAmt ...
String prop = m.getProp(); // A / B / C ...
if (StringUtils.isEmpty(label) || StringUtils.isEmpty(prop)) {
continue;
}
fieldColumnIndex.put(label, excelColToIndex(prop));
}
DataFormatter formatter = new DataFormatter();
int firstRowNum = sheet.getFirstRowNum();
int lastRowNum = sheet.getLastRowNum();
// 默认第一行是表头,从第二行开始读
for (int rowNum = firstRowNum + 1; rowNum <= lastRowNum; rowNum++) {
Row row = sheet.getRow(rowNum);
if (row == null) {
continue;
}
// 关键字段都为空则认为是空行,跳过
String wlNoVal = getCellString(row, fieldColumnIndex.get("wlNo"), formatter);
String sapNoVal = getCellString(row, fieldColumnIndex.get("sapNo"), formatter);
if (StringUtils.isEmpty(wlNoVal) && StringUtils.isEmpty(sapNoVal)) {
continue;
}
GysJh item = new GysJh();
// 序号可以用行号,也可以单独映射,看你需求
item.setIndexNo((long) (rowNum));
// 按字段名逐个赋值
for (Map.Entry<String, Integer> entry : fieldColumnIndex.entrySet()) {
String field = entry.getKey();
Integer colIndex = entry.getValue();
String cellValue = getCellString(row, colIndex, formatter);
if (StringUtils.isEmpty(cellValue)) {
continue;
}
switch (field) {
case "wlNo":
item.setWlNo(cellValue.trim());
break;
case "wlMs":
item.setWlMs(cellValue.trim());
break;
case "xmNo":
item.setXmNo(cellValue.trim());
break;
case "xmMs":
item.setXmMs(cellValue.trim());
break;
case "dw":
item.setDw(cellValue.trim());
break;
case "gysNo":
item.setGysNo(cellValue.trim());
break;
case "gysMc":
item.setGysMc(cellValue.trim());
break;
case "jhAmt":
// BigDecimal
item.setJhAmt(parseBigDecimal(cellValue));
break;
case "htDj":
// BigDecimal
item.setHtDj(parseBigDecimal(cellValue));
break;
case "jhQty":
// Long这里用 Long避免 BigDecimal 转 Long 的报错
item.setJhQty(parseLong(cellValue));
break;
case "htQty":
item.setHtQty(parseLong(cellValue));
break;
case "sapNo":
item.setSapNo(cellValue.trim());
break;
default:
// 以后扩展字段,就在上面加 case
break;
}
}
// 默认字段
item.setStatus("0");
item.setIsDelete("0");
// String username = SecurityUtils.getUsername();
item.setCreateBy("大爷的!!!");
item.setCreateTime(DateUtils.getNowDate());
result.add(item);
}
}
return result;
}
/**
* Excel 列字母转索引A -> 0, B -> 1, ..., AA -> 26
*/
private int excelColToIndex(String col) {
col = col.trim().toUpperCase();
int index = 0;
for (int i = 0; i < col.length(); i++) {
char c = col.charAt(i);
index = index * 26 + (c - 'A' + 1);
}
return index - 1;
}
/**
* 统一获取单元格字符串
*/
private String getCellString(Row row, Integer colIndex, DataFormatter formatter) {
if (row == null || colIndex == null || colIndex < 0) {
return null;
}
Cell cell = row.getCell(colIndex);
if (cell == null) {
return null;
}
String val = formatter.formatCellValue(cell);
return StringUtils.isEmpty(val) ? null : val.trim();
}
/**
* 字符串转 BigDecimal空串返回 null
*/
/**
* 字符串转 BigDecimal空串或"null"返回 null
*/
private BigDecimal parseBigDecimal(String value) {
if (StringUtils.isEmpty(value)) {
return null;
}
try {
String trimmedValue = value.trim();
if ("null".equalsIgnoreCase(trimmedValue)) {
return null;
}
// 去掉千分位逗号
String v = trimmedValue.replace(",", "").trim();
// 再次检查处理后的值
if (StringUtils.isEmpty(v) || "null".equalsIgnoreCase(v)) {
return null;
}
return new BigDecimal(v);
} catch (NumberFormatException e) {
// 记录详细错误信息以便调试
// log.warn("解析BigDecimal失败输入值: '{}'", value, e);
return null;
}
}
/**
* 字符串转 Long空串返回 null
*/
private Long parseLong(String value) {
if (StringUtils.isEmpty(value)) {
return null;
}
String trimmedValue = value.trim();
if ("null".equalsIgnoreCase(trimmedValue)) {
return null;
}
try {
String v = trimmedValue.replace(",", "").trim();
if (StringUtils.isEmpty(v) || "null".equalsIgnoreCase(v)) {
return null;
}
return Long.valueOf(v);
} catch (NumberFormatException e) {
// log.warn("无法解析为Long的值: '{}'", value);
return null;
}
}
}

View File

@@ -1128,8 +1128,11 @@ public class RkInfoServiceImpl implements IRkInfoService
}
@Override
public int updateDeliveryStatus(String billNoCk, Integer isDelivery) {
return rkInfoMapper.updateDeliveryStatus(billNoCk, isDelivery);
public int updateDeliveryStatus(List<Long> ids, Integer isDelivery) {
if (ids == null || ids.isEmpty()) {
return 0;
}
return rkInfoMapper.updateDeliveryStatus(ids, isDelivery);
}
@Override

View File

@@ -165,4 +165,8 @@ minio:
mock:
agv-job-create-url: http://localhost:8086/mock/agv/task/create
wcs-job-create-url: http://localhost:8086/mock/wcs/task/create
wcs-job-create-url: http://localhost:8086/mock/wcs/task/create
#配送系统中调用大模型进行图片识别
qwen-ocr:
base-url: http://192.168.1.253:8087/ocr/extractErpByBase64

View File

@@ -76,14 +76,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND status != '1'
</select>
<select id="existsByUniqueKeys" resultType="boolean">
<!-- 【已注释】唯一性校验查询基于SAP订单号、项目号、物料号判断是否已存在 -->
<!-- <select id="existsByUniqueKeys" resultType="boolean">
SELECT COUNT(1)
FROM gys_jh
WHERE sap_no = #{sapNo}
AND xm_no = #{xmNo}
AND wl_no = #{wlNo}
AND is_delete != '1'
</select>
</select> -->
<select id="selectByIds" resultMap="GysJhResult">
SELECT * FROM gys_jh
@@ -230,4 +231,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{id}
</foreach>
</delete>
</mapper>
</mapper>

View File

@@ -1223,8 +1223,10 @@
<update id="updateDeliveryStatus">
UPDATE rk_info
SET is_delivery = #{isDelivery}
WHERE bill_no_ck = #{billNoCk}
AND is_delete = '0'
WHERE is_delete = '0'
AND id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
</mapper>

View File

@@ -0,0 +1,639 @@
# 智慧仓储系统综合业务文档
## 项目概述
### 项目背景
智慧仓储系统包含WCSWarehouse Control System仓库控制系统、WMS仓库管理系统、AGV自动导引车系统以及Inventory库存盘点系统形成一个完整的自动化仓储解决方案。各系统协同工作实现货物的自动化入库、出库、移库、盘点等操作。
### 项目目标
- 实现WCS系统与WMS系统的无缝对接
- 实现WCS系统与AGV系统的协调作业
- 实现Inventory系统对库存的精确管理
- 提供标准化接口,确保多系统稳定运行
- 实现出入库、移库、盘点等核心业务流程
## WCS系统核心功能
### 1. 入库/上架功能
- 接收WMS系统的入库任务
- 控制立体库设备执行上架操作
- 实时反馈任务执行状态给WMS系统
### 2. 出库/下架功能
- 接收WMS系统的出库任务
- 控制立体库设备执行下架操作
- 实时反馈任务执行状态给WMS系统
### 3. 库位管理功能
- 管理立体库所有库位状态
- 实时更新库位占用情况
- 提供库位查询接口
### 4. 任务调度功能
- 任务队列管理
- 任务优先级调度
- 设备资源分配
## Inventory系统核心功能
### 1. 盘点任务管理
- 创建盘点任务设置任务名称、仓库ID、场景ID、执行人、完成时间等
- 任务类型手持盘点0和自动盘点1
- 任务状态待执行0、已完成1、已超时2
### 2. 自动盘点功能
- 设备连接管理通过RFID设备IP和端口建立TCP连接
- 标签扫描启动RFID设备进行标签扫描
- 数据传输通过WebSocket将扫描到的EPC标签数据发送给前端
- 扫描控制:支持开始、停止、断开连接等操作
### 3. 数据匹配功能
- 将扫描数据与系统库存数据进行匹配
- 生成匹配结果(正常、未扫到、误扫)
- 统计盘点结果并生成图表
### 4. 报告管理功能
- 生成盘点统计图表
- 导出盘点报告
- 提供历史盘点记录查询
## WCS系统对外接口
### 1. 入库/上架接口(/API/Ruku
#### 接口说明
WMS系统调用此接口创建入库/上架任务
#### 请求方式
POST
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| TaskID | String | 是 | 任务ID |
| TrayNo | String | 否 | 托盘号 |
| Materialstatus | Integer | 是 | 物料状态0: 空托盘1: 有货) |
| MaterialCode | String | 否 | 物料编码Materialstatus为1时必填 |
| Specification | String | 否 | 规格 |
| Quantity | String | 否 | 数量 |
| Mlocation | String | 是 | 目标库位 |
| Tlocation | String | 是 | 来源库位 |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| result | String | 结果("success"表示成功) |
| errorMessage | String | 错误消息 |
### 2. 出库/下架接口(/API/Chuku
#### 接口说明
WMS系统调用此接口创建出库/下架任务
#### 请求方式
POST
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| TaskID | String | 是 | 任务ID |
| TaskType | Integer | 是 | 任务类型1: 出库) |
| Mlocation | String | 是 | 来源库位 |
| TrayNo | String | 否 | 托盘号 |
| Materialstatus | Integer | 是 | 物料状态0: 空托盘1: 有货) |
| outBack | Integer | 是 | 固定值1 |
| MaterialCode | String | 否 | 物料编码Materialstatus为1时必填 |
| Specification | String | 否 | 规格 |
| Quantity | String | 否 | 数量 |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| result | String | 结果("success"表示成功) |
| errorMessage | String | 错误消息 |
## Inventory系统对外接口
### 1. 设备连接接口(/AutoInventory/connect
#### 接口说明
建立RFID设备连接
#### 请求方式
POST
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
| ip | String | 是 | 设备IP地址 |
| port | Integer | 是 | 设备端口号 |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 2. 开始盘点接口(/AutoInventory/scan
#### 接口说明
启动RFID设备进行标签扫描
#### 请求方式
GET
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 3. 停止盘点接口(/AutoInventory/stop
#### 接口说明
停止RFID设备扫描
#### 请求方式
GET
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 4. 断开连接接口(/AutoInventory/disconnect
#### 接口说明
断开RFID设备连接
#### 请求方式
GET
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 5. 设备状态查询接口(/AutoInventory/status
#### 接口说明
查询RFID设备连接状态
#### 请求方式
GET
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息(包含设备连接状态) |
### 6. 开始匹配接口(/AutoInventory/match
#### 接口说明
将扫描数据与系统库存数据进行匹配
#### 请求方式
POST
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| taskId | String | 是 | 盘点任务ID |
| deviceId | String | 是 | 设备ID |
| scanType | Integer | 是 | 扫描类型0=手动盘点1=自动盘点) |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 7. 盘点任务管理接口(/Inventory/task
#### 接口说明
管理盘点任务的增删改查
#### 请求方式
POST/GET/PUT/DELETE
#### 主要功能
- 新增盘点任务
- 查询盘点任务列表
- 修改盘点任务
- 删除盘点任务
- 导出盘点任务
## WCS系统开发工作内容
### 1. 接口开发工作
#### 1.1 入库/上架接口开发
- **工作内容**:开发 `/API/Ruku` 接口处理WMS入库任务请求
- **技术实现**
- HTTP POST接口开发
- JSON数据解析
- 业务参数验证
- 任务创建与调度
- 响应格式化
- **预计工时**16小时
#### 1.2 出库/下架接口开发
- **工作内容**:开发 `/API/Chuku` 接口处理WMS出库任务请求
- **技术实现**
- HTTP POST接口开发
- JSON数据解析
- 业务参数验证
- 任务创建与调度
- 响应格式化
- **预计工时**16小时
#### 1.3 任务状态回调接口开发
- **工作内容**实现WCS任务状态回调机制
- **技术实现**
- 状态变更触发器
- HTTP回调请求
- 状态同步机制
- **预计工时**24小时
### 2. 业务逻辑开发工作
#### 2.1 货物上架逻辑实现
- **工作内容**:实现完整的货物上架业务流程
- **技术实现**
- 库位分配算法
- 设备控制指令生成
- 执行状态跟踪
- 异常处理机制
- **预计工时**32小时
#### 2.2 货物下架逻辑实现
- **工作内容**:实现完整的货物下架业务流程
- **技术实现**
- 货物定位算法
- 设备控制指令生成
- 执行状态跟踪
- 异常处理机制
- **预计工时**32小时
#### 2.3 任务调度与排队机制
- **工作内容**:实现多任务排队调度算法
- **技术实现**
- 任务队列管理
- 优先级调度算法
- 设备资源分配
- 任务冲突解决
- **预计工时**24小时
### 3. 系统集成开发工作
#### 3.1 与WMS系统接口对接
- **工作内容**确保WCS与WMS系统稳定通信
- **技术实现**
- 接口协议实现
- 数据格式转换
- 通信安全机制
- 错误重试机制
- **预计工时**20小时
#### 3.2 与AGV系统协调机制
- **工作内容**实现WCS与AGV系统的任务协调
- **技术实现**
- 协调接口开发
- 状态同步机制
- 任务交接处理
- **预计工时**16小时
### 4. 数据管理开发工作
#### 4.1 任务数据存储与管理
- **工作内容**:开发任务数据的存储和管理功能
- **技术实现**
- 数据库表设计
- 数据访问层开发
- 数据一致性保证
- 数据清理机制
- **预计工时**20小时
#### 4.2 库位状态数据维护
- **工作内容**:实现库位状态的实时维护
- **技术实现**
- 库位状态表设计
- 状态变更处理
- 数据同步机制
- 状态查询接口
- **预计工时**16小时
### 5. 监控与维护开发工作
#### 5.1 系统运行状态监控
- **工作内容**:开发系统运行状态监控功能
- **技术实现**
- 监控指标定义
- 监控接口开发
- 异常告警机制
- **预计工时**12小时
#### 5.2 异常处理与恢复机制
- **工作内容**:开发完善的异常处理和任务恢复机制
- **技术实现**
- 异常类型定义
- 异常处理策略
- 任务恢复机制
- 日志记录系统
- **预计工时**20小时
## Inventory系统开发工作内容
### 1. 设备接口开发工作
#### 1.1 RFID设备连接接口开发
- **工作内容**开发RFID设备连接、断开、状态查询接口
- **技术实现**
- TCP连接管理
- 设备状态跟踪
- 连接池管理
- 异常处理机制
- **预计工时**24小时
#### 1.2 盘点控制接口开发
- **工作内容**:开发开始盘点、停止盘点等控制接口
- **技术实现**
- 设备控制指令发送
- 扫描状态管理
- 线程安全控制
- **预计工时**16小时
### 2. 数据处理开发工作
#### 2.1 扫描数据处理开发
- **工作内容**处理RFID设备扫描的标签数据
- **技术实现**
- 实时数据接收
- WebSocket通信
- 数据格式化处理
- 数据存储
- **预计工时**28小时
#### 2.2 数据匹配算法开发
- **工作内容**:开发扫描数据与库存数据的匹配算法
- **技术实现**
- 匹配算法设计
- 数据对比逻辑
- 状态标识处理
- 统计计算
- **预计工时**32小时
### 3. 任务管理开发工作
#### 3.1 盘点任务管理开发
- **工作内容**:开发盘点任务的增删改查功能
- **技术实现**
- 任务数据模型设计
- 任务状态管理
- 任务分配逻辑
- 任务进度跟踪
- **预计工时**24小时
#### 3.2 报告生成开发
- **工作内容**:开发盘点报告生成和统计功能
- **技术实现**
- 数据统计算法
- 图表生成
- 报告导出功能
- 历史数据查询
- **预计工时**20小时
### 4. 系统集成开发工作
#### 4.1 与WMS系统集成
- **工作内容**实现Inventory系统与WMS系统的数据同步
- **技术实现**
- 库存数据接口
- 数据同步机制
- 冲突处理策略
- **预计工时**16小时
#### 4.2 WebSocket通信开发
- **工作内容**:实现实时数据传输功能
- **技术实现**
- WebSocket服务端开发
- 设备标识管理
- 消息推送机制
- **预计工时**20小时
## 系统对接流程图
### WCS系统对接流程
```mermaid
graph TD
A[WMS创建任务] --> B{判断任务类型}
B -->|入库/上架| C[WMS调用WCS /API/Ruku接口]
B -->|出库/下架| D[WMS调用WCS /API/Chuku接口]
C --> E[WCS接收任务请求]
D --> E
E --> F[WCS验证任务参数]
F --> G{参数验证结果}
G -->|验证失败| H[WCS返回错误信息给WMS]
G -->|验证成功| I[WCS创建内部任务]
I --> J[WCS控制立体库设备执行任务]
J --> K[设备执行中...]
K --> L{任务执行结果}
L -->|执行成功| M[WCS更新任务状态]
L -->|执行失败| N[WCS记录异常并重试]
M --> O[WCS回调WMS状态更新]
N --> P{重试次数达到上限}
P -->|是| Q[WCS回调WMS失败状态]
P -->|否| J
O --> R[WMS接收状态更新]
Q --> R
H --> R
R --> S{是否需要AGV配合}
S -->|是| T[WMS调度AGV]
S -->|否| U[任务完成]
T --> U
```
### Inventory系统工作流程
```mermaid
graph TD
A[创建盘点任务] --> B[选择盘点方式]
B -->|自动盘点| C[连接RFID设备]
B -->|手持盘点| D[手动扫描]
C --> E[开始标签扫描]
E --> F[实时接收EPC数据]
F --> G[WebSocket推送数据到前端]
D --> G
G --> H[停止扫描]
H --> I[数据匹配处理]
I --> J[生成匹配结果]
J --> K[统计分析]
K --> L[生成盘点报告]
L --> M[任务完成]
```
## 项目实施计划
### 第一阶段接口开发预计3周
- 完成WCS入库/上架接口开发
- 完成WCS出库/下架接口开发
- 完成Inventory设备管理接口开发
- 完成基础数据模型设计
### 第二阶段业务逻辑开发预计4周
- 完成WCS货物上架逻辑开发
- 完成WCS货物下架逻辑开发
- 完成WCS任务调度机制开发
- 完成Inventory数据处理逻辑开发
- 完成盘点匹配算法开发
### 第三阶段系统集成预计3周
- 完成WCS与WMS系统对接
- 完成WCS与AGV系统协调
- 完成Inventory与WMS系统集成
- 完成WebSocket通信功能
- 完成监控功能开发
### 第四阶段测试与优化预计2周
- 系统集成测试
- 性能优化
- 异常处理完善
- 用户验收测试
## 项目交付物
1. **技术文档**
- WCS系统接口规范文档
- Inventory系统接口规范文档
- 部署手册
- 运维手册
- 用户操作手册
2. **软件系统**
- WCS系统核心程序
- Inventory系统核心程序
- 数据库脚本
- 配置文件
3. **测试报告**
- 单元测试报告
- 集成测试报告
- 性能测试报告
- 用户验收测试报告
## 项目价值体现
### 1. 技术价值
- 提供标准化接口,实现多系统间无缝对接
- 实现复杂的任务调度算法
- 确保系统高可用性和稳定性
- 实现自动化的盘点功能
### 2. 业务价值
- 实现仓库作业自动化
- 提高仓储效率和准确性
- 降低人工成本
- 实现库存精确管理
### 3. 服务价值
- 专业的技术开发服务
- 完善的系统集成方案
- 持续的技术支持服务
- 完整的仓储解决方案
## 风险与应对
### 1. 技术风险
- **风险**:接口兼容性问题
- **应对**:提前进行接口规范确认
### 2. 集成风险
- **风险**:多系统集成复杂度高
- **应对**:分阶段集成测试
### 3. 性能风险
- **风险**:高并发场景下系统性能
- **应对**:性能测试与优化
### 4. 设备风险
- **风险**RFID设备连接稳定性
- **应对**:设备连接监控和异常处理
## 服务收费标准
### WCS系统开发服务
#### 1. 接口开发服务40小时
- 入库/上架接口16小时
- 出库/下架接口16小时
- 任务状态回调接口8小时
#### 2. 业务逻辑开发88小时
- 货物上架逻辑32小时
- 货物下架逻辑32小时
- 任务调度机制24小时
#### 3. 系统集成服务36小时
- 与WMS系统对接20小时
- 与AGV系统协调16小时
#### 4. 数据管理开发36小时
- 任务数据管理20小时
- 库位状态维护16小时
#### 5. 监控维护开发32小时
- 系统监控12小时
- 异常处理机制20小时
### Inventory系统开发服务
#### 1. 设备接口开发40小时
- RFID设备连接接口24小时
- 盘点控制接口16小时
#### 2. 数据处理开发60小时
- 扫描数据处理28小时
- 数据匹配算法32小时
#### 3. 任务管理开发44小时
- 盘点任务管理24小时
- 报告生成20小时
#### 4. 系统集成开发36小时
- 与WMS系统集成16小时
- WebSocket通信20小时
**总计开发工时392小时**

View File

@@ -0,0 +1,79 @@
# 智慧实物管理系统安全功能审查报告
## 1. 身份鉴别功能 (Authentication)
### 审查结果:
**已实现** - 系统具备完善的身份鉴别功能
### 详细说明:
- **JWT Token机制**使用JWT令牌进行身份验证支持令牌自动刷新
- **登录验证**:通过`SysLoginService`实现用户登录验证,包含用户名密码校验、验证码校验
- **密码安全**:使用`BCryptPasswordEncoder`对密码进行加密存储
- **登录限制**支持登录IP黑名单、错误次数限制默认5次和账户锁定功能默认10分钟
- **登录日志**记录登录IP、时间、地点、浏览器等信息到`sys_logininfor`
- **多因子验证**:支持验证码验证,支持数学计算和字符验证两种类型
## 2. 安全标记功能 (Security Labeling)
### 审查结果:
**已实现** - 系统具备安全标记功能
### 详细说明:
- **角色权限标记**:通过`sys_role`表定义角色,每个角色分配特定权限
- **用户角色映射**:通过`sys_user_role`表建立用户与角色的关联关系
- **菜单权限标记**:通过`sys_role_menu`表为角色分配菜单权限
- **数据权限标记**通过数据范围控制data_scope实现数据级别的安全标记
- **操作权限标记**:通过`@PreAuthorize("@ss.hasPermi('module:action:operation')")`注解标记接口权限
## 3. 应用权限控制功能 (Access Control)
### 审查结果:
**已实现** - 系统具备完善的权限控制功能
### 详细说明:
- **细粒度权限控制**:使用`@PreAuthorize`注解实现方法级别的权限控制
- **权限表达式**
- `@ss.hasPermi('module:action:operation')` - 检查特定权限
- `@ss.hasRole('roleName')` - 检查角色权限
- **前端权限控制**:使用`v-hasPermi`指令实现前端按钮级权限控制
- **菜单权限控制**:根据用户权限动态显示菜单
- **数据权限控制**:支持部门数据权限过滤
- **权限继承机制**:角色权限通过菜单权限体系继承
- **权限缓存**用户权限信息存储在Redis中支持动态刷新
## 4. 安全审计功能 (Security Audit)
### 审查结果:
**已实现** - 系统具备全面的安全审计功能
### 详细说明:
- **操作日志审计**:使用`@Log`注解记录用户操作日志
- **日志存储**
- 操作日志存储在`sys_oper_log`
- 登录日志存储在`sys_logininfor`
- 任务日志存储在`sys_job_log`
- **审计内容**
- 操作用户、操作时间、操作IP、操作地点
- 请求方法、请求参数、返回结果
- 操作状态(成功/失败)、错误信息
- 执行耗时等详细信息
- **日志分类**支持不同级别的日志记录info, error, user等
- **日志管理**:提供日志查询、删除、导出等管理功能
- **异步记录**:使用异步机制记录日志,避免影响主业务流程
## 总体评估
### 优点:
1. **安全架构完整**:身份鉴别、权限控制、安全审计三大功能模块齐全
2. **技术实现成熟**基于Spring Security框架使用JWT令牌机制
3. **权限控制细粒度**:支持角色、菜单、数据等多个层面的权限控制
4. **审计功能全面**:涵盖登录、操作、任务等多维度审计
5. **代码规范性好**:使用注解方式实现安全控制,代码简洁清晰
### 建议改进:
1. **加强密码策略**:可增加更复杂的密码强度要求
2. **安全配置优化**:建议对敏感配置项进行加密存储
3. **日志分析**:可考虑增加安全日志的智能分析功能
### 结论:
该系统完全具备身份鉴别、安全标记、应用权限控制和安全审计四大安全功能符合企业级应用的安全要求。系统基于成熟的RuoYi框架开发在安全功能方面做了充分的实现和优化。

View File

@@ -0,0 +1,355 @@
# 盘点系统业务对接文档
## 项目概述
### 项目背景
盘点系统是用于实现仓库库存自动盘点的系统通过RFID设备自动采集货品信息并与系统库存数据进行比对以实现库存的精确管理。
### 项目目标
- 实现盘点任务的创建和管理
- 通过RFID设备自动采集货品标签信息
- 与系统库存数据进行比对分析
- 生成盘点结果报告
## 盘点系统业务流程
### 1. 任务创建阶段
- **业务内容**:在系统中创建盘点任务,指定盘点范围(仓库、区域、货品类别等)
- **数据准备**:系统获取当前库存数据作为基准数据
- **任务分配**将盘点任务分配给指定的RFID设备
### 2. 设备执行阶段
- **设备连接**RFID设备连接到系统
- **任务下发**系统将盘点任务下发到RFID设备
- **标签采集**RFID设备在指定区域扫描采集货品标签信息
- **数据传输**:将采集到的标签数据实时传输回系统
### 3. 结果采集阶段
- **数据收集**系统收集从RFID设备传回的标签数据
- **数据验证**:验证数据完整性和准确性
- **暂存处理**:将采集到的数据暂存到临时表
### 4. 结果匹配阶段
- **数据比对**:将采集到的标签数据与系统库存数据进行比对
- **状态标识**
- 正常:系统中有记录,且实物存在(标签被扫描到)
- 盘亏:系统中有记录,但实物不存在(标签未被扫描到)
- 盘盈:系统中无记录,但实物存在(标签被扫描到但无对应库存)
- **差异分析**:统计盘点差异情况
### 5. 结果输出阶段
- **报告生成**:生成盘点结果报告,包括正常、盘亏、盘盈等统计
- **结果展示**:通过图表和列表展示盘点结果
- **异常处理**:对盘点异常情况进行标注和处理
- **任务完成**:标记盘点任务为完成状态
## 合作方需要提供的信息
### 1. RFID设备技术信息
- 设备型号和规格
- 网络连接方式IP地址、端口
- 通信协议类型
- 设备API接口文档
- 设备认证和安全机制
### 2. 设备集成接口
- 设备连接接口TCP/UDP/HTTP等
- 标签数据获取接口
- 设备状态查询接口
- 设备控制接口(开始/停止扫描等)
### 3. 数据格式规范
- 标签数据格式
- 数据传输格式JSON/XML等
- 字符编码方式
- 数据字段定义
## 我方执行流程
### 1. 接口对接阶段
- **技术对接**根据合作方提供的API文档开发与RFID设备的接口
- **连接测试**:测试设备连接功能,确保能够正常建立连接
- **数据传输测试**:测试标签数据的获取和传输功能
### 2. 任务管理实现
- **任务创建**:开发盘点任务管理模块,支持任务的创建、分配、状态管理
- **设备绑定**实现盘点任务与RFID设备的绑定关系
- **权限控制**:确保任务的安全性和完整性
### 3. 数据处理实现
- **实时接收**:实现标签数据的实时接收和处理机制
- **WebSocket通信**通过WebSocket将采集到的标签数据实时推送到前端
- **数据存储**:将采集到的数据存储到系统中
### 4. 匹配算法实现
- **数据比对**:开发扫描数据与库存数据的匹配算法
- **差异计算**:计算盘点差异,标识盘盈、盘亏、正常等状态
- **统计分析**:生成盘点统计报告和图表
### 5. 结果展示实现
- **结果展示**:开发盘点结果的展示界面
- **报表生成**:实现盘点报告的生成和导出功能
- **异常处理**:处理盘点过程中的异常情况
## 对外接口规范
### 1. 设备连接接口(/AutoInventory/connect
#### 接口说明
建立RFID设备连接
#### 请求方式
POST
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
| ip | String | 是 | 设备IP地址 |
| port | Integer | 是 | 设备端口号 |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 2. 开始盘点接口(/AutoInventory/scan
#### 接口说明
启动RFID设备进行标签扫描
#### 请求方式
GET
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 3. 停止盘点接口(/AutoInventory/stop
#### 接口说明
停止RFID设备扫描
#### 请求方式
GET
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 4. 断开连接接口(/AutoInventory/disconnect
#### 接口说明
断开RFID设备连接
#### 请求方式
GET
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 5. 设备状态查询接口(/AutoInventory/status
#### 接口说明
查询RFID设备连接状态
#### 请求方式
GET
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| deviceId | String | 是 | 设备ID |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息(包含设备连接状态) |
### 6. 开始匹配接口(/AutoInventory/match
#### 接口说明
将扫描数据与系统库存数据进行匹配
#### 请求方式
POST
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| taskId | String | 是 | 盘点任务ID |
| deviceId | String | 是 | 设备ID |
| scanType | Integer | 是 | 扫描类型0=手动盘点1=自动盘点) |
#### 响应参数
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | Integer | 响应码200表示成功 |
| msg | String | 响应消息 |
### 7. 盘点任务管理接口(/Inventory/task
#### 接口说明
管理盘点任务的增删改查
#### 请求方式
POST/GET/PUT/DELETE
#### 主要功能
- 新增盘点任务
- 查询盘点任务列表
- 修改盘点任务
- 删除盘点任务
- 导出盘点任务
## 系统工作流程
```mermaid
graph TD
A[创建盘点任务] --> B[RFID设备连接]
B --> C[下发盘点任务到设备]
C --> D[设备开始标签扫描]
D --> E[实时收集标签数据]
E --> F{是否完成扫描?}
F -->|是| G[停止扫描]
F -->|否| D
G --> H[数据比对分析]
H --> I[生成盘点结果]
I --> J[输出盘点报告]
J --> K[任务完成]
```
## 系统开发工作内容
### 1. 设备接口开发工作
#### 1.1 RFID设备连接接口开发
- **工作内容**开发RFID设备连接、断开、状态查询接口
- **技术实现**
- TCP连接管理
- 设备状态跟踪
- 连接池管理
- 异常处理机制
- **预计工时**24小时
#### 1.2 盘点控制接口开发
- **工作内容**:开发开始盘点、停止盘点等控制接口
- **技术实现**
- 设备控制指令发送
- 扫描状态管理
- 线程安全控制
- **预计工时**16小时
### 2. 数据处理开发工作
#### 2.1 扫描数据处理开发
- **工作内容**处理RFID设备扫描的标签数据
- **技术实现**
- 实时数据接收
- WebSocket通信
- 数据格式化处理
- 数据存储
- **预计工时**28小时
#### 2.2 数据匹配算法开发
- **工作内容**:开发扫描数据与库存数据的匹配算法
- **技术实现**
- 匹配算法设计
- 数据对比逻辑
- 状态标识处理
- 统计计算
- **预计工时**32小时
### 3. 任务管理开发工作
#### 3.1 盘点任务管理开发
- **工作内容**:开发盘点任务的增删改查功能
- **技术实现**
- 任务数据模型设计
- 任务状态管理
- 任务分配逻辑
- 任务进度跟踪
- **预计工时**24小时
#### 3.2 报告生成开发
- **工作内容**:开发盘点报告生成和统计功能
- **技术实现**
- 数据统计算法
- 图表生成
- 报告导出功能
- 历史数据查询
- **预计工时**20小时
### 4. 系统集成开发工作
#### 4.1 WebSocket通信开发
- **工作内容**:实现实时数据传输功能
- **技术实现**
- WebSocket服务端开发
- 设备标识管理
- 消息推送机制
- **预计工时**20小时
## 项目交付物
1. **技术文档**
- 盘点系统接口规范文档
- 部署手册
- 运维手册
- 用户操作手册
2. **软件系统**
- 盘点系统核心程序
- 数据库脚本
- 配置文件
3. **测试报告**
- 单元测试报告
- 集成测试报告
- 性能测试报告
- 用户验收测试报告
## 服务收费标准
### 盘点系统开发服务
#### 1. 设备接口开发40小时
- RFID设备连接接口24小时
- 盘点控制接口16小时
#### 2. 数据处理开发60小时
- 扫描数据处理28小时
- 数据匹配算法32小时
#### 3. 任务管理开发44小时
- 盘点任务管理24小时
- 报告生成20小时
#### 4. 系统集成开发20小时
- WebSocket通信20小时
**总计开发工时164小时**

View File

@@ -0,0 +1,318 @@
# 调度系统与盘点系统业务对接文档
## 调度系统业务描述
### 项目背景
调度系统是用于实现仓库自动化作业的核心系统通过与WCS仓库控制系统和AGV自动导引车系统的协作实现货物的自动化入库、出库、移库等操作。
### 项目目标
- 实现与WCS系统的无缝对接
- 实现与AGV系统的协调作业
- 提供标准化接口,确保系统间稳定运行
- 实现出入库、移库等核心业务流程
### 核心功能
#### 1. 入库/上架功能
- 接收WMS系统的入库任务
- 控制立体库设备执行上架操作
- 实时反馈任务执行状态给WMS系统
#### 2. 出库/下架功能
- 接收WMS系统的出库任务
- 控制立体库设备执行下架操作
- 实时反馈任务执行状态给WMS系统
#### 3. 任务调度功能
- 任务队列管理
- 任务优先级调度
- 设备资源分配
### 接口列表
- 入库接口(/API/Ruku
- 出库接口(/API/Chuku
- 任务状态回调接口
### 调度系统开发工作内容
#### 1. 接口开发工作
- **入库/上架接口开发**实现与WCS系统的入库任务下发预计16小时
- **出库/下架接口开发**实现与WCS系统的出库任务下发预计16小时
- **任务状态回调接口开发**实现任务状态反馈机制预计24小时
#### 2. 业务逻辑开发工作
- **货物上架逻辑实现**实现完整的货物上架业务流程预计32小时
- **货物下架逻辑实现**实现完整的货物下架业务流程预计32小时
- **任务调度与排队机制**实现多任务排队调度算法预计24小时
#### 3. 系统集成开发工作
- **与WMS系统接口对接**确保调度系统与WMS系统稳定通信预计20小时
- **与AGV系统协调机制**实现调度系统与AGV系统的任务协调预计16小时
---
## 盘点系统业务描述
### 项目背景
盘点系统是用于实现仓库库存自动盘点的系统通过RFID设备自动采集货品信息并与系统库存数据进行比对以实现库存的精确管理。
### 项目目标
- 实现盘点任务的创建和管理
- 通过RFID设备自动采集货品标签信息
- 与系统库存数据进行比对分析
- 生成盘点结果报告
### 核心功能
#### 1. 盘点任务管理
- 创建盘点任务设置任务名称、仓库ID、场景ID、执行人、完成时间等
- 任务类型手持盘点0和自动盘点1
- 任务状态待执行0、已完成1、已超时2
#### 2. 自动盘点功能
- 设备连接管理通过RFID设备IP和端口建立TCP连接
- 标签扫描启动RFID设备进行标签扫描
- 数据传输通过WebSocket将扫描到的EPC标签数据发送给前端
- 扫描控制:支持开始、停止、断开连接等操作
#### 3. 数据匹配功能
- 将扫描数据与系统库存数据进行匹配
- 生成匹配结果(正常、未扫到、误扫)
- 统计盘点结果并生成图表
#### 4. 报告管理功能
- 生成盘点统计图表
- 导出盘点报告
- 提供历史盘点记录查询
### 盘点任务创建详细流程
#### 1. 任务规划阶段
- 确定盘点范围(指定仓库、库区、货位等)
- 确定盘点类型(全盘、抽盘、专项盘点等)
- 确定盘点时间安排
- 分配盘点人员
#### 2. 基础数据准备
- 获取指定范围内的库存数据作为基准
- 验证库存数据完整性
- 生成任务清单
#### 3. 任务创建阶段
- 在系统中创建盘点任务记录
- 设置任务基本信息(名称、仓库、时间等)
- 绑定盘点设备(如适用)
- 分配执行人员
#### 4. 任务下发阶段
- 将任务信息同步到相关设备或人员
- 准备盘点所需的辅助数据
- 启动任务状态监控
### 接口列表
- 设备连接接口(/AutoInventory/connect
- 开始盘点接口(/AutoInventory/scan
- 停止盘点接口(/AutoInventory/stop
- 断开连接接口(/AutoInventory/disconnect
- 设备状态查询接口(/AutoInventory/status
- 开始匹配接口(/AutoInventory/match
- 盘点任务管理接口(/Inventory/task
### 盘点系统开发工作内容
#### 1. 设备接口开发工作
- **RFID设备连接接口开发**开发RFID设备连接、断开、状态查询接口预计24小时
- **盘点控制接口开发**开发开始盘点、停止盘点等控制接口预计16小时
#### 2. 数据处理开发工作
- **扫描数据处理开发**处理RFID设备扫描的标签数据预计28小时
- **数据匹配算法开发**开发扫描数据与库存数据的匹配算法预计32小时
#### 3. 任务管理开发工作
- **盘点任务管理开发**开发盘点任务的增删改查功能预计24小时
- **报告生成开发**开发盘点报告生成和统计功能预计20小时
#### 4. 系统集成开发工作
- **WebSocket通信开发**实现实时数据传输功能预计20小时
---
## 系统与设备对接流程
### 调度系统设备对接流程
#### 1. 我方提供服务
- **任务调度服务**:根据业务需求生成调度任务
- **接口服务**提供标准化的HTTP接口供WCS和AGV系统调用
- **状态监控服务**:实时监控任务执行状态
- **协调控制服务**协调WCS和AGV系统的任务执行顺序
#### 2. WCS系统对接要求
- **接口调用**WCS系统需支持我方提供的入库/出库接口调用
- **数据格式**WCS系统需按照我方定义的数据格式进行数据交互
- **状态反馈**WCS系统需通过回调接口实时反馈任务执行状态
- **异常处理**WCS系统需支持异常情况的处理和重试机制
#### 3. AGV系统对接要求
- **接口调用**AGV系统需支持我方提供的搬运任务接口调用
- **数据格式**AGV系统需按照我方定义的数据格式进行数据交互
- **状态反馈**AGV系统需实时反馈任务执行状态
- **任务协调**AGV系统需与WCS系统任务进行协调执行
#### 4. 对接执行流程
- **任务生成**WMS系统创建任务后通过接口下发到调度系统
- **任务分发**调度系统根据任务类型将任务分发给WCS或AGV系统
- **执行监控**实时监控WCS和AGV系统的任务执行状态
- **状态同步**WCS和AGV系统通过回调接口同步任务执行状态
- **完成确认**任务完成后调度系统更新任务状态并通知WMS系统
#### 5. 执行流程
```mermaid
graph TD
A[WMS创建任务] --> B{判断任务类型}
B -->|入库/上架| C[WMS调用WCS /API/Ruku接口]
B -->|出库/下架| D[WMS调用WCS /API/Chuku接口]
C --> E[WCS接收任务请求]
D --> E
E --> F[WCS验证任务参数]
F --> G{参数验证结果}
G -->|验证失败| H[WCS返回错误信息给WMS]
G -->|验证成功| I[WCS创建内部任务]
I --> J[WCS控制立体库设备执行任务]
J --> K[设备执行中...]
K --> L{任务执行结果}
L -->|执行成功| M[WCS更新任务状态]
L -->|执行失败| N[WCS记录异常并重试]
M --> O[WCS回调WMS状态更新]
N --> P{重试次数达到上限}
P -->|是| Q[WCS回调WMS失败状态]
P -->|否| J
O --> R[WMS接收状态更新]
Q --> R
H --> R
R --> S{是否需要AGV配合}
S -->|是| T[WMS调度AGV]
S -->|否| U[任务完成]
T --> U
```
### 盘点系统设备对接流程
#### 1. 我方提供服务
- **设备管理服务**:提供设备连接、状态监控、任务下发等服务
- **数据处理服务**:实时接收设备数据,进行格式转换和处理
- **WebSocket通信服务**:提供实时数据传输通道
- **数据匹配服务**:将采集数据与库存数据进行比对分析
#### 2. 第三方设备对接要求
- **网络连接**设备需支持TCP/IP协议能够与我方系统建立稳定连接
- **数据格式**:设备需按照我方定义的数据格式传输标签信息
- **接口调用**:设备需支持我方提供的控制接口(开始/停止扫描等)
- **心跳机制**:设备需定期向我方系统发送心跳包,确保连接状态
#### 3. 对接执行流程
- **连接建立**设备通过TCP/IP连接到我方系统建立通信链路
- **设备注册**设备向我方系统注册获取设备ID和认证信息
- **任务获取**:设备从我方系统获取当前盘点任务信息
- **数据采集**:设备开始扫描,将采集到的标签数据实时传输给我方系统
- **状态同步**:设备定期向我方系统同步工作状态
- **任务完成**:设备完成任务后,向我方系统报告完成状态
#### 4. 执行流程
```mermaid
graph TD
A[创建盘点任务] --> B[RFID设备连接]
B --> C[下发盘点任务到设备]
C --> D[设备开始标签扫描]
D --> E[实时收集标签数据]
E --> F{是否完成扫描?}
F -->|是| G[停止扫描]
F -->|否| D
G --> H[数据比对分析]
H --> I[生成盘点结果]
I --> J[输出盘点报告]
J --> K[任务完成]
```
## 项目交付物
### 调度系统
1. **技术文档**
- 调度系统接口规范文档
- 部署手册
- 运维手册
- 用户操作手册
2. **软件系统**
- 调度系统核心程序
- 数据库脚本
- 配置文件
3. **测试报告**
- 单元测试报告
- 集成测试报告
- 性能测试报告
- 用户验收测试报告
### 盘点系统
1. **技术文档**
- 盘点系统接口规范文档
- 部署手册
- 运维手册
- 用户操作手册
2. **软件系统**
- 盘点系统核心程序
- 数据库脚本
- 配置文件
3. **测试报告**
- 单元测试报告
- 集成测试报告
- 性能测试报告
- 用户验收测试报告
## 服务收费标准
### 调度系统开发服务
#### 1. 接口开发服务56小时
- 入库/上架接口16小时
- 出库/下架接口16小时
- 任务状态回调接口24小时
#### 2. 业务逻辑开发88小时
- 货物上架逻辑32小时
- 货物下架逻辑32小时
- 任务调度机制24小时
#### 3. 系统集成服务36小时
- 与WMS系统对接20小时
- 与AGV系统协调16小时
### 盘点系统开发服务
#### 1. 设备接口开发40小时
- RFID设备连接接口24小时
- 盘点控制接口16小时
#### 2. 数据处理开发60小时
- 扫描数据处理28小时
- 数据匹配算法32小时
#### 3. 任务管理开发44小时
- 盘点任务管理24小时
- 报告生成20小时
#### 4. 系统集成开发20小时
- WebSocket通信20小时
**调度系统总计180小时**
**盘点系统总计164小时**
**项目总计344小时**

View File

@@ -0,0 +1,362 @@
# 调度系统与盘点系统开发文档
## 1. 项目概述
### 1.1 项目背景
调度系统是用于实现仓库自动化作业的核心系统通过与WCS仓库控制系统和AGV自动导引车系统的协作实现货物的自动化入库、出库、移库等操作。
盘点系统是用于实现仓库库存自动盘点的系统通过RFID设备自动采集货品信息并与系统库存数据进行比对以实现库存的精确管理。
### 1.2 项目目标
- 实现调度系统与WCS、AGV系统间的无缝对接
- 实现盘点系统与RFID设备的高效协作
- 提供标准化接口,确保各系统间稳定运行
- 实现出入库、盘点等核心业务流程
## 2. 调度系统
### 2.1 系统架构
调度系统作为中间层负责协调WMS、WCS、AGV三个系统间的任务流转和状态同步。
### 2.2 业务流程描述
#### 2.2.1 入库/上架流程
1. **任务创建**WMS系统创建入库任务
2. **任务分发**调度系统将任务分发给WCS系统
3. **设备执行**WCS系统控制立体库设备执行上架操作
4. **状态反馈**WCS系统实时反馈任务执行状态
5. **完成确认**:任务完成后更新状态
#### 2.2.2 出库/下架流程
1. **任务创建**WMS系统创建出库任务
2. **任务分发**调度系统将任务分发给WCS系统
3. **设备执行**WCS系统控制立体库设备执行下架操作
4. **AGV配合**根据需要调度AGV进行货物搬运
5. **状态反馈**WCS/AGV系统实时反馈任务执行状态
6. **完成确认**:任务完成后更新状态
#### 2.2.3 移库流程
1. **任务创建**WMS系统创建移库任务
2. **AGV调度**调度系统先调度AGV搬运货物
3. **WCS配合**根据需要调度WCS进行货物存放
4. **状态监控**:实时监控任务执行状态
5. **完成确认**:任务完成后更新状态
### 2.3 核心功能
#### 2.3.1 入库/上架功能
- 接收WMS系统的入库任务
- 控制立体库设备执行上架操作
- 实时反馈任务执行状态给WMS系统
#### 2.3.2 出库/下架功能
- 接收WMS系统的出库任务
- 控制立体库设备执行下架操作
- 实时反馈任务执行状态给WMS系统
#### 2.3.3 任务调度功能
- 任务队列管理
- 任务优先级调度
- 设备资源分配
### 2.4 业务流程图
```mermaid
graph TD
A[WMS创建任务] --> B{判断任务类型}
B -->|入库/上架| C[WMS调用WCS /API/Ruku接口]
B -->|出库/下架| D[WMS调用WCS /API/Chuku接口]
C --> E[WCS接收任务请求]
D --> E
E --> F[WCS验证任务参数]
F --> G{参数验证结果}
G -->|验证失败| H[WCS返回错误信息给WMS]
G -->|验证成功| I[WCS创建内部任务]
I --> J[WCS控制立体库设备执行任务]
J --> K[设备执行中...]
K --> L{任务执行结果}
L -->|执行成功| M[WCS更新任务状态]
L -->|执行失败| N[WCS记录异常并重试]
M --> O[WCS回调WMS状态更新]
N --> P{重试次数达到上限}
P -->|是| Q[WCS回调WMS失败状态]
P -->|否| J
O --> R[WMS接收状态更新]
Q --> R
H --> R
R --> S{是否需要AGV配合}
S -->|是| T[WMS调度AGV]
S -->|否| U[任务完成]
T --> U
```
### 2.5 接口规范
#### 2.5.1 入库接口(/API/Ruku
- **功能说明**WMS系统调用此接口创建入库/上架任务
- **请求方式**POST
- **我方服务地址**http://[IP_ADDR]:[PORT]/API/Ruku
- **第三方调用**WCS系统需实现此接口并接受调用
#### 2.5.2 出库接口(/API/Chuku
- **功能说明**WMS系统调用此接口创建出库/下架任务
- **请求方式**POST
- **我方服务地址**http://[IP_ADDR]:[PORT]/API/Chuku
- **第三方调用**WCS系统需实现此接口并接受调用
#### 2.5.3 任务状态回调接口
- **功能说明**WCS/AGV系统回调任务执行状态
- **请求方式**POST
- **我方服务地址**http://[IP_ADDR]:[PORT]/wisdom/wcs/callback
- **第三方调用**WCS/AGV系统需调用此接口反馈状态
### 2.6 对接流程
#### 2.6.1 WCS系统对接流程
1. **接口实现**WCS系统需实现入库/出库接口
2. **数据格式**:按约定格式接收任务数据
3. **状态反馈**:通过回调接口实时反馈任务状态
4. **异常处理**:处理任务执行中的异常情况
#### 2.6.2 AGV系统对接流程
1. **接口实现**AGV系统需实现搬运任务接口
2. **数据格式**:按约定格式接收任务数据
3. **状态反馈**:实时反馈任务执行状态
4. **任务协调**与WCS系统任务进行协调执行
### 2.7 配置信息
#### 2.7.1 WCS系统配置
```yaml
wcs:
job:
create-url: http://[WCS_IP_ADDR]:[WCS_PORT]/API/Ruku # WCS上架任务接口
chuku-url: http://[WCS_IP_ADDR]:[WCS_PORT]/API/Chuku # WCS出库任务接口
```
#### 2.7.2 AGV系统配置
```yaml
agv:
job:
create-url: http://[AGV_IP_ADDR]:[AGV_PORT]/api/job/create
```
## 3. 盘点系统
### 3.1 系统架构
盘点系统通过RFID设备采集数据与库存数据进行比对生成盘点报告。
### 3.2 业务流程描述
#### 3.2.1 盘点任务创建流程
1. **任务规划阶段**
- 确定盘点范围(指定仓库、库区、货位等)
- 确定盘点类型
- 确定盘点时间安排
- 分配盘点人员
2. **基础数据准备**
- 获取指定范围内的库存数据作为基准
- 验证库存数据完整性
- 生成任务清单
3. **任务创建阶段**
- 在系统中创建盘点任务记录
- 设置任务基本信息(名称、仓库、时间等)
- 绑定盘点设备
- 分配执行人员
4. **任务下发阶段**
- 将任务信息同步到相关设备或人员
- 准备盘点所需的辅助数据
- 启动任务状态监控
#### 3.2.2 盘点执行流程
1. **设备连接**RFID设备连接到系统
2. **任务获取**:设备获取盘点任务信息
3. **标签扫描**RFID设备在指定区域扫描标签
4. **数据传输**:将扫描数据实时传输回系统
5. **状态监控**:监控设备工作状态和任务进度
#### 3.2.3 数据处理流程
1. **数据收集**收集从RFID设备传回的标签数据
2. **数据验证**:验证数据完整性和准确性
3. **数据比对**:将采集数据与库存数据进行比对
4. **差异分析**:分析盘点差异
5. **结果生成**:生成盘点结果报告
### 3.3 核心功能
#### 3.3.1 盘点任务管理
- 创建盘点任务设置任务名称、仓库ID、场景ID、执行人、完成时间等
- 任务类型手持盘点0和自动盘点1
- 任务状态待执行0、已完成1、已超时2
#### 3.3.2 自动盘点功能
- 设备连接管理通过RFID设备IP和端口建立TCP连接
- 标签扫描启动RFID设备进行标签扫描
- 数据传输通过WebSocket将扫描到的EPC标签数据发送给前端
- 扫描控制:支持开始、停止、断开连接等操作
#### 3.3.3 数据匹配功能
- 将扫描数据与系统库存数据进行匹配
- 生成匹配结果(正常、未扫到、误扫)
- 统计盘点结果并生成图表
#### 3.3.4 报告管理功能
- 生成盘点统计图表
- 导出盘点报告
- 提供历史盘点记录查询
### 3.4 业务流程图
```mermaid
graph TD
A[创建盘点任务] --> B[RFID设备连接]
B --> C[下发盘点任务到设备]
C --> D[设备开始标签扫描]
D --> E[实时收集标签数据]
E --> F{是否完成扫描?}
F -->|是| G[停止扫描]
F -->|否| D
G --> H[数据比对分析]
H --> I[生成盘点结果]
I --> J[输出盘点报告]
J --> K[任务完成]
```
### 3.5 接口规范
#### 3.5.1 设备连接接口(/AutoInventory/connect
- **功能说明**建立RFID设备连接
- **请求方式**POST
- **我方服务地址**http://[IP_ADDR]:[PORT]/AutoInventory/connect
- **第三方调用**RFID设备需调用此接口建立连接
#### 3.5.2 开始盘点接口(/AutoInventory/scan
- **功能说明**启动RFID设备进行标签扫描
- **请求方式**GET
- **我方服务地址**http://[IP_ADDR]:[PORT]/AutoInventory/scan
- **第三方调用**RFID设备需调用此接口开始扫描
#### 3.5.3 停止盘点接口(/AutoInventory/stop
- **功能说明**停止RFID设备扫描
- **请求方式**GET
- **我方服务地址**http://[IP_ADDR]:[PORT]/AutoInventory/stop
- **第三方调用**RFID设备需调用此接口停止扫描
#### 3.5.4 断开连接接口(/AutoInventory/disconnect
- **功能说明**断开RFID设备连接
- **请求方式**GET
- **我方服务地址**http://[IP_ADDR]:[PORT]/AutoInventory/disconnect
- **第三方调用**RFID设备需调用此接口断开连接
#### 3.5.5 设备状态查询接口(/AutoInventory/status
- **功能说明**查询RFID设备连接状态
- **请求方式**GET
- **我方服务地址**http://[IP_ADDR]:[PORT]/AutoInventory/status
- **第三方调用**RFID设备需调用此接口查询状态
#### 3.5.6 开始匹配接口(/AutoInventory/match
- **功能说明**:将扫描数据与系统库存数据进行匹配
- **请求方式**POST
- **我方服务地址**http://[IP_ADDR]:[PORT]/AutoInventory/match
- **第三方调用**:系统内部调用
#### 3.5.7 盘点任务管理接口(/Inventory/task
- **功能说明**:管理盘点任务的增删改查
- **请求方式**POST/GET/PUT/DELETE
- **我方服务地址**http://[IP_ADDR]:[PORT]/Inventory/task
- **第三方调用**:系统内部调用
### 3.6 对接流程
#### 3.6.1 RFID设备对接流程
1. **连接建立**设备通过TCP/IP连接到我方系统
2. **设备注册**设备向我方系统注册获取设备ID
3. **任务获取**:设备从我方系统获取当前盘点任务
4. **数据采集**:设备开始扫描,实时传输标签数据
5. **状态同步**:设备定期同步工作状态
6. **任务完成**:设备完成任务后报告完成状态
#### 3.6.2 WebSocket通信
- **连接地址**ws://[IP_ADDR]:[PORT]/websocket
- **数据格式**JSON格式的标签数据
- **心跳机制**:定期发送心跳包保持连接
### 3.7 配置信息
#### 3.7.1 RFID设备配置
```yaml
rfid:
device:
conn-id: [RFID_IP_ADDR]:[RFID_PORT]
```
## 4. 部署说明
### 4.1 环境要求
- Java 8 或更高版本
- Maven 3.6.0 或更高版本
- MySQL 5.7 或更高版本
- Redis 5.0 或更高版本
### 4.2 部署步骤
1. 配置数据库连接信息
2. 配置第三方系统接口地址
3. 启动应用服务
4. 验证接口连通性
### 4.3 配置文件
- application.yml主配置文件
- application-druid.yml数据库配置文件
## 5. 我方开发工作汇总
### 5.1 调度系统开发工作
#### 5.1.1 接口开发
- **入库/上架接口开发**实现与WCS系统的入库任务下发预计16小时
- **出库/下架接口开发**实现与WCS系统的出库任务下发预计16小时
- **任务状态回调接口开发**实现任务状态反馈机制预计24小时
#### 5.1.2 业务逻辑开发
- **货物上架逻辑实现**实现完整的货物上架业务流程预计32小时
- **货物下架逻辑实现**实现完整的货物下架业务流程预计32小时
- **任务调度与排队机制**实现多任务排队调度算法预计24小时
#### 5.1.3 系统集成开发
- **与WMS系统接口对接**确保调度系统与WMS系统稳定通信预计20小时
- **与AGV系统协调机制**实现调度系统与AGV系统的任务协调预计16小时
**调度系统总计180小时**
### 5.2 盘点系统开发工作
#### 5.2.1 设备接口开发
- **RFID设备连接接口开发**开发RFID设备连接、断开、状态查询接口预计24小时
- **盘点控制接口开发**开发开始盘点、停止盘点等控制接口预计16小时
#### 5.2.2 数据处理开发
- **扫描数据处理开发**处理RFID设备扫描的标签数据预计28小时
- **数据匹配算法开发**开发扫描数据与库存数据的匹配算法预计32小时
#### 5.2.3 任务管理开发
- **盘点任务管理开发**开发盘点任务的增删改查功能预计24小时
- **报告生成开发**开发盘点报告生成和统计功能预计20小时
#### 5.2.4 系统集成开发
- **WebSocket通信开发**实现实时数据传输功能预计20小时
**盘点系统总计164小时**
### 5.3 项目总计
- **调度系统开发**180小时
- **盘点系统开发**164小时
- **项目总计**344小时