1.0版本提交
This commit is contained in:
parent
54045a2fb4
commit
ad9ee93500
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.idea/
|
||||
**/.idea/
|
||||
*.iml
|
||||
.vscode/
|
||||
wms_log/
|
||||
5
.idea/.gitignore
vendored
5
.idea/.gitignore
vendored
|
|
@ -1,5 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Environment-dependent path to Maven home directory
|
||||
/mavenHomeManager.xml
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/202504-Wms-MengYang.iml" filepath="$PROJECT_DIR$/.idea/202504-Wms-MengYang.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/202504-Wms-MengYang-box" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/202504-Wms-MengYang-tp" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
5
202504-Wms-MengYang-box/.idea/.gitignore
vendored
5
202504-Wms-MengYang-box/.idea/.gitignore
vendored
|
|
@ -1,5 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Environment-dependent path to Maven home directory
|
||||
/mavenHomeManager.xml
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/202504-Wms-MengYang-box.iml" filepath="$PROJECT_DIR$/.idea/202504-Wms-MengYang-box.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CommonStatePersistent">
|
||||
<option name="searchCache" value="Vechile" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CoolRequestCommonStatePersistent">
|
||||
<option name="searchCache" value="TAPPTaskBak" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CoolRequestSetting">
|
||||
<option name="serializePaths">
|
||||
<list>
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\0731597f11a84ef9a829b9c437031693" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\c2da60b5bb4f438da6ff954a1346b32a" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\85ec0988f8bb450badbde0c5045e6f4f" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\61490adb4d49462aaa40afbbac8699e6" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\76cdc0dbab984b13a97a0db9a3df6095" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\36536ff461cd40c988172b846eb25446" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\b6d54e66c7284e47989ca35b263db167" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\2be9aef4c51247b89ce2e1cd4b2df4fc" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\b3cc1afd501342d99c561026bce48d76" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\8fae6093623c4ac5a1c0365a4ded5536" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\acedef38ef5940a598c4ffe04e50c401" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\7ade37455d3e4d0ab3491e3a869f61f5" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\d15666989172454c805e3b2272e04141" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\d1888b44bae647b08e8125548c6bb98e" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\dff01454c888463d8f560f44f5704845" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\301bbc7b37a248a6854096f807d20d29" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\fee8eb3055c54e0ab41294f6f8d53bef" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\067a1c7afeb64b63aaf87483016a0581" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\bee22dfdeffc4d5998c22fdeddebae26" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\fa7cf9b8dcfb4c8f9a2f8b6397c8b561" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\969f157d209a4d95bd33fb4c78fbb865" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\1b50b1aa4d154b7d958596a91c09d973" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\60a6a267ee424dada8a2cc2013695964" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\e2629fff699d4beda8d0d9d21552856e" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\09af44f9079d463e9d2d962caeb47d24" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\68b9bda72d11450aa3f7dc61d37426cd" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\ca1c303e1c9240c8b279b02ea529b049" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\fb590408ed954d6f82ac99c73b3838ee" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\2f629eccee904dcb8da5d5a04d549c6d" />
|
||||
<option value="C:\Users\btoba\.config\.cool-request\request\serialize\949fb2693bfb4d649e246b767241ae51" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="projectCachePath" value="project-b7ef1676-f3ff-4c1d-950c-a8cb1bbc2462" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="dev_wms_serve" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="dev_wms_serve" options="-parameters" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/java/com/wms_main/service/quartz_job/serviceImpl/JobServiceImpl.java" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://maven.aliyun.com/repository/public" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -4,12 +4,29 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||
|
||||
## 项目概述
|
||||
|
||||
这是一个宝应梦阳WMS(仓库管理系统)后端项目,基于Spring Boot 3.3.5和Java 21开发,使用Maven构建。系统管理仓库的入库、出库、库存和任务调度等核心业务。
|
||||
这是一个宝应梦阳WMS(仓库管理系统)项目,包含前后端分离的完整解决方案:
|
||||
- **后端项目**:基于Spring Boot 3.3.5和Java 21开发,使用Maven构建
|
||||
- **前端项目**:基于Vue 3和Element Plus开发,提供Web管理界面
|
||||
- **业务场景**:支持托盘库(TP)和料箱库(BOX)两种存储类型,管理仓库的入库、出库、库存和任务调度等核心业务
|
||||
|
||||
## 项目结构
|
||||
|
||||
本项目包含两个子项目,位于不同目录:
|
||||
- `202504-Wms-MengYang-box/` - 料箱库(BOX)版本
|
||||
- `202504-Wms-MengYang-tp/` - 托盘库(TP)版本
|
||||
|
||||
每个子项目都包含:
|
||||
- `wms_serve_mengyang/` - Spring Boot后端服务
|
||||
- `wms_web_mengyang/` - Vue.js前端应用
|
||||
- `db/` - 数据库SQL文件
|
||||
|
||||
## 开发环境设置
|
||||
|
||||
### 构建和运行命令
|
||||
### 后端项目命令(Maven)
|
||||
```bash
|
||||
# 进入后端目录(以BOX版本为例)
|
||||
cd 202504-Wms-MengYang-box/wms_serve_mengyang
|
||||
|
||||
# 编译项目
|
||||
mvn clean compile
|
||||
|
||||
|
|
@ -19,28 +36,66 @@ mvn clean package
|
|||
# 运行项目
|
||||
mvn spring-boot:run
|
||||
|
||||
# 跳过测试运行(默认配置)
|
||||
# 跳过测试运行(项目配置默认跳过测试)
|
||||
mvn clean package -Dmaven.test.skip=true
|
||||
```
|
||||
|
||||
### 数据库配置
|
||||
### 前端项目命令(Vue.js)
|
||||
```bash
|
||||
# 进入前端目录(以BOX版本为例)
|
||||
cd 202504-Wms-MengYang-box/wms_web_mengyang
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# 启动开发服务器
|
||||
npm run serve
|
||||
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
|
||||
# 代码检查和修复
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### 运行环境配置
|
||||
|
||||
**数据库配置**
|
||||
- 本地开发:MySQL `localhost:3306/wms_mengyang_box`
|
||||
- 生产环境:MySQL `10.18.58.21:3306/wms_yachi_nantong`
|
||||
- 用户名/密码:本地使用root/root,生产使用user/user
|
||||
- 认证信息:本地使用root/root,生产使用user/user
|
||||
|
||||
### 应用配置
|
||||
**后端服务 (Spring Boot)**
|
||||
- 服务端口:12315
|
||||
- 应用名称:wms_main
|
||||
- 文件上传限制:单文件100MB,总计1000MB
|
||||
- 当前配置:`spring.profiles.active=online`
|
||||
|
||||
**前端应用 (Vue.js)**
|
||||
- 开发端口:12306
|
||||
- 后端API地址:`http://10.18.58.21:12315`
|
||||
- 路由模式:Hash路由
|
||||
|
||||
## 核心架构
|
||||
|
||||
### 分层架构
|
||||
|
||||
**后端架构(Spring Boot)**
|
||||
系统采用标准的MVC三层架构:
|
||||
- **Controller层**:REST API接口,包含mywms和wms两个模块
|
||||
- **Service层**:业务逻辑层,分为controller、business、api三个子模块
|
||||
- **DAO层**:数据访问层,使用MyBatis-Plus
|
||||
|
||||
**前端架构(Vue.js)**
|
||||
采用现代化的Vue 3组件化架构:
|
||||
- **Views层**:页面视图组件(login、HomeView、SystemCenter)
|
||||
- **Layout层**:业务布局组件(库存、入库、出库等功能页面)
|
||||
- **Components层**:可复用组件(sideMenu、appTag)
|
||||
- **API层**:HTTP请求封装和接口定义
|
||||
- **Store层**:Vuex状态管理(用户信息、菜单权限、标签页)
|
||||
- **Router层**:Vue Router路由管理
|
||||
- **Utils层**:工具函数(日期处理、格式化、加密等)
|
||||
|
||||
### 核心业务模块
|
||||
|
||||
#### 1. MyWMS模块 (`controller/mywms/`)
|
||||
|
|
@ -72,35 +127,79 @@ mvn clean package -Dmaven.test.skip=true
|
|||
- `vo/` - 视图对象(View Object)
|
||||
|
||||
### 常用枚举类 (`constant/enums/`)
|
||||
|
||||
**WMS业务枚举** (`enums/wms/`)
|
||||
- `StorageTypeEnums` - 存储类型(托盘库TP/料箱库BOX)
|
||||
- `WmsDepthStrategyEnums` - 深度策略枚举
|
||||
- `WmsTaskTypeEnums` - 任务类型枚举
|
||||
- `OrderStatusEnum` - 订单状态枚举
|
||||
- `WmsLocationTypeEnums` - 货位类型枚举
|
||||
- `WmsGoodsStatusEnums` - 货物状态枚举
|
||||
- `WmsVehicleStatusEnums` - 载具状态枚举
|
||||
|
||||
**WCS集成枚举** (`enums/wcs/`)
|
||||
- `WcsApiResponseCodeEnums` - WCS API响应码
|
||||
- `WcsStackerTaskTypeEnums` - 堆垛机任务类型
|
||||
- `WcsStackerTaskStatusEnums` - 堆垛机任务状态
|
||||
|
||||
**任务调度枚举** (`enums/jobs/`)
|
||||
- `JobStatusEnums` - 任务状态枚举
|
||||
- `JobTimerTypeEnums` - 定时器类型枚举
|
||||
|
||||
## 技术栈
|
||||
|
||||
### 核心依赖
|
||||
### 后端技术栈(Spring Boot)
|
||||
|
||||
**核心依赖**
|
||||
- Spring Boot Web 3.3.5 - REST API框架
|
||||
- Spring Boot Quartz - 定时任务调度
|
||||
- MyBatis-Plus 3.5.7 - ORM框架
|
||||
- MySQL Connector - 数据库连接
|
||||
- Lombok - 代码简化
|
||||
|
||||
### 工具库
|
||||
**工具库**
|
||||
- Hutool 5.8.33 - Java工具类库
|
||||
- FastJSON 2.0.21 - JSON处理
|
||||
- EasyExcel 4.0.3 & EasyPOI 4.5.0 - Excel处理
|
||||
- Apache HttpClient 4.5.13 - HTTP客户端
|
||||
- Google Guava 33.3.1 - 集合工具
|
||||
|
||||
### 前端技术栈(Vue.js)
|
||||
|
||||
**核心框架**
|
||||
- Vue 3.2.13 - 前端框架
|
||||
- Vue Router 4.0.3 - 路由管理
|
||||
- Vuex 4.0.0 - 状态管理
|
||||
- Element Plus 2.4.0 - UI组件库
|
||||
|
||||
**主要依赖**
|
||||
- Axios 1.3.3 - HTTP请求库
|
||||
- Moment 2.29.4 - 日期处理
|
||||
- XLSX 0.18.5 - Excel文件处理
|
||||
- QRCode.vue 3.4.1 - 二维码生成
|
||||
- Vue3-print-nb 0.1.4 - 打印功能
|
||||
- File-saver 2.0.5 - 文件下载
|
||||
|
||||
**开发工具**
|
||||
- Sass 1.83.4 - CSS预处理器
|
||||
- ESLint - 代码质量检查
|
||||
- Babel - JavaScript编译器
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
### 代码规范
|
||||
### 后端代码规范
|
||||
- 使用Lombok注解减少样板代码
|
||||
- 统一的API响应格式(WmsApiResponse)
|
||||
- 枚举类管理常量值
|
||||
- 接口-实现分离的服务层设计
|
||||
|
||||
### 前端代码规范
|
||||
- Vue 3 Composition API优先
|
||||
- Element Plus组件库统一UI风格
|
||||
- Vuex模块化状态管理
|
||||
- ESLint代码质量检查(关闭未使用变量警告)
|
||||
- 响应式设计,支持不同屏幕尺寸
|
||||
|
||||
### 数据库操作
|
||||
- 使用MyBatis-Plus进行ORM操作
|
||||
- 支持批量操作和事务处理
|
||||
|
|
@ -113,11 +212,15 @@ mvn clean package -Dmaven.test.skip=true
|
|||
- 请求日志过滤器:`RequestLogFilter`
|
||||
|
||||
### Excel处理
|
||||
系统支持完整的Excel导入导出功能:
|
||||
**后端**:使用EasyExcel和EasyPOI双重支持
|
||||
- 货物信息、产品信息、库存信息等业务数据
|
||||
- 使用EasyExcel和EasyPOI双重支持
|
||||
- 模板位置:`excel/easypoi/excelTemplate/`
|
||||
|
||||
**前端**:使用XLSX和Element Plus支持
|
||||
- 文件上传组件:`excel/` 目录下的各类Excel上传组件
|
||||
- 支持在线预览和数据导出
|
||||
- 集成二维码生成和打印功能
|
||||
|
||||
## 外部系统集成
|
||||
|
||||
### WCS系统集成
|
||||
|
|
@ -131,8 +234,91 @@ mvn clean package -Dmaven.test.skip=true
|
|||
|
||||
## 测试说明
|
||||
|
||||
**后端测试**
|
||||
项目配置中跳过了单元测试执行(`maven-surefire-plugin.skip=true`),在开发新功能时建议:
|
||||
1. 先实现功能代码
|
||||
2. 使用Postman等工具进行API测试
|
||||
3. 检查数据库数据状态
|
||||
4. 验证定时任务执行情况
|
||||
4. 验证定时任务执行情况
|
||||
|
||||
**前端测试**
|
||||
- 使用浏览器开发者工具调试
|
||||
- 通过Vue DevTools检查组件状态
|
||||
- 使用Element Plus组件库确保UI一致性
|
||||
- 在不同浏览器(Chrome、Firefox、Edge)中测试兼容性
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
### 特殊的Maven配置
|
||||
- 项目默认跳过单元测试:`maven-surefire-plugin.skip=true`
|
||||
- 最终构建文件名:`wms-box-server`
|
||||
- Java版本:21 (source和target都是21)
|
||||
- Maven Wrapper可用:使用`./mvnw`替代`mvn`命令
|
||||
|
||||
### 重要的文件路径
|
||||
- 主要工作目录:`202504-Wms-MengYang-box/wms_serve_mengyang/`
|
||||
- 日志存储:`wms_log/` (按日期和级别分类)
|
||||
- 数据库脚本:`db/wms_mengyang_box.sql`
|
||||
- MyBatis映射:`src/main/resources/mapper/`
|
||||
|
||||
### 常见开发任务
|
||||
|
||||
**启动后端服务**
|
||||
```bash
|
||||
cd 202504-Wms-MengYang-box/wms_serve_mengyang
|
||||
mvn spring-boot:run
|
||||
# 或使用Maven Wrapper
|
||||
./mvnw spring-boot:run
|
||||
```
|
||||
|
||||
**启动前端开发服务器**
|
||||
```bash
|
||||
cd 202504-Wms-MengYang-box/wms_web_mengyang
|
||||
npm run serve
|
||||
```
|
||||
|
||||
**查看日志**
|
||||
```bash
|
||||
# 查看今天的info日志
|
||||
tail -f wms_log/info/$(date +%Y-%m-%d)/$(date +%Y-%m-%d).0.log
|
||||
|
||||
# 查看今天的error日志
|
||||
tail -f wms_log/error/$(date +%Y-%m-%d)/$(date +%Y-%m-%d).0.log
|
||||
```
|
||||
|
||||
**数据库操作**
|
||||
- 使用MyBatis-Plus进行ORM操作
|
||||
- 支持批量操作和事务处理
|
||||
- 驼峰命名自动映射(`map-underscore-to-camel-case: true`)
|
||||
- ID生成策略:`assign_id`
|
||||
|
||||
### 系统集成要点
|
||||
|
||||
**WCS系统集成**
|
||||
- TCP和HTTP双协议支持
|
||||
- 堆垛机任务调度和状态同步
|
||||
- 载具管理(托盘和料箱)
|
||||
|
||||
**任务调度系统**
|
||||
- 基于Quartz的定时任务框架
|
||||
- 关键执行器:`WmsTaskExecutor`、`MyOutExecutor`、`WcsStackerTaskSender`
|
||||
- 任务状态实时监控
|
||||
|
||||
**Excel处理**
|
||||
- 后端:EasyExcel 4.0.3 + EasyPOI 4.5.0
|
||||
- 前端:XLSX 0.18.5 + Element Plus上传组件
|
||||
- 模板位置:`excel/easypoi/excelTemplate/`
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
1. **端口冲突**:确认12315端口未被占用
|
||||
2. **数据库连接**:检查MySQL服务状态和配置
|
||||
3. **前端代理**:确认后端API地址配置正确
|
||||
4. **日志分析**:按级别查看对应日志目录
|
||||
|
||||
### 调试技巧
|
||||
- 使用`RequestLogFilter`查看API请求日志
|
||||
- 通过`WmsControllerExceptionHandler`统一异常处理
|
||||
- 检查定时任务执行状态:查看`TAppJobs`表
|
||||
- Vue DevTools调试前端状态管理
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
# wms_serve_mengyang
|
||||
|
||||
宝应梦阳料箱库WMS后端
|
||||
宝应梦阳托盘库WMS后端
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
### MyWMS接口测试
|
||||
### 基础配置
|
||||
@baseUrl = http://localhost:12315
|
||||
|
||||
### 1. 入库订单接口
|
||||
POST {{baseUrl}}/mywms/orderIn
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"taskId": "testOrderId6",
|
||||
"vehicleNo": "1006"
|
||||
}
|
||||
|
||||
### 2. 出库订单接口
|
||||
POST {{baseUrl}}/mywms/orderOut
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"taskId": "testOrderId1",
|
||||
"vehicleNo": "1004"
|
||||
}
|
||||
|
||||
### 3. 库存查询接口 - 仅按载具查询
|
||||
POST {{baseUrl}}/mywms/stock
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"requestId": "testOrderId1",
|
||||
"details": [
|
||||
{
|
||||
"vehicleNo": "1001"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### 4. 库存查询接口 - 仅按库位查询
|
||||
POST {{baseUrl}}/mywms/stock
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"requestId": "testOrderId2",
|
||||
"details": [
|
||||
{
|
||||
"locationId": "A02-01-02-02"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### 5. 检查是否允许投料
|
||||
GET {{baseUrl}}/mywms/allowFeed
|
||||
|
||||
### 6. 允许出库
|
||||
GET {{baseUrl}}/mywms/allowOut
|
||||
|
||||
### 测试数据说明
|
||||
# 1. orderIn: 入库订单接口,需要taskId和vehicleNo
|
||||
# 2. orderOut: 出库订单接口,需要taskId和vehicleNo
|
||||
# 3. stock: 库存查询接口,需要requestId和details数组
|
||||
# - details中可以包含vehicleNo和/或locationId
|
||||
# 4. allowFeed: 查询当前系统是否允许投料操作(GET请求)
|
||||
|
||||
### 响应格式说明
|
||||
# 所有接口都返回MyWmsResponse格式:
|
||||
# {
|
||||
# "code": 200, // 响应码
|
||||
# "message": "操作成功", // 响应消息
|
||||
# "data": {}, // 具体数据
|
||||
# "success": true // 是否成功
|
||||
# }
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
### TaskController接口测试 - WMS任务控制接口
|
||||
### 基础配置
|
||||
@baseUrl = http://localhost:12315
|
||||
|
||||
### 1. WCS请求载具入库
|
||||
POST {{baseUrl}}/wms/task/wcsRequestVehicleIn
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"origin": "R1",
|
||||
"vehicleNo": "1006",
|
||||
"codeMessage": "test",
|
||||
"remark": "载具入库测试"
|
||||
}
|
||||
|
||||
### 2. 发送任务结果 - 任务完成
|
||||
POST {{baseUrl}}/wms/task/sendTaskResult
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"taskId": "1753403954324010001",
|
||||
"taskStatus": 100,
|
||||
"vehicleNo": "1004",
|
||||
"destination": "C1",
|
||||
"message": "任务执行成功"
|
||||
}
|
||||
|
||||
### 测试数据说明
|
||||
# 1. wcsRequestVehicleIn: WCS请求载具入库
|
||||
# - origin: 点位(必填)
|
||||
# - vehicleNo: 载具信息(必填)
|
||||
# - codeMessage: 条码信息(可选)
|
||||
# - remark: 备注(可选)
|
||||
|
||||
# 2. sendTaskResult: WCS反馈任务执行结果
|
||||
# - taskId: 任务ID(必填)
|
||||
# - taskStatus: 任务状态(必填)
|
||||
# * 0: 等待执行
|
||||
# * 1: 执行中
|
||||
# * 2: 执行完成
|
||||
# * 3: 执行失败
|
||||
# - vehicleNo: 载具号(必填)
|
||||
# - destination: 终点(可选)
|
||||
# - message: 信息(可选)
|
||||
|
||||
### 响应格式说明
|
||||
# wcsRequestVehicleIn返回WcsVehicleInResponse:
|
||||
# {
|
||||
# "success": true,
|
||||
# "code": "SUCCESS",
|
||||
# "message": "请求成功",
|
||||
# "data": {}
|
||||
# }
|
||||
|
||||
# sendTaskResult返回BaseWcsApiResponse:
|
||||
# {
|
||||
# "success": true,
|
||||
# "code": "SUCCESS",
|
||||
# "message": "任务结果接收成功"
|
||||
# }
|
||||
|
|
@ -9,10 +9,10 @@
|
|||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com</groupId>
|
||||
<artifactId>dev_wms_serve</artifactId>
|
||||
<artifactId>wms_serve_mengyang_box</artifactId>
|
||||
<version>3.2</version>
|
||||
<name>dev_wms_serve</name>
|
||||
<description>dev_wms_serve</description>
|
||||
<name>wms_serve_mengyang_box</name>
|
||||
<description>wms_serve_mengyang_box</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
|
|
@ -162,6 +162,15 @@
|
|||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>21</source>
|
||||
<target>21</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.wms_main.constant.enums.mywms;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum OrderInCBEnums {
|
||||
COMPLETE(1, "入库完成"),
|
||||
CANCEL(2, "入库取消"),
|
||||
EXCEPTION(3, "入库异常");
|
||||
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
OrderInCBEnums(Integer code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.wms_main.constant.enums.mywms;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum OrderOutCBEnums {
|
||||
COMPLETE(1, "出库完成"),
|
||||
CANCEL(2, "出库取消"),
|
||||
EXCEPTION(3, "出库异常");
|
||||
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
OrderOutCBEnums(Integer code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ public enum AppConfigKeyEnums {
|
|||
WCS_STACKER_TASK_URL("WcsStackerTaskUrl", "发送堆垛机任务地址"),
|
||||
WCS_PICK_TASK_URL("WcsPickTaskUrl", "发送拣选任务地址"),
|
||||
WCS_CANCEL_PICK_TASK_URL("WcsCancelPickTaskUrl", "发送取消拣选任务地址"),
|
||||
WCS_CAN_FEED_URL("wcsCanFeedUrl", "查询wcs是否可上料"),
|
||||
WCS_RELEASE_BOX_URL("WcsReleaseBoxUrl", "发送释放站台箱子地址"),
|
||||
STAND_CAPACITY("StandCapacity", "站台容量"),
|
||||
IMAGE_IP("ImageIp", "图片存放ip"),
|
||||
|
|
@ -19,7 +20,9 @@ public enum AppConfigKeyEnums {
|
|||
STOCK_WARNING_QTY("StockWarningQty", "库存预警数量"),
|
||||
MES_GET_GOODS_URL("MesGetGoodsUrl", "获取物料信息地址"),
|
||||
ERP_GET_VEHICLENO_DATA("ErpGetVehicleNoData", "根据托盘号查询简单生产入库单"),
|
||||
WMS_MANAGE_CALLBACK("WmsManageCallback", "场内WMS接受的入库出库执行后回调地址");
|
||||
WMS_ORDER_IN_CALLBACK("WmsOrderInCallback", "WMS接受的入库执行后回调地址"),
|
||||
WMS_ORDER_OUT_CALLBACK("WmsOrderOutCallback", "WMS接受的出库执行后回调地址");
|
||||
|
||||
|
||||
private final String key;
|
||||
private final String desc;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package com.wms_main.constant.enums.wms;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum WmsAgvLockEnums {
|
||||
AVAILABLE(0, "可用"),
|
||||
LOCK(1, "锁定");
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
}
|
||||
|
|
@ -7,15 +7,20 @@ import com.wms_main.model.dto.request.mywms.StockRespGoodsDetail;
|
|||
import com.wms_main.model.dto.response.mywms.MyWmsResponse;
|
||||
import com.wms_main.service.controller.IMyWmsControllerService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
|
||||
@RestController
|
||||
@ResponseBody
|
||||
@CrossOrigin
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/mywms")
|
||||
@Slf4j
|
||||
public class MyWmsController {
|
||||
|
||||
private final IMyWmsControllerService myWmsControllerService;
|
||||
|
|
@ -34,4 +39,14 @@ public class MyWmsController {
|
|||
public MyWmsResponse<List<StockRespGoodsDetail>> stock(@RequestBody StockReq request) {
|
||||
return myWmsControllerService.stock(request);
|
||||
}
|
||||
|
||||
@GetMapping("/allowFeed")
|
||||
public MyWmsResponse<Boolean> canFeed() {
|
||||
return myWmsControllerService.queryCanFeed();
|
||||
}
|
||||
|
||||
@GetMapping("/allowOut")
|
||||
public MyWmsResponse<Boolean> canOut() {
|
||||
return myWmsControllerService.queryCanOut();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package com.wms_main.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.wms_main.model.po.TAppAgvLock;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AGV互锁表数据访问接口
|
||||
*/
|
||||
public interface ITAppAgvLockService extends IService<TAppAgvLock> {
|
||||
|
||||
/**
|
||||
* 根据AGV和站点查询锁定记录
|
||||
*/
|
||||
List<TAppAgvLock> getByAgvAndStation(String agvId, String feedStation);
|
||||
|
||||
/**
|
||||
* 根据站点查询所有锁定记录
|
||||
*/
|
||||
List<TAppAgvLock> getByStation(String feedStation);
|
||||
|
||||
/**
|
||||
* 查询超时的锁定记录
|
||||
*/
|
||||
List<TAppAgvLock> getTimeoutLocks();
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.wms_main.dao.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.wms_main.dao.ITAppAgvLockService;
|
||||
import com.wms_main.mapper.AppAgvLockMapper;
|
||||
import com.wms_main.model.po.TAppAgvLock;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AGV互锁表数据访问实现
|
||||
*/
|
||||
@Service
|
||||
public class TAppAgvLockServiceImpl extends ServiceImpl<AppAgvLockMapper, TAppAgvLock> implements ITAppAgvLockService {
|
||||
|
||||
@Override
|
||||
public List<TAppAgvLock> getByAgvAndStation(String agvId, String feedStation) {
|
||||
return list(new LambdaQueryWrapper<TAppAgvLock>()
|
||||
.eq(TAppAgvLock::getAgvId, agvId)
|
||||
.eq(TAppAgvLock::getFeedStation, feedStation)
|
||||
.eq(TAppAgvLock::getLockStatus, 1)
|
||||
.orderByAsc(TAppAgvLock::getCreateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TAppAgvLock> getByStation(String feedStation) {
|
||||
return list(new LambdaQueryWrapper<TAppAgvLock>()
|
||||
.eq(TAppAgvLock::getFeedStation, feedStation)
|
||||
.eq(TAppAgvLock::getLockStatus, 1)
|
||||
.orderByAsc(TAppAgvLock::getPriority)
|
||||
.orderByAsc(TAppAgvLock::getCreateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TAppAgvLock> getTimeoutLocks() {
|
||||
return list(new LambdaQueryWrapper<TAppAgvLock>()
|
||||
.eq(TAppAgvLock::getLockStatus, 1)
|
||||
.lt(TAppAgvLock::getLockTime, LocalDateTime.now().minusSeconds(300)) // 超过5分钟的锁定
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.wms_main.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.wms_main.model.po.TAppAgvLock;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* AGV互锁表映射器
|
||||
*/
|
||||
@Mapper
|
||||
public interface AppAgvLockMapper extends BaseMapper<TAppAgvLock> {
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.wms_main.model.dto.request.mywms;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
|
@ -8,8 +9,18 @@ import lombok.NoArgsConstructor;
|
|||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class OrderInCBReq {
|
||||
String orderId;
|
||||
String vehicleNo;
|
||||
Integer orderStatus;
|
||||
String message;
|
||||
@JsonProperty("taskId")
|
||||
private String taskId;
|
||||
|
||||
@JsonProperty("vehicleNo")
|
||||
private String vehicleNo;
|
||||
|
||||
@JsonProperty("locationId")
|
||||
private String locationId;
|
||||
|
||||
@JsonProperty("result")
|
||||
private Integer result;
|
||||
|
||||
@JsonProperty("resultMessage")
|
||||
private String resultMessage;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
package com.wms_main.model.dto.request.mywms;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
|
||||
import com.wms_main.repository.utils.StringUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
|
@ -18,34 +13,11 @@ public class OrderInReq {
|
|||
@JsonProperty("taskId")
|
||||
private String taskId;
|
||||
|
||||
@JsonProperty("storageId")
|
||||
private Integer storageId;
|
||||
|
||||
@JsonProperty("taskType")
|
||||
private Integer taskType;
|
||||
|
||||
@JsonProperty("vehicleNo")
|
||||
private String vehicleNo;
|
||||
|
||||
@JsonProperty("standId")
|
||||
private String standId;
|
||||
|
||||
@JsonProperty("requestTime")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime requestTime;
|
||||
|
||||
@JsonProperty("requestUser")
|
||||
private String requestUser;
|
||||
|
||||
public boolean isValid() {
|
||||
if (StringUtils.isEmpty(this.getTaskId())
|
||||
|| StringUtils.isEmpty(this.getVehicleNo())
|
||||
|| StringUtils.isEmpty(this.getStandId())
|
||||
|| !Objects.equals(this.getTaskType(), WmsTaskTypeEnums.IN.getCode())) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return !StringUtils.isEmpty(this.getTaskId())
|
||||
&& !StringUtils.isEmpty(this.getVehicleNo());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.wms_main.model.dto.request.mywms;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
|
@ -8,9 +9,15 @@ import lombok.NoArgsConstructor;
|
|||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class OrderOutCBReq {
|
||||
String orderId;
|
||||
String vehicleNo;
|
||||
Integer orderStatus;
|
||||
String outStand;
|
||||
String message;
|
||||
@JsonProperty("taskId")
|
||||
private String taskId;
|
||||
|
||||
@JsonProperty("result")
|
||||
private Integer result;
|
||||
|
||||
@JsonProperty("resultMessage")
|
||||
private String resultMessage;
|
||||
|
||||
@JsonProperty("vehicleNo")
|
||||
private String vehicleNo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ import lombok.Setter;
|
|||
@Getter
|
||||
@Setter
|
||||
public class OrderOutGoodsDetail {
|
||||
@JsonProperty("inTaskId")
|
||||
private String inTaskId;
|
||||
@JsonProperty("vehicleNo")
|
||||
private String vehicleNo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
package com.wms_main.model.dto.request.mywms;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
|
@ -17,20 +11,6 @@ public class OrderOutReq {
|
|||
@JsonProperty("taskId")
|
||||
private String taskId;
|
||||
|
||||
@JsonProperty("storageId")
|
||||
private Integer storageId;
|
||||
|
||||
@JsonProperty("taskType")
|
||||
private Integer taskType;
|
||||
|
||||
@JsonProperty("details")
|
||||
private List<OrderOutGoodsDetail> details;
|
||||
|
||||
@JsonProperty("requestTime")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime requestTime;
|
||||
|
||||
@JsonProperty("requestUser")
|
||||
private String requestUser;
|
||||
@JsonProperty("vehicleNo")
|
||||
private String vehicleNo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,25 +16,10 @@ public class StockReq {
|
|||
@JsonProperty("requestId")
|
||||
private String requestId;
|
||||
|
||||
@JsonProperty("storageId")
|
||||
private Integer storageId;
|
||||
|
||||
@JsonProperty("requestTime")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String requestTime;
|
||||
|
||||
@JsonProperty("requestUser")
|
||||
private String requestUser;
|
||||
|
||||
@JsonProperty("details")
|
||||
private List<StockReqGoodsDetail> details;
|
||||
|
||||
public boolean empty() {
|
||||
return StringUtils.isEmpty(requestId)
|
||||
&& StringUtils.isEmpty(requestTime)
|
||||
&& StringUtils.isEmpty(requestUser)
|
||||
&& Objects.isNull(storageId);
|
||||
return StringUtils.isEmpty(requestId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,8 @@ public class StockReqGoodsDetail {
|
|||
@JsonProperty("locationId")
|
||||
private String locationId;
|
||||
|
||||
@JsonProperty("inTaskId")
|
||||
private String inTaskId;
|
||||
|
||||
public boolean empty() {
|
||||
return StringUtils.isEmpty(vehicleNo)
|
||||
&& StringUtils.isEmpty(locationId)
|
||||
&& StringUtils.isEmpty(inTaskId);
|
||||
&& StringUtils.isEmpty(locationId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package com.wms_main.model.dto.request.wcs;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class WcsCanFeedRequest {
|
||||
/**
|
||||
* 入库口编号(默认为单一入库口)
|
||||
*/
|
||||
private String inboundPort;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.wms_main.model.dto.response.mes;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MesApiResponse {
|
||||
@JsonProperty("code")
|
||||
private Integer code;
|
||||
|
||||
@JsonProperty("message")
|
||||
private String message;
|
||||
|
||||
public static MesApiResponse error(String msg) {
|
||||
return new MesApiResponse(999, msg);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.wms_main.model.dto.response.mes;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* MES系统查询是否可上料响应
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class MesCanFeedResponse {
|
||||
|
||||
/**
|
||||
* 是否可以上料
|
||||
*/
|
||||
private Boolean canFeed;
|
||||
|
||||
/**
|
||||
* 入库口状态(空闲/占用)
|
||||
*/
|
||||
private String inboundPortStatus;
|
||||
|
||||
/**
|
||||
* 当前处理中的任务数量
|
||||
*/
|
||||
private Integer processingTaskCount;
|
||||
|
||||
/**
|
||||
* 响应消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 预留字段1
|
||||
*/
|
||||
private String reserved1;
|
||||
|
||||
/**
|
||||
* 预留字段2
|
||||
*/
|
||||
private String reserved2;
|
||||
|
||||
/**
|
||||
* 预留字段3
|
||||
*/
|
||||
private String reserved3;
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ public class WcsApiResponse<T> extends BaseWcsApiResponse {
|
|||
/**
|
||||
* 返回数据
|
||||
*/
|
||||
@JsonProperty("data")
|
||||
@JsonProperty("returnData")
|
||||
private T data;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package com.wms_main.model.dto.response.wcs;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 立库查询是否可上料响应
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class WcsCanFeedResponse {
|
||||
@JsonProperty("responseTime")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
|
||||
private LocalDateTime responseTime;
|
||||
|
||||
@JsonProperty("allowAction")
|
||||
boolean allowAction;
|
||||
|
||||
@JsonProperty("msg")
|
||||
String msg;
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package com.wms_main.model.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* AGV互锁表
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName(value = "t_app_agv_lock", autoResultMap = true)
|
||||
public class TAppAgvLock {
|
||||
|
||||
@TableId(value = "lock_id")
|
||||
private String lockId;
|
||||
|
||||
/**
|
||||
* AGV设备ID
|
||||
*/
|
||||
@TableField(value = "agv_id")
|
||||
private String agvId;
|
||||
|
||||
/**
|
||||
* 上料站点
|
||||
*/
|
||||
@TableField(value = "feed_station")
|
||||
private String feedStation;
|
||||
|
||||
/**
|
||||
* 锁定状态: 1-锁定中, 0-已释放
|
||||
*/
|
||||
@TableField(value = "lock_status")
|
||||
private Integer lockStatus;
|
||||
|
||||
/**
|
||||
* 锁定类型: FEED-上料锁定, WAIT-等待锁定
|
||||
*/
|
||||
@TableField(value = "lock_type")
|
||||
private String lockType;
|
||||
|
||||
/**
|
||||
* 优先级: 数字越小优先级越高
|
||||
*/
|
||||
@TableField(value = "priority")
|
||||
private Integer priority;
|
||||
|
||||
/**
|
||||
* 队列位置
|
||||
*/
|
||||
@TableField(value = "queue_position")
|
||||
private Integer queuePosition;
|
||||
|
||||
/**
|
||||
* 锁定时间
|
||||
*/
|
||||
@TableField(value = "lock_time")
|
||||
private LocalDateTime lockTime;
|
||||
|
||||
/**
|
||||
* 释放时间
|
||||
*/
|
||||
@TableField(value = "unlock_time")
|
||||
private LocalDateTime unlockTime;
|
||||
|
||||
/**
|
||||
* 超时时间(秒)
|
||||
*/
|
||||
@TableField(value = "timeout_seconds")
|
||||
private Integer timeoutSeconds;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@TableField(value = "remark")
|
||||
private String remark;
|
||||
|
||||
@TableField(value = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField(value = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
|
|
@ -19,8 +19,8 @@ public class TAppOrderOut {
|
|||
@TableField(value = "order_id")
|
||||
private String orderId;
|
||||
|
||||
@TableField(value = "in_task_id")
|
||||
private String inTaskId;
|
||||
@TableField(value = "vehicle_no")
|
||||
private String vehicleNo;
|
||||
|
||||
@TableField(value = "order_status")
|
||||
private Integer orderStatus;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
package com.wms_main.service.api;
|
||||
|
||||
import com.wms_main.model.bo.ycwms.YCWmsApiResponse;
|
||||
import com.wms_main.model.dto.request.mywms.OrderInCBReq;
|
||||
import com.wms_main.model.dto.request.mywms.OrderOutCBReq;
|
||||
import com.wms_main.model.dto.response.mywms.MyWmsResponse;
|
||||
import com.wms_main.model.dto.response.mes.MesApiResponse;
|
||||
|
||||
public interface IExternalApiService {
|
||||
// MyWmsResponse<ErpVehicleNoResp> getVehicleNoData(String vehicleNo);
|
||||
|
||||
MyWmsResponse invokeOrderInCB(OrderInCBReq request);
|
||||
MesApiResponse invokeOrderInCB(OrderInCBReq request);
|
||||
|
||||
MyWmsResponse invokeOrderOutCB(OrderOutCBReq request);
|
||||
MesApiResponse invokeOrderOutCB(OrderOutCBReq request);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@ package com.wms_main.service.api;
|
|||
|
||||
import com.wms_main.model.bo.wcs.WcsPickTask;
|
||||
import com.wms_main.model.bo.wcs.WcsStackerTask;
|
||||
import com.wms_main.model.dto.request.wcs.WcsCanFeedRequest;
|
||||
import com.wms_main.model.dto.request.wcs.WcsPickTaskRequest;
|
||||
import com.wms_main.model.dto.request.wcs.WcsReleaseBoxRequest;
|
||||
import com.wms_main.model.dto.request.wcs.WcsStackerTaskRequest;
|
||||
import com.wms_main.model.dto.response.wcs.BaseWcsApiResponse;
|
||||
import com.wms_main.model.dto.response.wcs.WcsApiResponse;
|
||||
import com.wms_main.model.dto.response.wcs.WcsCanFeedResponse;
|
||||
|
||||
/**
|
||||
* wcs接口服务
|
||||
|
|
@ -39,4 +41,11 @@ public interface IWcsApiService {
|
|||
* @return 发送结果
|
||||
*/
|
||||
WcsApiResponse<WcsPickTask> cancelPickTask(WcsPickTaskRequest request);
|
||||
|
||||
/**
|
||||
* 查询是否可上料
|
||||
* @param request 查询请求信息
|
||||
* @return 查询结果
|
||||
*/
|
||||
WcsApiResponse<WcsCanFeedResponse> canFeed(WcsCanFeedRequest request);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.wms_main.app.AppCommon;
|
|||
import com.wms_main.constant.enums.wms.AppConfigKeyEnums;
|
||||
import com.wms_main.model.dto.request.mywms.OrderInCBReq;
|
||||
import com.wms_main.model.dto.request.mywms.OrderOutCBReq;
|
||||
import com.wms_main.model.dto.response.mywms.MyWmsResponse;
|
||||
import com.wms_main.model.dto.response.mes.MesApiResponse;
|
||||
import com.wms_main.repository.http.HttpClient;
|
||||
import com.wms_main.repository.http.entity.HttpRequest;
|
||||
import com.wms_main.repository.http.entity.HttpResponse;
|
||||
|
|
@ -12,12 +12,6 @@ import com.wms_main.service.api.IExternalApiService;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -26,87 +20,27 @@ public class ExternalApiServiceImpl implements IExternalApiService {
|
|||
private final HttpClient httpClient;// http客户端
|
||||
private final AppCommon appCommon;// 应用共通
|
||||
|
||||
// @Override
|
||||
// public YcwmsResponse<ErpVehicleNoResp> getVehicleNoData(String vehicleNo) {
|
||||
// Map<String, String> request = new HashMap<>();
|
||||
// request.put("vehicleNo", vehicleNo);
|
||||
// HttpRequest httpRequest = HttpRequest.postInstanceOf(appCommon.getConfigByKey(AppConfigKeyEnums.ERP_GET_VEHICLENO_DATA.getKey()), request);
|
||||
// HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||
// if (httpResponse != null && httpResponse.isSuccess()) {
|
||||
// try {
|
||||
// String responseMessage = httpResponse.getResponseMessage();
|
||||
// // 使用Map接收基本响应,避免泛型问题
|
||||
// Map<String, Object> baseResponseMap = JSON.parseObject(responseMessage, Map.class);
|
||||
//
|
||||
// // 创建最终返回的对象
|
||||
// YcwmsResponse<ErpVehicleNoResp> finalResponse = new YcwmsResponse<>();
|
||||
// finalResponse.setCode((Integer) baseResponseMap.get("code"));
|
||||
// finalResponse.setMessage((String) baseResponseMap.get("message"));
|
||||
//
|
||||
// // 处理returnData部分
|
||||
// if (baseResponseMap.containsKey("returnData") && baseResponseMap.get("returnData") != null) {
|
||||
// // 转换returnData部分
|
||||
// Map<String, Object> returnDataMap = (Map<String, Object>) baseResponseMap.get("returnData");
|
||||
//
|
||||
// // 创建ErpVehicleNoResp对象
|
||||
// ErpVehicleNoResp vehicleData = new ErpVehicleNoResp();
|
||||
// vehicleData.setVehicleNo((String) returnDataMap.get("vehicleNo"));
|
||||
//
|
||||
// // 处理goodsDetail数组
|
||||
// List<Map<String, Object>> goodsDetailList = (List<Map<String, Object>>) returnDataMap.get("goodsDetail");
|
||||
// List<ErpGoodsDetail> erpsGoodsDetails = new ArrayList<>();
|
||||
//
|
||||
// if (goodsDetailList != null) {
|
||||
// for (Map<String, Object> detail : goodsDetailList) {
|
||||
// ErpGoodsDetail goodsDetail = new ErpGoodsDetail();
|
||||
// goodsDetail.setGoodsId((String) detail.get("goodsId"));
|
||||
// goodsDetail.setGoodsName((String) detail.get("goodsName"));
|
||||
// goodsDetail.setBatch((String) detail.get("batch"));
|
||||
// goodsDetail.setGoodsType((String) detail.get("goodsType"));
|
||||
// goodsDetail.setSpecification((String) (detail.get("specification")));
|
||||
// goodsDetail.setQuantity(Double.parseDouble(detail.get("quantity").toString()));
|
||||
// goodsDetail.setGoodsDesc((String) detail.get("goodsDesc"));
|
||||
// goodsDetail.setXsfbillno((String) detail.get("xsfbillno"));
|
||||
// goodsDetail.setXsfseq(Integer.parseInt(detail.get("xsfseq").toString()));
|
||||
// goodsDetail.setNeibubianhao((String) detail.get("neibubianhao"));
|
||||
// goodsDetail.setGoodsBarcode((String) detail.get("goodsBarcode"));
|
||||
// erpsGoodsDetails.add(goodsDetail);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// vehicleData.setGoodsDetail(erpsGoodsDetails);
|
||||
// finalResponse.setReturnData(vehicleData);
|
||||
// }
|
||||
//
|
||||
// return finalResponse;
|
||||
// } catch (Exception e) {
|
||||
// return YcwmsResponse.error("解析响应数据失败: " + e.getMessage(), null);
|
||||
// }
|
||||
// }
|
||||
// return YcwmsResponse.error("请求未获得响应信息。", null);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public MyWmsResponse invokeOrderInCB(OrderInCBReq request) {
|
||||
HttpRequest httpRequest = HttpRequest.postInstanceOf(appCommon.getConfigByKey(AppConfigKeyEnums.WMS_MANAGE_CALLBACK.getKey()), request);
|
||||
public MesApiResponse invokeOrderInCB(OrderInCBReq request) {
|
||||
HttpRequest httpRequest = HttpRequest.postInstanceOf(appCommon.getConfigByKey(AppConfigKeyEnums.WMS_ORDER_IN_CALLBACK.getKey()), request);
|
||||
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||
if (httpResponse != null && httpResponse.isSuccess()) {
|
||||
MyWmsResponse response = new MyWmsResponse();
|
||||
response = httpResponse.getData(response.getClass().asSubclass(MyWmsResponse.class));
|
||||
MesApiResponse response = new MesApiResponse();
|
||||
response = httpResponse.getData(response.getClass().asSubclass(MesApiResponse.class));
|
||||
return response;
|
||||
}
|
||||
return MyWmsResponse.error("操作失败!", null);
|
||||
return MesApiResponse.error("操作失败!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyWmsResponse invokeOrderOutCB(OrderOutCBReq request) {
|
||||
HttpRequest httpRequest = HttpRequest.postInstanceOf(appCommon.getConfigByKey(AppConfigKeyEnums.WMS_MANAGE_CALLBACK.getKey()), request);
|
||||
public MesApiResponse invokeOrderOutCB(OrderOutCBReq request) {
|
||||
HttpRequest httpRequest = HttpRequest.postInstanceOf(appCommon.getConfigByKey(AppConfigKeyEnums.WMS_ORDER_OUT_CALLBACK.getKey()), request);
|
||||
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||
if (httpResponse != null && httpResponse.isSuccess()) {
|
||||
MyWmsResponse response = new MyWmsResponse();
|
||||
response = httpResponse.getData(response.getClass().asSubclass(MyWmsResponse.class));
|
||||
MesApiResponse response = new MesApiResponse();
|
||||
response = httpResponse.getData(response.getClass().asSubclass(MesApiResponse.class));
|
||||
return response;
|
||||
}
|
||||
return MyWmsResponse.error("操作失败!", null);
|
||||
return MesApiResponse.error("操作失败!");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,19 +4,26 @@ import com.wms_main.app.AppCommon;
|
|||
import com.wms_main.constant.enums.wms.AppConfigKeyEnums;
|
||||
import com.wms_main.model.bo.wcs.WcsPickTask;
|
||||
import com.wms_main.model.bo.wcs.WcsStackerTask;
|
||||
import com.wms_main.model.dto.request.wcs.WcsCanFeedRequest;
|
||||
import com.wms_main.model.dto.request.wcs.WcsPickTaskRequest;
|
||||
import com.wms_main.model.dto.request.wcs.WcsReleaseBoxRequest;
|
||||
import com.wms_main.model.dto.request.wcs.WcsStackerTaskRequest;
|
||||
import com.wms_main.model.dto.response.wcs.BaseWcsApiResponse;
|
||||
import com.wms_main.model.dto.response.wcs.WcsApiResponse;
|
||||
import com.wms_main.model.dto.response.wcs.WcsCanFeedResponse;
|
||||
import com.wms_main.model.po.TAppAgvLock;
|
||||
import com.wms_main.repository.http.HttpClient;
|
||||
import com.wms_main.repository.http.entity.HttpRequest;
|
||||
import com.wms_main.repository.http.entity.HttpResponse;
|
||||
import com.wms_main.service.api.IWcsApiService;
|
||||
import com.wms_main.service.business.IAgvLockService;
|
||||
import com.wms_main.service.business.IStackerTaskService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Wcs接口服务实现
|
||||
*/
|
||||
|
|
@ -26,6 +33,8 @@ import org.springframework.stereotype.Service;
|
|||
public class WcsApiServiceImpl implements IWcsApiService {
|
||||
private final HttpClient httpClient;// http客户端
|
||||
private final AppCommon appCommon;// 应用共通
|
||||
private final IAgvLockService agvLockService;// AGV互锁服务
|
||||
private final IStackerTaskService stackerTaskService;// 库位分配服务
|
||||
|
||||
/**
|
||||
* 发送堆垛机任务
|
||||
|
|
@ -97,4 +106,27 @@ public class WcsApiServiceImpl implements IWcsApiService {
|
|||
}
|
||||
return WcsApiResponse.error("请求未获得响应信息。", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询WCS系统是否可上料
|
||||
* @param request 查询请求信息
|
||||
* @return 查询结果
|
||||
*/
|
||||
@Override
|
||||
public WcsApiResponse<WcsCanFeedResponse> canFeed(WcsCanFeedRequest request) {
|
||||
HttpRequest httpRequest = HttpRequest.postInstanceOf(appCommon.getConfigByKey(AppConfigKeyEnums.WCS_CAN_FEED_URL.getKey()), request);
|
||||
// HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||
// if (httpResponse != null && httpResponse.isSuccess()) {
|
||||
// WcsApiResponse<WcsCanFeedResponse> response = new WcsApiResponse<>();
|
||||
// response = httpResponse.getData(response.getClass().asSubclass(WcsApiResponse.class));
|
||||
// return response;
|
||||
// }
|
||||
// TODO error -> success
|
||||
// return WcsApiResponse.error("请求未获得响应信息。", null);
|
||||
WcsCanFeedResponse wcsCanFeedResponse = new WcsCanFeedResponse();
|
||||
wcsCanFeedResponse.setResponseTime(LocalDateTime.now());
|
||||
wcsCanFeedResponse.setMsg("success");
|
||||
wcsCanFeedResponse.setAllowAction(true);
|
||||
return WcsApiResponse.success("成功", wcsCanFeedResponse);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
package com.wms_main.service.business;
|
||||
|
||||
import com.wms_main.model.po.TAppAgvLock;
|
||||
|
||||
/**
|
||||
* 入库口互锁服务接口
|
||||
* 管理单一入库口的AGV上料互锁机制
|
||||
*/
|
||||
public interface IAgvLockService {
|
||||
|
||||
/**
|
||||
* AGV就位并放货后,锁定入库口
|
||||
* @param agvId AGV设备ID
|
||||
* @param inboundPort 入库口编号
|
||||
* @return 锁定结果:成功返回锁定记录,失败返回null
|
||||
*/
|
||||
TAppAgvLock lockInboundPort(String agvId, String inboundPort);
|
||||
|
||||
/**
|
||||
* 检查入库口是否可以上料(MES系统调用)
|
||||
* @param inboundPort 入库口编号
|
||||
* @return 是否可以上料
|
||||
*/
|
||||
boolean canFeedToInboundPort(String inboundPort);
|
||||
|
||||
/**
|
||||
* 获取当前入库口处理中的任务数量
|
||||
* @param inboundPort 入库口编号
|
||||
* @return 处理中的任务数量
|
||||
*/
|
||||
int getProcessingTaskCount(String inboundPort);
|
||||
|
||||
/**
|
||||
* 获取入库口状态描述
|
||||
* @param inboundPort 入库口编号
|
||||
* @return 状态描述(空闲/占用)
|
||||
*/
|
||||
String getInboundPortStatus(String inboundPort);
|
||||
|
||||
/**
|
||||
* 清理超时锁定
|
||||
* @return 清理的记录数
|
||||
*/
|
||||
int cleanTimeoutLocks();
|
||||
|
||||
/**
|
||||
* 释放指定入库口的所有活动锁定
|
||||
* @param inboundPort 入库口编号
|
||||
* @return 释放的锁定数量
|
||||
*/
|
||||
int releaseAllInboundPortLocks(String inboundPort);
|
||||
}
|
||||
|
|
@ -13,11 +13,11 @@ import java.util.List;
|
|||
public interface IDepthStrategyService {
|
||||
|
||||
/**
|
||||
* 分析出库订单的深度策略
|
||||
* @param orderOut 出库订单
|
||||
* 基于载具号分析深度策略
|
||||
* @param vehicleNo 载具号
|
||||
* @return 深度策略分析结果
|
||||
*/
|
||||
DepthStrategyResult analyzeDepthStrategy(TAppOrderOut orderOut);
|
||||
DepthStrategyResult analyzeDepthStrategyByVehicle(String vehicleNo);
|
||||
|
||||
/**
|
||||
* 获取指定库位的深度信息
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
package com.wms_main.service.business.serviceImpl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.wms_main.constant.enums.wms.WmsAgvLockEnums;
|
||||
import com.wms_main.dao.ITAppAgvLockService;
|
||||
import com.wms_main.dao.ITAppTaskService;
|
||||
import com.wms_main.model.po.TAppAgvLock;
|
||||
import com.wms_main.model.po.TAppTask;
|
||||
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
|
||||
import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums;
|
||||
import com.wms_main.repository.utils.StringUtils;
|
||||
import com.wms_main.repository.utils.UUIDUtils;
|
||||
import com.wms_main.service.business.IAgvLockService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 入库口互锁服务实现
|
||||
* 管理单一入库口的AGV上料互锁机制
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AgvLockServiceImpl implements IAgvLockService {
|
||||
|
||||
private final ITAppAgvLockService agvLockService;
|
||||
private final ITAppTaskService appTaskService;
|
||||
|
||||
private static final String DEFAULT_INBOUND_PORT = "R1"; // 默认入库口
|
||||
private static final int DEFAULT_TIMEOUT_SECONDS = 600; // 默认超时时间10分钟
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public TAppAgvLock lockInboundPort(String agvId, String inboundPort) {
|
||||
if (StringUtils.isEmpty(agvId)) {
|
||||
log.warn("AGV ID为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 使用默认入库口如果未指定
|
||||
if (StringUtils.isEmpty(inboundPort)) {
|
||||
inboundPort = DEFAULT_INBOUND_PORT;
|
||||
}
|
||||
|
||||
// 清理超时锁定
|
||||
cleanTimeoutLocks();
|
||||
|
||||
// 检查入库口是否已被占用
|
||||
List<TAppAgvLock> existingLocks = agvLockService.list(new LambdaQueryWrapper<TAppAgvLock>().eq(TAppAgvLock::getFeedStation, inboundPort));
|
||||
if (existingLocks == null || existingLocks.isEmpty()) {
|
||||
return createInboundPortLock(agvId, inboundPort);
|
||||
} else {
|
||||
agvLockService.update(
|
||||
new LambdaUpdateWrapper<TAppAgvLock>()
|
||||
.eq(TAppAgvLock::getFeedStation, inboundPort)
|
||||
.eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
|
||||
.set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
|
||||
.set(TAppAgvLock::getLockTime, LocalDateTime.now())
|
||||
.set(TAppAgvLock::getRemark, "AGV就位并放货,锁定入库口")
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canFeedToInboundPort(String inboundPort) {
|
||||
// 使用默认入库口如果未指定
|
||||
if (StringUtils.isEmpty(inboundPort)) {
|
||||
inboundPort = DEFAULT_INBOUND_PORT;
|
||||
}
|
||||
|
||||
// 清理超时锁定
|
||||
cleanTimeoutLocks();
|
||||
|
||||
// 检查入库口是否有活动的锁定
|
||||
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
|
||||
boolean hasActiveLock = activeLocks.stream()
|
||||
.anyMatch(lock -> lock.getLockStatus() == 1);
|
||||
|
||||
if (hasActiveLock) {
|
||||
log.debug("入库口 {} 当前被占用,无法上料", inboundPort);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有正在处理的入库任务
|
||||
int processingTasks = getProcessingTaskCount(inboundPort);
|
||||
boolean canFeed = processingTasks == 0;
|
||||
|
||||
log.debug("入库口 {} 可上料状态: {}, 处理中任务数: {}", inboundPort, canFeed, processingTasks);
|
||||
return canFeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProcessingTaskCount(String inboundPort) {
|
||||
// 使用默认入库口如果未指定
|
||||
if (StringUtils.isEmpty(inboundPort)) {
|
||||
inboundPort = DEFAULT_INBOUND_PORT;
|
||||
}
|
||||
|
||||
// 统计正在处理的入库任务数量(包括等待、运行状态的任务)
|
||||
List<TAppTask> processingTasks = appTaskService.list(
|
||||
new LambdaQueryWrapper<TAppTask>()
|
||||
.eq(TAppTask::getTaskType, WmsTaskTypeEnums.IN.getCode())
|
||||
.in(TAppTask::getTaskStatus,
|
||||
WmsStackerTaskStatusEnums.WAIT.getCode(),
|
||||
WmsStackerTaskStatusEnums.RUN.getCode())
|
||||
.like(TAppTask::getOrigin, inboundPort) // 假设任务来源包含入库口信息
|
||||
);
|
||||
|
||||
return processingTasks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInboundPortStatus(String inboundPort) {
|
||||
// 使用默认入库口如果未指定
|
||||
if (StringUtils.isEmpty(inboundPort)) {
|
||||
inboundPort = DEFAULT_INBOUND_PORT;
|
||||
}
|
||||
|
||||
// 检查是否有活动锁定
|
||||
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
|
||||
boolean hasActiveLock = activeLocks.stream()
|
||||
.anyMatch(lock -> lock.getLockStatus() == 1);
|
||||
|
||||
if (hasActiveLock) {
|
||||
return "占用";
|
||||
}
|
||||
|
||||
// 检查是否有处理中的任务
|
||||
int processingTasks = getProcessingTaskCount(inboundPort);
|
||||
if (processingTasks > 0) {
|
||||
return "占用";
|
||||
}
|
||||
|
||||
return "空闲";
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int cleanTimeoutLocks() {
|
||||
List<TAppAgvLock> timeoutLocks = agvLockService.getTimeoutLocks();
|
||||
if (timeoutLocks.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
for (TAppAgvLock lock : timeoutLocks) {
|
||||
agvLockService.update(
|
||||
new LambdaUpdateWrapper<TAppAgvLock>()
|
||||
.eq(TAppAgvLock::getLockId, lock.getLockId())
|
||||
.set(TAppAgvLock::getLockStatus, 0)
|
||||
.set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
|
||||
.set(TAppAgvLock::getRemark, "超时自动释放")
|
||||
);
|
||||
|
||||
log.info("释放超时锁定: AGV {} 在入库口 {}", lock.getAgvId(), lock.getFeedStation());
|
||||
}
|
||||
|
||||
log.info("清理了 {} 个超时锁定", timeoutLocks.size());
|
||||
return timeoutLocks.size();
|
||||
} catch (Exception e) {
|
||||
log.error("清理超时锁定失败", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int releaseAllInboundPortLocks(String inboundPort) {
|
||||
// 使用默认入库口如果未指定
|
||||
if (StringUtils.isEmpty(inboundPort)) {
|
||||
inboundPort = DEFAULT_INBOUND_PORT;
|
||||
}
|
||||
|
||||
try {
|
||||
// 释放指定入库口的所有活动锁定
|
||||
agvLockService.update(
|
||||
new LambdaUpdateWrapper<TAppAgvLock>()
|
||||
.eq(TAppAgvLock::getFeedStation, inboundPort)
|
||||
.eq(TAppAgvLock::getLockStatus, WmsAgvLockEnums.LOCK.getCode())
|
||||
.set(TAppAgvLock::getLockStatus, WmsAgvLockEnums.AVAILABLE.getCode())
|
||||
.set(TAppAgvLock::getUnlockTime, LocalDateTime.now())
|
||||
.set(TAppAgvLock::getRemark, "入库任务完成,批量释放锁定")
|
||||
);
|
||||
|
||||
// 查询实际释放的锁定数量
|
||||
List<TAppAgvLock> activeLocks = agvLockService.getByStation(inboundPort);
|
||||
int releasedCount = (int) activeLocks.stream()
|
||||
.filter(lock -> lock.getLockStatus() == 0)
|
||||
.count();
|
||||
|
||||
log.info("释放入库口 {} 的所有锁定,共释放 {} 个锁定", inboundPort, releasedCount);
|
||||
return releasedCount;
|
||||
} catch (Exception e) {
|
||||
log.error("释放入库口 {} 的所有锁定失败", inboundPort, e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建入库口锁定记录
|
||||
*/
|
||||
private TAppAgvLock createInboundPortLock(String agvId, String inboundPort) {
|
||||
TAppAgvLock lock = new TAppAgvLock();
|
||||
lock.setLockId(UUIDUtils.getNewUUID());
|
||||
lock.setAgvId(agvId);
|
||||
lock.setFeedStation(inboundPort);
|
||||
lock.setLockStatus(1);
|
||||
lock.setLockType("INBOUND_PORT_LOCK");
|
||||
lock.setPriority(1);
|
||||
lock.setQueuePosition(1);
|
||||
lock.setLockTime(LocalDateTime.now());
|
||||
lock.setTimeoutSeconds(DEFAULT_TIMEOUT_SECONDS);
|
||||
lock.setCreateTime(LocalDateTime.now());
|
||||
lock.setUpdateTime(LocalDateTime.now());
|
||||
lock.setRemark("AGV就位并放货,锁定入库口");
|
||||
|
||||
if (agvLockService.save(lock)) {
|
||||
log.info("AGV {} 成功锁定入库口 {}", agvId, inboundPort);
|
||||
return lock;
|
||||
}
|
||||
|
||||
log.error("AGV {} 锁定入库口 {} 失败", agvId, inboundPort);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* 简化后的深度策略服务实现
|
||||
* 核心逻辑:根据inTaskId查询库存,检测深度策略
|
||||
* 核心逻辑:基于载具号查询库存,检测深度策略
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -31,36 +31,32 @@ public class DepthStrategyServiceImpl implements IDepthStrategyService {
|
|||
private final IStackerTaskService stackerTaskService;
|
||||
|
||||
/**
|
||||
* 分析出库订单的深度策略(核心方法)
|
||||
* 基于载具号分析深度策略(新核心方法)
|
||||
*/
|
||||
@Override
|
||||
public DepthStrategyResult analyzeDepthStrategy(TAppOrderOut orderOut) {
|
||||
// 1. 参数验证
|
||||
if (orderOut == null || StringUtils.isEmpty(orderOut.getInTaskId())) {
|
||||
log.warn("出库订单为空或入库任务ID为空");
|
||||
return DepthStrategyResult.createError("订单信息不完整");
|
||||
public DepthStrategyResult analyzeDepthStrategyByVehicle(String vehicleNo) {
|
||||
if (StringUtils.isEmpty(vehicleNo)) {
|
||||
log.warn("载具号为空");
|
||||
return DepthStrategyResult.createError("载具号不能为空");
|
||||
}
|
||||
|
||||
// 2. 根据inTaskId查询唯一库存
|
||||
TAppStock stock = appStockService.getOne(
|
||||
new LambdaQueryWrapper<TAppStock>()
|
||||
.eq(TAppStock::getInTaskId, orderOut.getInTaskId())
|
||||
.eq(TAppStock::getVehicleId, vehicleNo)
|
||||
.eq(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode())
|
||||
);
|
||||
|
||||
if (stock == null) {
|
||||
log.warn("入库任务ID{}对应的库存不存在", orderOut.getInTaskId());
|
||||
return DepthStrategyResult.createError("库存不存在");
|
||||
log.warn("载具号{}对应的库存不存在", vehicleNo);
|
||||
return DepthStrategyResult.createError("载具库存不存在");
|
||||
}
|
||||
|
||||
// 3. 获取库存深度
|
||||
Integer depth = getLocationDepth(stock.getLocationId());
|
||||
if (depth == null) {
|
||||
log.warn("无法解析库存位置深度: {}", stock.getLocationId());
|
||||
return DepthStrategyResult.createError("库位深度解析失败");
|
||||
}
|
||||
|
||||
// 4. 深度策略判断
|
||||
if (depth == 1) {
|
||||
return DepthStrategyResult.createDirectOut("深度1,直接出库");
|
||||
} else if (depth == 2) {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ package com.wms_main.service.business.serviceImpl;
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.wms_main.app.AppCommon;
|
||||
import com.wms_main.constant.enums.mywms.OrderInCBEnums;
|
||||
import com.wms_main.constant.enums.mywms.OrderOutCBEnums;
|
||||
import com.wms_main.constant.enums.wms.*;
|
||||
import com.wms_main.dao.*;
|
||||
import com.wms_main.model.dto.request.mywms.OrderInCBReq;
|
||||
import com.wms_main.model.dto.request.mywms.OrderOutCBReq;
|
||||
import com.wms_main.model.dto.response.mywms.MyWmsResponse;
|
||||
import com.wms_main.model.dto.response.mes.MesApiResponse;
|
||||
import com.wms_main.model.po.*;
|
||||
import com.wms_main.repository.utils.ConvertUtils;
|
||||
import com.wms_main.repository.utils.StringUtils;
|
||||
|
|
@ -22,7 +25,6 @@ import java.time.LocalDateTime;
|
|||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.wms_main.repository.utils.ConvertUtils.convertDestinationToPoint;
|
||||
|
||||
/**
|
||||
* 服务实现
|
||||
|
|
@ -391,27 +393,28 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
|
|||
.eq(TAppStock::getVehicleId, orderIn.getVehicleNo()));
|
||||
}
|
||||
|
||||
// OrderInCBReq orderInCBReq = new OrderInCBReq();
|
||||
// orderInCBReq.setOrderId(orderIn.getOrderId());
|
||||
// orderInCBReq.setVehicleNo(wmsTask.getVehicleId());
|
||||
// orderInCBReq.setOrderStatus(OrderStatusEnum.COMPLETE.getCode());
|
||||
// orderInCBReq.setMessage("入库完成");
|
||||
//
|
||||
// int times = 0;
|
||||
// MyWmsResponse response = null;
|
||||
// do {
|
||||
// Thread.sleep(15000L * times);
|
||||
// response = externalApiService.invokeOrderInCB(orderInCBReq);
|
||||
// times++;
|
||||
// } while (!response.getMessage().equals("success") && times <= 10);
|
||||
// if (response.getMessage().equals("error")) {
|
||||
// log.error("[wms]上报失败");
|
||||
// } else {
|
||||
// log.info("[wms]上报成功");
|
||||
// }
|
||||
if (!appOrderInService.removeById(orderIn.getRecordId())) {
|
||||
log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
|
||||
}
|
||||
OrderInCBReq orderInCBReq = new OrderInCBReq();
|
||||
orderInCBReq.setTaskId(orderIn.getOrderId());
|
||||
orderInCBReq.setVehicleNo(wmsTask.getVehicleId());
|
||||
orderInCBReq.setLocationId(wmsTask.getDestination());
|
||||
orderInCBReq.setResult(OrderInCBEnums.COMPLETE.getCode());
|
||||
orderInCBReq.setResultMessage("入库完成");
|
||||
|
||||
// int times = 0;
|
||||
// MesApiResponse response = null;
|
||||
// do {
|
||||
// Thread.sleep(15000L * times);
|
||||
// response = externalApiService.invokeOrderInCB(orderInCBReq);
|
||||
// times++;
|
||||
// } while (response.getCode() != 0 && times <= 10);
|
||||
// if (response.getCode() != 0) {
|
||||
// log.error("[wms]上报失败");
|
||||
// } else {
|
||||
// log.info("[wms]上报成功");
|
||||
// }
|
||||
// if (!appOrderInService.removeById(orderIn.getRecordId())) {
|
||||
// log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
|
||||
// }
|
||||
TAppVehicle vehicle = new TAppVehicle();
|
||||
vehicle.setVehicleId(wmsTask.getVehicleId());
|
||||
vehicle.setVehicleStatus(WmsVehicleStatusEnums.ON.getCode());
|
||||
|
|
@ -508,6 +511,12 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
|
|||
.eq(TAppStock::getVehicleId, vehicleId));
|
||||
// 当前载具的任务列表
|
||||
List<TAppTask> thisVehicleOutTasks = vehicleIdToTaskMap.get(vehicleId);
|
||||
if (thisVehicleOutTasks.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<String> orderIds = thisVehicleOutTasks.stream().map(TAppTask::getTaskGroup).distinct().toList();
|
||||
List<TAppOrderOut> orderOuts = appOrderOutService.list(new LambdaQueryWrapper<TAppOrderOut>()
|
||||
.in(TAppOrderOut::getOrderId, orderIds));
|
||||
if (!thisVehicleOutTasks.isEmpty()) {
|
||||
// 存储出库记录
|
||||
List<TAppTaskBak> stockOutRecordList = thisVehicleOutTasks.stream()
|
||||
|
|
@ -519,39 +528,30 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
|
|||
.eq(TAppTask::getTaskType, WmsTaskTypeEnums.OUT.getCode())
|
||||
.in(TAppTask::getTaskId, thisVehicleOutTasks.stream().map(TAppTask::getTaskId).toList()));
|
||||
// 使用流删除关联的出库订单实体(新增的核心部分)
|
||||
List<String> orderIds = thisVehicleOutTasks.stream().map(TAppTask::getTaskGroup).distinct().toList();
|
||||
List<TAppOrderOut> orderOuts = appOrderOutService.list(new LambdaQueryWrapper<TAppOrderOut>()
|
||||
.in(TAppOrderOut::getOrderId, orderIds));
|
||||
if (!orderOuts.isEmpty()) {
|
||||
appOrderOutService.removeBatchByIds(orderOuts);
|
||||
}
|
||||
}
|
||||
// List<String> orderOutsId = thisVehicleOutTasks.stream().map(TAppTask::getTaskGroup).distinct().toList();
|
||||
// for (String orderId : orderOutsId) {
|
||||
// if (orderId.contains("baokai")) {
|
||||
// continue;
|
||||
// }
|
||||
// List<TAppTask> appTasks = vehicleIdToTaskMap.get(vehicleId);
|
||||
// OrderOutCBReq orderOutCBReq = new OrderOutCBReq();
|
||||
// orderOutCBReq.setOrderId(orderId);
|
||||
// orderOutCBReq.setVehicleNo(vehicleId);
|
||||
// orderOutCBReq.setOrderStatus(OrderStatusEnum.COMPLETE.getCode());
|
||||
// orderOutCBReq.setOutStand(convertDestinationToPoint(appTasks.getFirst().getDestination()));
|
||||
// orderOutCBReq.setMessage("出库完成");
|
||||
//
|
||||
// int times = 0;
|
||||
// MyWmsResponse response = null;
|
||||
// do {
|
||||
// response = externalApiService.invokeOrderOutCB(orderOutCBReq);
|
||||
// times++;
|
||||
// Thread.sleep(15000L * times);
|
||||
// } while (!response.getMessage().equals("success") && times <= 10);
|
||||
// if (response.getMessage().equals("error")) {
|
||||
// log.error("[WMS]上报失败");
|
||||
// } else {
|
||||
// log.info("[WMS]上报成功");
|
||||
// }
|
||||
// }
|
||||
// for (TAppOrderOut orderOut : orderOuts) {
|
||||
// OrderOutCBReq orderOutCBReq = new OrderOutCBReq();
|
||||
// orderOutCBReq.setTaskId(orderOut.getOrderId());
|
||||
// orderOutCBReq.setVehicleNo(vehicleId);
|
||||
// orderOutCBReq.setResult(OrderOutCBEnums.COMPLETE.getCode());
|
||||
// orderOutCBReq.setResultMessage("出库完成");
|
||||
|
||||
// int times = 0;
|
||||
// MesApiResponse response = null;
|
||||
// do {
|
||||
// response = externalApiService.invokeOrderOutCB(orderOutCBReq);
|
||||
// times++;
|
||||
// Thread.sleep(15000L * times);
|
||||
// } while (response.getCode() != 0 && times <= 10);
|
||||
// if (response.getCode() != 0) {
|
||||
// log.error("[WMS]上报失败");
|
||||
// } else {
|
||||
// log.info("[WMS]上报成功");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,4 +14,8 @@ public interface IMyWmsControllerService {
|
|||
MyWmsResponse<Object> orderOut(OrderOutReq request);
|
||||
|
||||
MyWmsResponse<List<StockRespGoodsDetail>> stock(StockReq request);
|
||||
|
||||
MyWmsResponse<Boolean> queryCanFeed();
|
||||
|
||||
MyWmsResponse<Boolean> queryCanOut();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,32 @@
|
|||
package com.wms_main.service.controller.serviceImpl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.wms_main.constant.enums.wms.OrderStatusEnum;
|
||||
import com.wms_main.constant.enums.wms.StorageTypeEnums;
|
||||
import com.wms_main.constant.enums.wms.WmsDepthStrategyEnums;
|
||||
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
|
||||
import com.wms_main.constant.enums.wms.WmsStockStatusEnums;
|
||||
import com.wms_main.dao.ITAppAgvLockService;
|
||||
import com.wms_main.dao.ITAppLocationService;
|
||||
import com.wms_main.dao.ITAppOrderInService;
|
||||
import com.wms_main.dao.ITAppOrderOutService;
|
||||
import com.wms_main.dao.ITAppStockService;
|
||||
import com.wms_main.model.bo.wms.DepthStrategyResult;
|
||||
import com.wms_main.model.dto.request.mywms.*;
|
||||
import com.wms_main.model.dto.request.wcs.WcsCanFeedRequest;
|
||||
import com.wms_main.model.dto.response.mywms.MyWmsResponse;
|
||||
import com.wms_main.model.dto.response.wcs.WcsApiResponse;
|
||||
import com.wms_main.model.dto.response.wcs.WcsCanFeedResponse;
|
||||
import com.wms_main.model.po.TAppLocation;
|
||||
import com.wms_main.model.po.TAppOrderIn;
|
||||
import com.wms_main.model.po.TAppOrderOut;
|
||||
import com.wms_main.model.po.TAppStock;
|
||||
import com.wms_main.repository.utils.StringUtils;
|
||||
import com.wms_main.repository.utils.UUIDUtils;
|
||||
import com.wms_main.service.api.IWcsApiService;
|
||||
import com.wms_main.service.business.IAgvLockService;
|
||||
import com.wms_main.service.business.IDepthStrategyService;
|
||||
import com.wms_main.service.business.IStackerTaskService;
|
||||
import com.wms_main.service.controller.IMyWmsControllerService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
@ -35,8 +44,14 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
|
|||
private final ITAppOrderOutService appOrderOutService;
|
||||
private final ITAppStockService appStockService;
|
||||
private final IDepthStrategyService depthStrategyService;
|
||||
private final ITAppLocationService appLocationService;
|
||||
private final IStackerTaskService stackerTaskService;
|
||||
private final IAgvLockService agvLockService;
|
||||
private final IWcsApiService wcsApiService;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private static final String L_TEMP_FLAG = "temp";
|
||||
|
||||
@Override
|
||||
public MyWmsResponse<Object> orderIn(OrderInReq request) {
|
||||
try {
|
||||
|
|
@ -44,9 +59,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
|
|||
if (!request.isValid()) {
|
||||
return MyWmsResponse.error("参数错误", null);
|
||||
}
|
||||
if (!Objects.equals(request.getStorageId(), StorageTypeEnums.BOX.getCode())) {
|
||||
return MyWmsResponse.error("仓库号错误", null);
|
||||
}
|
||||
// 校验是否存在相同的入库单
|
||||
List<TAppOrderIn> withTaskId = appOrderInService.getWithTaskId(request.getTaskId());
|
||||
if (withTaskId == null) {
|
||||
|
|
@ -59,8 +71,8 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
|
|||
orderIn.setRecordId(UUIDUtils.getNewUUID());
|
||||
orderIn.setOrderId(request.getTaskId());
|
||||
orderIn.setVehicleNo(request.getVehicleNo());
|
||||
orderIn.setInStand(request.getStandId());
|
||||
orderIn.setRequestUser(request.getRequestUser());
|
||||
orderIn.setInStand("R1");
|
||||
orderIn.setRequestUser("wms");
|
||||
orderIn.setOrderStatus(OrderStatusEnum.CREATE.getCode());
|
||||
orderIn.setCreateTime(LocalDateTime.now());
|
||||
orderIn.setUpdateTime(LocalDateTime.now());
|
||||
|
|
@ -76,13 +88,10 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
|
|||
@Override
|
||||
public MyWmsResponse<Object> orderOut(OrderOutReq request) {
|
||||
try {
|
||||
if (request == null) return MyWmsResponse.error("参数错误", null);
|
||||
if (StringUtils.isEmpty(request.getTaskId())
|
||||
|| request.getDetails() == null
|
||||
|| request.getStorageId() == null
|
||||
|| !Objects.equals(request.getTaskType(), WmsTaskTypeEnums.OUT.getCode())) {
|
||||
if (request == null || StringUtils.isEmpty(request.getTaskId()) || StringUtils.isEmpty(request.getVehicleNo())) {
|
||||
return MyWmsResponse.error("参数错误", null);
|
||||
}
|
||||
|
||||
List<TAppOrderOut> orderOutCheckList = appOrderOutService.getWithTaskId(request.getTaskId());
|
||||
if (orderOutCheckList == null) {
|
||||
return MyWmsResponse.error("数据服务异常,请稍后重试", null);
|
||||
|
|
@ -90,29 +99,39 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
|
|||
if (!orderOutCheckList.isEmpty()) {
|
||||
return MyWmsResponse.error("出库单已存在,请勿重复推送", null);
|
||||
}
|
||||
List<TAppOrderOut> orderOutList = new ArrayList<>();
|
||||
for (OrderOutGoodsDetail orderOutGoodsDetail : request.getDetails()) {
|
||||
TAppOrderOut orderOut = new TAppOrderOut();
|
||||
orderOut.setRecordId(UUIDUtils.getNewUUID());
|
||||
orderOut.setOrderId(request.getTaskId());
|
||||
orderOut.setInTaskId(orderOutGoodsDetail.getInTaskId());
|
||||
orderOut.setOrderStatus(OrderStatusEnum.CREATE.getCode());
|
||||
orderOut.setCreateTime(LocalDateTime.now());
|
||||
orderOut.setUpdateTime(LocalDateTime.now());
|
||||
DepthStrategyResult depthStrategy = depthStrategyService.analyzeDepthStrategy(orderOut);
|
||||
orderOut.setDepthStrategy(depthStrategy.getStrategy().getCode());
|
||||
orderOut.setDepthStrategyDetail(objectMapper.writeValueAsString(depthStrategy));
|
||||
|
||||
if (orderOut.getDepthStrategy().equals(WmsDepthStrategyEnums.NO_ACTION.getCode())) {
|
||||
return MyWmsResponse.error("载具出库任务添加失败:" + orderOut.getInTaskId(), null);
|
||||
}
|
||||
orderOutList.add(orderOut);
|
||||
List<TAppStock> vehicleStocks = appStockService.list(
|
||||
new LambdaQueryWrapper<TAppStock>()
|
||||
.eq(TAppStock::getVehicleId, request.getVehicleNo())
|
||||
.eq(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode())
|
||||
);
|
||||
|
||||
if (vehicleStocks == null || vehicleStocks.isEmpty()) {
|
||||
return MyWmsResponse.error("载具号" + request.getVehicleNo() + "无库存记录", null);
|
||||
}
|
||||
if (!appOrderOutService.saveBatch(orderOutList)) {
|
||||
|
||||
TAppOrderOut orderOut = new TAppOrderOut();
|
||||
orderOut.setRecordId(UUIDUtils.getNewUUID());
|
||||
orderOut.setOrderId(request.getTaskId());
|
||||
orderOut.setVehicleNo(request.getVehicleNo());
|
||||
orderOut.setOrderStatus(OrderStatusEnum.CREATE.getCode());
|
||||
orderOut.setCreateTime(LocalDateTime.now());
|
||||
orderOut.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
DepthStrategyResult depthStrategy = depthStrategyService.analyzeDepthStrategyByVehicle(request.getVehicleNo());
|
||||
orderOut.setDepthStrategy(depthStrategy.getStrategy().getCode());
|
||||
orderOut.setDepthStrategyDetail(objectMapper.writeValueAsString(depthStrategy));
|
||||
|
||||
if (orderOut.getDepthStrategy().equals(WmsDepthStrategyEnums.NO_ACTION.getCode())) {
|
||||
return MyWmsResponse.error("载具出库任务添加失败:" + request.getVehicleNo(), null);
|
||||
}
|
||||
|
||||
if (!appOrderOutService.save(orderOut)) {
|
||||
return MyWmsResponse.error("出库单保存失败,请稍后再试", null);
|
||||
}
|
||||
return MyWmsResponse.success();
|
||||
} catch (Exception e) {
|
||||
log.error("出库任务添加失败", e);
|
||||
return MyWmsResponse.error("出库任务添加失败,请稍后再试", null);
|
||||
}
|
||||
}
|
||||
|
|
@ -130,7 +149,6 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
|
|||
new LambdaQueryWrapper<TAppStock>()
|
||||
.eq(StringUtils.isNotEmpty(stockReqGoodsDetail.getVehicleNo()), TAppStock::getVehicleId, stockReqGoodsDetail.getVehicleNo())
|
||||
.eq(StringUtils.isNotEmpty(stockReqGoodsDetail.getLocationId()), TAppStock::getLocationId, stockReqGoodsDetail.getLocationId())
|
||||
.eq(StringUtils.isNotEmpty(stockReqGoodsDetail.getInTaskId()), TAppStock::getInTaskId, stockReqGoodsDetail.getInTaskId())
|
||||
);
|
||||
if (stockList != null && !stockList.isEmpty()) {
|
||||
for (TAppStock stock : stockList) {
|
||||
|
|
@ -156,4 +174,39 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
|
|||
}
|
||||
return MyWmsResponse.success(respList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyWmsResponse<Boolean> queryCanFeed() {
|
||||
TAppLocation location = stackerTaskService.requestOneLocation(null, L_TEMP_FLAG);
|
||||
if (location != null && StringUtils.isNotEmpty(location.getLocationId())) {
|
||||
appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
|
||||
.eq(TAppLocation::getLocationId, location.getLocationId())
|
||||
.set(TAppLocation::getIsOccupy, 0)
|
||||
.set(TAppLocation::getVehicleId, ""));
|
||||
return MyWmsResponse.success(true);
|
||||
}
|
||||
return MyWmsResponse.error("无剩余可用库位", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyWmsResponse<Boolean> queryCanOut() {
|
||||
try {
|
||||
WcsApiResponse<WcsCanFeedResponse> wcsResponse = wcsApiService.canFeed(new WcsCanFeedRequest("R1"));
|
||||
|
||||
if (wcsResponse != null && wcsResponse.getData() != null) {
|
||||
Boolean wcsAllow = wcsResponse.getData().isAllowAction();
|
||||
Boolean wmsAllow = agvLockService.canFeedToInboundPort("R1");
|
||||
|
||||
if (wcsAllow && wmsAllow) {
|
||||
return MyWmsResponse.success(true);
|
||||
} else {
|
||||
return MyWmsResponse.error("出库口锁定中", null);
|
||||
}
|
||||
} else {
|
||||
return MyWmsResponse.error("WCS系统查询失败", null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return MyWmsResponse.error("系统异常,请稍后重试", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.wms_main.model.po.*;
|
|||
import com.wms_main.repository.utils.ConvertUtils;
|
||||
import com.wms_main.repository.utils.StringUtils;
|
||||
import com.wms_main.repository.utils.UUIDUtils;
|
||||
import com.wms_main.service.business.IAgvLockService;
|
||||
import com.wms_main.service.business.IStackerTaskService;
|
||||
import com.wms_main.service.controller.ITaskControllerService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
|
@ -41,11 +42,18 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
|||
private final IStackerTaskService stackerTaskService;// 堆垛机任务服务
|
||||
private final ITAppOrderInService orderInService;
|
||||
private final ITAppWcsTaskBakService appWcsTaskBakService;
|
||||
private final IAgvLockService agvLockService;// AGV互锁服务
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public WcsVehicleInResponse requireInTask(WcsVehicleInRequest request) {
|
||||
String vehicleNo = request.getVehicleNo();
|
||||
String origin = request.getOrigin();
|
||||
String inboundPort = "R1"; // 默认入库口
|
||||
|
||||
log.info("收到入库请求 - 载具号: {}, 来源: {}, 入库口: {}",
|
||||
vehicleNo, origin, inboundPort);
|
||||
|
||||
TAppOrderIn orderIn = orderInService.getOne(
|
||||
new LambdaQueryWrapper<TAppOrderIn>()
|
||||
.eq(StringUtils.isNotEmpty(vehicleNo), TAppOrderIn::getVehicleNo, vehicleNo)
|
||||
|
|
@ -55,6 +63,12 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
|||
return WcsVehicleInResponse.error(String.format("条码:%s 不存在待入库的订单", vehicleNo));
|
||||
}
|
||||
|
||||
// 检查入库口是否可用(不关心具体是哪台AGV)
|
||||
boolean canFeed = agvLockService.canFeedToInboundPort(inboundPort);
|
||||
if (!canFeed) {
|
||||
return WcsVehicleInResponse.error("入库口被占用,请等待其他任务完成后再试");
|
||||
}
|
||||
|
||||
/* 查找可用库位 */
|
||||
TAppLocation useLocation = stackerTaskService.requestOneLocation(null, vehicleNo);
|
||||
if (useLocation == null) {
|
||||
|
|
@ -93,6 +107,7 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
|||
.set(TAppOrderIn::getOrderStatus, OrderStatusEnum.RUNNING.getCode())
|
||||
.set(TAppOrderIn::getUpdateTime, LocalDateTime.now())
|
||||
);
|
||||
agvLockService.lockInboundPort("AGV", "");
|
||||
|
||||
WcsVehicleInResponse success = new WcsVehicleInResponse();
|
||||
success.setCode("200");
|
||||
|
|
@ -144,6 +159,19 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
|||
.eq(TAppOrderIn::getOrderId, wmsTask.getTaskGroup())
|
||||
.set(TAppOrderIn::getOrderStatus, OrderStatusEnum.COMPLETE.getCode())
|
||||
.set(TAppOrderIn::getCompleteTime, LocalDateTime.now()));
|
||||
|
||||
// 如果是入库任务完成,释放入库口锁定
|
||||
if (wmsTask != null && WmsTaskTypeEnums.IN.getCode().equals(wmsTask.getTaskType())) {
|
||||
try {
|
||||
String inboundPort = "R1"; // 默认入库口
|
||||
|
||||
// 释放该入库口的所有活动锁定,不关心具体是哪台AGV
|
||||
int releasedCount = agvLockService.releaseAllInboundPortLocks(inboundPort);
|
||||
log.info("入库任务完成,释放入库口 {} 的锁定,共释放 {} 个锁定", inboundPort, releasedCount);
|
||||
} catch (Exception e) {
|
||||
log.error("释放入库口锁定时发生异常", e);
|
||||
}
|
||||
}
|
||||
// 移除wcs任务,并向wcs备份表添加记录
|
||||
TAppWcsTaskBak wcsTaskBak = new TAppWcsTaskBak(
|
||||
wcsTask.getWcsTaskId(),
|
||||
|
|
|
|||
|
|
@ -63,10 +63,10 @@ public class MyOutExecutor implements Job {
|
|||
*/
|
||||
private void processSingleOrder(TAppOrderOut order) {
|
||||
try {
|
||||
// 1. 根据inTaskId获取关联库存
|
||||
TAppStock stock = getStockByInTaskId(order.getInTaskId());
|
||||
// 1. 根据载具号获取关联库存
|
||||
TAppStock stock = getStockByVehicleNo(order.getVehicleNo());
|
||||
if (stock == null) {
|
||||
log.error("未找到inTaskId关联的库存: {}", order.getInTaskId());
|
||||
log.error("未找到载具号关联的库存: {}", order.getVehicleNo());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -107,12 +107,12 @@ public class MyOutExecutor implements Job {
|
|||
}
|
||||
|
||||
/**
|
||||
* 根据inTaskId获取唯一库存
|
||||
* 根据载具号获取唯一库存
|
||||
*/
|
||||
private TAppStock getStockByInTaskId(String inTaskId) {
|
||||
private TAppStock getStockByVehicleNo(String vehicleNo) {
|
||||
return appStockService.getOne(
|
||||
new LambdaQueryWrapper<TAppStock>()
|
||||
.eq(TAppStock::getInTaskId, inTaskId)
|
||||
.eq(TAppStock::getVehicleId, vehicleNo)
|
||||
.eq(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode())
|
||||
);
|
||||
}
|
||||
|
|
|
|||
209
202504-Wms-MengYang-box/wms_web_mengyang/CLAUDE.md
Normal file
209
202504-Wms-MengYang-box/wms_web_mengyang/CLAUDE.md
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## 项目概述
|
||||
|
||||
这是宝应梦阳WMS前端项目(BOX料箱库版本),基于Vue 3和Element Plus开发的现代化Web管理界面,用于仓库管理系统的操作和监控。
|
||||
|
||||
## 开发环境设置
|
||||
|
||||
### 基本命令
|
||||
```bash
|
||||
# 进入项目目录
|
||||
cd 202504-Wms-MengYang-box/wms_web_mengyang
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# 启动开发服务器
|
||||
npm run serve
|
||||
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
|
||||
# 代码检查和修复
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### 开发配置
|
||||
- **开发端口**:12306
|
||||
- **路由模式**:Hash路由 (`createWebHashHistory`)
|
||||
- **默认路由**:登录页面 (`/`) -> 主页 (`/home`) -> 库存页面 (`/stock`)
|
||||
- **代理配置**:Microsoft OAuth认证代理
|
||||
|
||||
## 技术栈
|
||||
|
||||
### 核心框架
|
||||
- **Vue 3.2.13** - 前端框架(Composition API)
|
||||
- **Vue Router 4.0.3** - 路由管理
|
||||
- **Vuex 4.0.0** - 状态管理
|
||||
- **Element Plus 2.4.0** - UI组件库
|
||||
|
||||
### 主要依赖
|
||||
- **Axios 1.3.3** - HTTP请求库
|
||||
- **Moment 2.29.4** - 日期处理
|
||||
- **XLSX 0.18.5** - Excel文件处理
|
||||
- **QRCode.vue 3.4.1** - 二维码生成
|
||||
- **Vue3-print-nb 0.1.4** - 打印功能
|
||||
- **File-saver 2.0.5** - 文件下载
|
||||
|
||||
### 开发工具
|
||||
- **Sass 1.83.4** - CSS预处理器
|
||||
- **Vue CLI 5.0** - 构建工具
|
||||
- **ESLint** - 代码质量检查(已关闭未使用变量警告)
|
||||
|
||||
## 项目架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
src/
|
||||
├── api/ # API接口封装
|
||||
├── assets/ # 静态资源
|
||||
├── components/ # 可复用组件
|
||||
├── constant/ # 常量配置
|
||||
├── excel/ # Excel上传组件
|
||||
├── http/ # HTTP请求配置
|
||||
├── layout/ # 业务页面组件
|
||||
├── print/ # 打印相关组件
|
||||
├── router/ # 路由配置
|
||||
├── store/ # Vuex状态管理
|
||||
├── styles/ # 全局样式
|
||||
├── utils/ # 工具函数
|
||||
└── views/ # 主要视图组件
|
||||
```
|
||||
|
||||
### 核心业务模块
|
||||
|
||||
#### 1. 仓库作业 (`layout/`)
|
||||
**库存管理**
|
||||
- `stock.vue` - 库存查询和管理
|
||||
- `inventory.vue` - 库存盘点
|
||||
- `inventoryRecord.vue` - 盘点记录
|
||||
|
||||
**入出库作业**
|
||||
- `goodsIn.vue` - 入库作业界面
|
||||
- `goodsOut.vue` - 出库作业界面
|
||||
- `orderIn.vue` - 入库单管理
|
||||
- `orderOut.vue` - 出库单管理
|
||||
|
||||
**任务监控**
|
||||
- `taskMonitor.vue` - 任务执行监控
|
||||
- `pickTaskMonitor.vue` - 拣选任务监控
|
||||
- `inTaskRecord.vue` - 入库任务记录
|
||||
- `outTaskRecord.vue` - 出库任务记录
|
||||
|
||||
#### 2. 基础数据管理
|
||||
- `goods.vue` - 物料信息管理
|
||||
- `locationsTable.vue` - 库位信息管理
|
||||
- `standSettings.vue` - 站台(库口)设置
|
||||
- `vehicle.vue` - 料箱监控
|
||||
|
||||
#### 3. 配料系统
|
||||
- `kitting.vue` - 配料作业
|
||||
- `kittingList.vue` - 配料单管理
|
||||
- `kittingRelation.vue` - 配料关系配置
|
||||
- `clcKanban.vue` - 需求看板
|
||||
|
||||
#### 4. 系统管理
|
||||
- `wmsConfigNew.vue` - 系统配置
|
||||
- `role_user.vue` - 用户角色管理
|
||||
- `role_permission.vue` - 权限管理
|
||||
- `wmsLog.vue` - 系统日志
|
||||
|
||||
### API接口模块 (`api/`)
|
||||
|
||||
**核心业务接口**
|
||||
- `goods.js` - 物料信息API
|
||||
- `stock.js` - 库存相关API
|
||||
- `task.js` - 任务管理API
|
||||
- `location.js` - 库位管理API
|
||||
|
||||
**作业流程接口**
|
||||
- `orderIn.js` - 入库订单API
|
||||
- `orderOut.js` - 出库订单API
|
||||
- `kateWork.js` - 配料作业API
|
||||
|
||||
**系统功能接口**
|
||||
- `login.js` - 登录认证API
|
||||
- `user.js` - 用户管理API
|
||||
- `config.js` - 系统配置API
|
||||
- `excel.js` - Excel处理API
|
||||
|
||||
### 公共组件 (`components/`)
|
||||
- `sideMenu.vue` - 侧边菜单导航
|
||||
- `appTag.vue` - 标签页管理
|
||||
|
||||
### 工具模块 (`utils/`)
|
||||
- `dateUtils.js` - 日期处理工具
|
||||
- `formatter.js` - 数据格式化
|
||||
- `hashUtils.js` - 哈希计算
|
||||
- `stringUtils.js` - 字符串处理
|
||||
- `loading.js` - 加载状态管理
|
||||
- `myMessageBox.js` - 消息提示封装
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
### 路由配置
|
||||
- 使用Hash路由模式,兼容性更好
|
||||
- 实现了路由守卫,未登录用户自动跳转登录页
|
||||
- 登录状态通过`sessionStorage`中的`user`字段判断
|
||||
|
||||
### 状态管理
|
||||
- 使用Vuex进行全局状态管理
|
||||
- 主要管理用户信息、菜单权限、标签页状态
|
||||
|
||||
### HTTP请求
|
||||
- 统一使用Axios进行API调用
|
||||
- 请求封装在`/http/request.js`中
|
||||
- API接口按业务模块分类组织
|
||||
|
||||
### Excel处理
|
||||
- 支持Excel文件上传和解析
|
||||
- 专门的Excel上传组件位于`excel/`目录
|
||||
- 支持多种业务数据的Excel导入导出
|
||||
|
||||
### 打印功能
|
||||
- 使用`vue3-print-nb`实现打印功能
|
||||
- 打印组件位于`print/`目录
|
||||
|
||||
### 样式规范
|
||||
- 使用Sass预处理器
|
||||
- 全局样式文件:`styles/index.scss`
|
||||
- 响应式设计,支持不同屏幕尺寸
|
||||
|
||||
## 常见开发任务
|
||||
|
||||
### 添加新页面
|
||||
1. 在`layout/`目录创建Vue组件
|
||||
2. 在`router/index.js`中配置路由
|
||||
3. 如需API调用,在`api/`目录创建对应接口文件
|
||||
4. 更新侧边菜单配置
|
||||
|
||||
### Excel上传功能
|
||||
1. 参考`excel/`目录下的现有组件
|
||||
2. 使用Element Plus的上传组件
|
||||
3. 后端API处理Excel数据解析
|
||||
|
||||
### 新增API接口
|
||||
1. 在`api/`目录按模块创建文件
|
||||
2. 使用`@/http/request`进行请求封装
|
||||
3. 导出接口函数供组件使用
|
||||
|
||||
### 调试和测试
|
||||
- 使用Vue DevTools检查组件状态
|
||||
- 浏览器开发者工具调试网络请求
|
||||
- ESLint检查代码质量
|
||||
- 在不同浏览器中测试兼容性
|
||||
|
||||
## 后端API集成
|
||||
|
||||
### 默认后端地址
|
||||
根据当前配置,后端API地址需要在`http/request.js`中配置,通常为:
|
||||
- 开发环境:`http://localhost:12315`
|
||||
- 生产环境:`http://10.18.58.21:12315`
|
||||
|
||||
### 认证机制
|
||||
- 支持Microsoft OAuth认证代理
|
||||
- 登录状态存储在`sessionStorage`中
|
||||
- 路由守卫自动验证用户登录状态
|
||||
|
|
@ -4,12 +4,23 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||
|
||||
## 项目概述
|
||||
|
||||
这是一个宝应梦阳WMS(仓库管理系统)后端项目,基于Spring Boot 3.3.5和Java 21开发,使用Maven构建。系统管理仓库的入库、出库、库存和任务调度等核心业务。
|
||||
这是宝应梦阳WMS(仓库管理系统)后端项目(TP托盘库版本),基于Spring Boot 3.3.5和Java 21开发,使用Maven构建。专门针对托盘库存储场景,管理仓库的入库、出库、库存和任务调度等核心业务。
|
||||
|
||||
## 项目特点
|
||||
|
||||
**TP托盘库版本特性**
|
||||
- 专为托盘存储优化的算法策略
|
||||
- 支持大型货物的托盘化存储管理
|
||||
- 与BOX料箱库版本在业务逻辑上有所差异
|
||||
- 数据库schema针对托盘库场景设计
|
||||
|
||||
## 开发环境设置
|
||||
|
||||
### 构建和运行命令
|
||||
### 基本构建命令
|
||||
```bash
|
||||
# 进入项目目录
|
||||
cd 202504-Wms-MengYang-tp/wms_serve_mengyang
|
||||
|
||||
# 编译项目
|
||||
mvn clean compile
|
||||
|
||||
|
|
@ -19,19 +30,30 @@ mvn clean package
|
|||
# 运行项目
|
||||
mvn spring-boot:run
|
||||
|
||||
# 跳过测试运行(默认配置)
|
||||
# 使用Maven Wrapper
|
||||
./mvnw spring-boot:run
|
||||
|
||||
# 跳过测试运行(项目配置默认跳过测试)
|
||||
mvn clean package -Dmaven.test.skip=true
|
||||
```
|
||||
|
||||
### 数据库配置
|
||||
- 本地开发:MySQL `localhost:3306/wms_mengyang_box`
|
||||
- 生产环境:MySQL `10.18.58.21:3306/wms_yachi_nantong`
|
||||
- 用户名/密码:本地使用root/root,生产使用user/user
|
||||
### 运行环境配置
|
||||
|
||||
### 应用配置
|
||||
**数据库配置**
|
||||
- 本地开发:MySQL `localhost:3306/wms_mengyang_tp`(注意:使用tp数据库)
|
||||
- 生产环境:MySQL `10.18.58.21:3306/wms_yachi_nantong`
|
||||
- 认证信息:本地使用root/root,生产使用user/user
|
||||
|
||||
**应用配置**
|
||||
- 服务端口:12315
|
||||
- 应用名称:wms_main
|
||||
- 文件上传限制:单文件100MB,总计1000MB
|
||||
- 当前配置:`spring.profiles.active=online`
|
||||
|
||||
**Maven特殊配置**
|
||||
- 项目默认跳过单元测试:`maven-surefire-plugin.skip=true`
|
||||
- 最终构建文件名:`wms-box-server`(注意:名称还是box-server但实际是tp版本)
|
||||
- Java版本:21 (source和target都是21)
|
||||
|
||||
## 核心架构
|
||||
|
||||
|
|
@ -50,50 +72,134 @@ mvn clean package -Dmaven.test.skip=true
|
|||
- `POST /stock` - 库存查询接口
|
||||
|
||||
#### 2. 深度策略服务 (`service/business/DepthStrategyService`)
|
||||
核心算法模块,实现智能仓储策略:
|
||||
- 支持托盘库(TP)和料箱库(BOX)两种存储类型
|
||||
- 动态深度分析和出库优化策略
|
||||
核心算法模块,针对托盘库优化:
|
||||
- **托盘库(TP)专属存储策略**
|
||||
- 大型货物的存储位置优化算法
|
||||
- 托盘堆叠和存取路径优化
|
||||
|
||||
#### 3. 任务调度系统 (`service/quartz_job/`)
|
||||
基于Quartz的定时任务:
|
||||
基于Quartz的定时任务框架:
|
||||
- `WmsTaskExecutor` - WMS任务执行器
|
||||
- `MyOutExecutor` - 出库任务执行器
|
||||
- `WcsStackerTaskSender` - WCS任务发送器
|
||||
- `WcsStackerTaskSender` - WCS堆垛机任务发送器
|
||||
|
||||
#### 4. 设备集成 (`service/api/`)
|
||||
- `WcsApiService` - WCS系统集成
|
||||
- `WcsApiService` - WCS系统集成(托盘库设备)
|
||||
- `ExternalApiService` - 外部系统API调用
|
||||
|
||||
### 数据模型结构
|
||||
- `po/` - 数据库实体对象(Persistent Object)
|
||||
- `po/` - 数据库实体对象(针对托盘库schema)
|
||||
- `dto/request/` - 请求数据传输对象
|
||||
- `dto/response/` - 响应数据传输对象
|
||||
- `bo/` - 业务对象(Business Object)
|
||||
- `vo/` - 视图对象(View Object)
|
||||
|
||||
### 常用枚举类 (`constant/enums/`)
|
||||
- `StorageTypeEnums` - 存储类型(托盘库TP/料箱库BOX)
|
||||
- `WmsDepthStrategyEnums` - 深度策略枚举
|
||||
|
||||
**WMS业务枚举** (`enums/wms/`)
|
||||
- `StorageTypeEnums` - 存储类型(重点关注TP托盘库类型)
|
||||
- `WmsDepthStrategyEnums` - 深度策略枚举(托盘库专用策略)
|
||||
- `WmsTaskTypeEnums` - 任务类型枚举
|
||||
- `OrderStatusEnum` - 订单状态枚举
|
||||
- `WmsLocationTypeEnums` - 货位类型枚举(托盘货位)
|
||||
- `WmsVehicleStatusEnums` - 载具状态枚举(托盘载具)
|
||||
|
||||
**WCS集成枚举** (`enums/wcs/`)
|
||||
- `WcsApiResponseCodeEnums` - WCS API响应码
|
||||
- `WcsStackerTaskTypeEnums` - 堆垛机任务类型(托盘堆垛机)
|
||||
- `WcsStackerTaskStatusEnums` - 堆垛机任务状态
|
||||
|
||||
## 技术栈
|
||||
|
||||
### 核心依赖
|
||||
- Spring Boot Web 3.3.5 - REST API框架
|
||||
- Spring Boot Quartz - 定时任务调度
|
||||
- MyBatis-Plus 3.5.7 - ORM框架
|
||||
- MySQL Connector - 数据库连接
|
||||
- Lombok - 代码简化
|
||||
- **Spring Boot Web 3.3.5** - REST API框架
|
||||
- **Spring Boot Quartz** - 定时任务调度
|
||||
- **MyBatis-Plus 3.5.7** - ORM框架
|
||||
- **MySQL Connector** - 数据库连接
|
||||
- **Lombok** - 代码简化
|
||||
|
||||
### 工具库
|
||||
- Hutool 5.8.33 - Java工具类库
|
||||
- FastJSON 2.0.21 - JSON处理
|
||||
- EasyExcel 4.0.3 & EasyPOI 4.5.0 - Excel处理
|
||||
- Apache HttpClient 4.5.13 - HTTP客户端
|
||||
- Google Guava 33.3.1 - 集合工具
|
||||
- **Hutool 5.8.33** - Java工具类库
|
||||
- **FastJSON 2.0.21** - JSON处理
|
||||
- **EasyExcel 4.0.3 & EasyPOI 4.5.0** - Excel处理
|
||||
- **Apache HttpClient 4.5.13** - HTTP客户端
|
||||
- **Google Guava 33.3.1** - 集合工具
|
||||
|
||||
## 开发注意事项
|
||||
## 重要的文件路径
|
||||
|
||||
- **主要工作目录**:`202504-Wms-MengYang-tp/wms_serve_mengyang/`
|
||||
- **日志存储**:`wms_log/` (按日期和级别分类)
|
||||
- **数据库脚本**:`db/wms_mengyang_tp.sql`
|
||||
- **MyBatis映射**:`src/main/resources/mapper/`
|
||||
|
||||
## 常见开发任务
|
||||
|
||||
### 启动应用
|
||||
```bash
|
||||
cd 202504-Wms-MengYang-tp/wms_serve_mengyang
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
### 查看日志
|
||||
```bash
|
||||
# 查看今天的info日志
|
||||
tail -f wms_log/info/$(date +%Y-%m-%d)/$(date +%Y-%m-%d).0.log
|
||||
|
||||
# 查看今天的error日志
|
||||
tail -f wms_log/error/$(date +%Y-%m-%d)/$(date +%Y-%m-%d).0.log
|
||||
```
|
||||
|
||||
### 数据库操作
|
||||
- 使用MyBatis-Plus进行ORM操作
|
||||
- 支持批量操作和事务处理
|
||||
- 驼峰命名自动映射(`map-underscore-to-camel-case: true`)
|
||||
- ID生成策略:`assign_id`
|
||||
|
||||
## 系统集成要点
|
||||
|
||||
### WCS系统集成(托盘库专用)
|
||||
- TCP和HTTP双协议支持
|
||||
- **托盘堆垛机**任务调度和状态同步
|
||||
- **托盘载具**管理和追踪
|
||||
|
||||
### 任务调度系统
|
||||
- 基于Quartz的定时任务框架
|
||||
- 关键执行器针对托盘库场景优化
|
||||
- 任务状态实时监控
|
||||
|
||||
### Excel处理
|
||||
- 后端:EasyExcel 4.0.3 + EasyPOI 4.5.0
|
||||
- 支持托盘库相关的业务数据导入导出
|
||||
- 模板位置:`excel/easypoi/excelTemplate/`
|
||||
|
||||
## TP与BOX版本的差异
|
||||
|
||||
### 主要区别
|
||||
1. **数据库schema**:使用`wms_mengyang_tp`数据库
|
||||
2. **存储策略算法**:针对托盘存储特点优化
|
||||
3. **设备集成**:对接托盘库专用设备
|
||||
4. **业务规则**:托盘的尺寸、重量、堆叠规则不同
|
||||
|
||||
### 开发注意事项
|
||||
- 在开发新功能时,注意区分TP和BOX版本的业务差异
|
||||
- 深度策略算法需要考虑托盘的物理特性
|
||||
- WCS集成需要适配托盘库的设备类型
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
1. **端口冲突**:确认12315端口未被占用
|
||||
2. **数据库连接**:检查MySQL服务状态和TP数据库配置
|
||||
3. **版本混淆**:确认操作的是TP版本而非BOX版本
|
||||
4. **日志分析**:按级别查看对应日志目录
|
||||
|
||||
### 调试技巧
|
||||
- 使用`RequestLogFilter`查看API请求日志
|
||||
- 通过`WmsControllerExceptionHandler`统一异常处理
|
||||
- 检查定时任务执行状态:查看`TAppJobs`表
|
||||
- 注意区分TP和BOX版本的业务逻辑差异
|
||||
|
||||
## 开发规范
|
||||
|
||||
### 代码规范
|
||||
- 使用Lombok注解减少样板代码
|
||||
|
|
@ -101,43 +207,10 @@ mvn clean package -Dmaven.test.skip=true
|
|||
- 枚举类管理常量值
|
||||
- 接口-实现分离的服务层设计
|
||||
|
||||
### 数据库操作
|
||||
- 使用MyBatis-Plus进行ORM操作
|
||||
- 支持批量操作和事务处理
|
||||
- 驼峰命名自动映射
|
||||
- ID生成策略:assign_id
|
||||
|
||||
### 错误处理
|
||||
- 统一异常处理器:`WmsControllerExceptionHandler`
|
||||
- 标准化错误码:`WmsApiResponseCodeEnums`
|
||||
- 请求日志过滤器:`RequestLogFilter`
|
||||
|
||||
### Excel处理
|
||||
系统支持完整的Excel导入导出功能:
|
||||
- 货物信息、产品信息、库存信息等业务数据
|
||||
- 使用EasyExcel和EasyPOI双重支持
|
||||
- 模板位置:`excel/easypoi/excelTemplate/`
|
||||
|
||||
## 外部系统集成
|
||||
|
||||
### WCS系统集成
|
||||
- 堆垛机任务调度
|
||||
- 载具管理(托盘和料箱)
|
||||
- TCP/HTTP通信协议
|
||||
|
||||
### MES系统对接
|
||||
- 制造执行系统数据交换
|
||||
- 生产任务状态同步
|
||||
|
||||
## 测试说明
|
||||
|
||||
项目配置中跳过了单元测试执行(`maven-surefire-plugin.skip=true`),在开发新功能时建议:
|
||||
### 测试建议
|
||||
项目配置跳过单元测试,建议:
|
||||
1. 先实现功能代码
|
||||
2. 使用Postman等工具进行API测试
|
||||
3. 检查数据库数据状态
|
||||
3. 检查托盘库相关的数据库数据状态
|
||||
4. 验证定时任务执行情况
|
||||
|
||||
## Claude交互指南
|
||||
|
||||
### AI助手通用记录
|
||||
- 说中文,think hard
|
||||
5. 测试WCS设备集成功能
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
### MyWMS接口测试
|
||||
### 基础配置
|
||||
@baseUrl = http://localhost:12315
|
||||
|
||||
### 1. 入库订单接口
|
||||
POST {{baseUrl}}/mywms/orderIn
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"taskId": "testOrderId1",
|
||||
"vehicleNo": "1001"
|
||||
}
|
||||
|
||||
### 2. 出库订单接口
|
||||
POST {{baseUrl}}/mywms/orderOut
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"taskId": "testOrderId1",
|
||||
"vehicleNo": "1001"
|
||||
}
|
||||
|
||||
### 3. 库存查询接口 - 仅按载具查询
|
||||
POST {{baseUrl}}/mywms/stock
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"requestId": "testOrderId1",
|
||||
"details": [
|
||||
{
|
||||
"vehicleNo": "1001"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### 4. 库存查询接口 - 仅按库位查询
|
||||
POST {{baseUrl}}/mywms/stock
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"requestId": "testOrderId2",
|
||||
"details": [
|
||||
{
|
||||
"locationId": "A01-01-01-02"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### 5. 检查是否允许投料
|
||||
GET {{baseUrl}}/mywms/allowFeed
|
||||
|
||||
### 测试数据说明
|
||||
# 1. orderIn: 入库订单接口,需要taskId和vehicleNo
|
||||
# 2. orderOut: 出库订单接口,需要taskId和vehicleNo
|
||||
# 3. stock: 库存查询接口,需要requestId和details数组
|
||||
# - details中可以包含vehicleNo和/或locationId
|
||||
# 4. allowFeed: 查询当前系统是否允许投料操作(GET请求)
|
||||
|
||||
### 响应格式说明
|
||||
# 所有接口都返回MyWmsResponse格式:
|
||||
# {
|
||||
# "code": 200, // 响应码
|
||||
# "message": "操作成功", // 响应消息
|
||||
# "data": {}, // 具体数据
|
||||
# "success": true // 是否成功
|
||||
# }
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
### TaskController接口测试 - WMS任务控制接口
|
||||
### 基础配置
|
||||
@baseUrl = http://localhost:12315
|
||||
|
||||
### 1. WCS请求载具入库
|
||||
POST {{baseUrl}}/wms/task/wcsRequestVehicleIn
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"origin": "R1",
|
||||
"vehicleNo": "1001",
|
||||
"codeMessage": "test",
|
||||
"remark": "载具入库测试"
|
||||
}
|
||||
|
||||
### 2. 发送任务结果 - 任务完成
|
||||
POST {{baseUrl}}/wms/task/sendTaskResult
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"taskId": "TASK202507240001",
|
||||
"taskStatus": 100,
|
||||
"vehicleNo": "1001",
|
||||
"destination": "A01-01-01-02",
|
||||
"message": "任务执行成功"
|
||||
}
|
||||
|
||||
### 测试数据说明
|
||||
# 1. wcsRequestVehicleIn: WCS请求载具入库
|
||||
# - origin: 点位(必填)
|
||||
# - vehicleNo: 载具信息(必填)
|
||||
# - codeMessage: 条码信息(可选)
|
||||
# - remark: 备注(可选)
|
||||
|
||||
# 2. sendTaskResult: WCS反馈任务执行结果
|
||||
# - taskId: 任务ID(必填)
|
||||
# - taskStatus: 任务状态(必填)
|
||||
# * 0: 等待执行
|
||||
# * 1: 执行中
|
||||
# * 2: 执行完成
|
||||
# * 3: 执行失败
|
||||
# - vehicleNo: 载具号(必填)
|
||||
# - destination: 终点(可选)
|
||||
# - message: 信息(可选)
|
||||
|
||||
### 响应格式说明
|
||||
# wcsRequestVehicleIn返回WcsVehicleInResponse:
|
||||
# {
|
||||
# "success": true,
|
||||
# "code": "SUCCESS",
|
||||
# "message": "请求成功",
|
||||
# "data": {}
|
||||
# }
|
||||
|
||||
# sendTaskResult返回BaseWcsApiResponse:
|
||||
# {
|
||||
# "success": true,
|
||||
# "code": "SUCCESS",
|
||||
# "message": "任务结果接收成功"
|
||||
# }
|
||||
|
|
@ -9,10 +9,10 @@
|
|||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com</groupId>
|
||||
<artifactId>dev_wms_serve</artifactId>
|
||||
<artifactId>wms_serve_mengyang_tp</artifactId>
|
||||
<version>3.2</version>
|
||||
<name>dev_wms_serve</name>
|
||||
<description>dev_wms_serve</description>
|
||||
<name>wms_serve_mengyang_tp</name>
|
||||
<description>wms_serve_mengyang_tp</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
|
|
@ -162,6 +162,15 @@
|
|||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>21</source>
|
||||
<target>21</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.wms_main.dao.*;
|
|||
import com.wms_main.model.dto.request.mywms.OrderInCBReq;
|
||||
import com.wms_main.model.dto.request.mywms.OrderOutCBReq;
|
||||
import com.wms_main.model.dto.response.mes.MesApiResponse;
|
||||
import com.wms_main.model.dto.response.mywms.MyWmsResponse;
|
||||
import com.wms_main.model.po.*;
|
||||
import com.wms_main.repository.utils.ConvertUtils;
|
||||
import com.wms_main.repository.utils.StringUtils;
|
||||
|
|
@ -26,7 +25,6 @@ import java.time.LocalDateTime;
|
|||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.wms_main.repository.utils.ConvertUtils.convertDestinationToPoint;
|
||||
|
||||
/**
|
||||
* 服务实现
|
||||
|
|
@ -60,11 +58,6 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
|
|||
*/
|
||||
private final ITAppTaskBakService appTaskBakService;
|
||||
|
||||
private final ITAppWcsTaskBakService appWcsTaskBakService;
|
||||
/**
|
||||
* 拣选任务服务
|
||||
*/
|
||||
private final ITAppPickTaskService appPickTaskService;
|
||||
/**
|
||||
* 设备服务
|
||||
*/
|
||||
|
|
@ -402,21 +395,21 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
|
|||
orderInCBReq.setResult(OrderInCBEnums.COMPLETE.getCode());
|
||||
orderInCBReq.setResultMessage("入库完成");
|
||||
|
||||
int times = 0;
|
||||
MesApiResponse response = null;
|
||||
do {
|
||||
Thread.sleep(15000L * times);
|
||||
response = externalApiService.invokeOrderInCB(orderInCBReq);
|
||||
times++;
|
||||
} while (response.getCode() != 0 && times <= 10);
|
||||
if (response.getCode() != 0) {
|
||||
log.error("[wms]上报失败");
|
||||
} else {
|
||||
log.info("[wms]上报成功");
|
||||
}
|
||||
if (!appOrderInService.removeById(orderIn.getRecordId())) {
|
||||
log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
|
||||
}
|
||||
// int times = 0;
|
||||
// MesApiResponse response = null;
|
||||
// do {
|
||||
// Thread.sleep(15000L * times);
|
||||
// response = externalApiService.invokeOrderInCB(orderInCBReq);
|
||||
// times++;
|
||||
// } while (response.getCode() != 0 && times <= 10);
|
||||
// if (response.getCode() != 0) {
|
||||
// log.error("[wms]上报失败");
|
||||
// } else {
|
||||
// log.info("[wms]上报成功");
|
||||
// }
|
||||
// if (!appOrderInService.removeById(orderIn.getRecordId())) {
|
||||
// log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
|
||||
// }
|
||||
TAppVehicle vehicle = new TAppVehicle();
|
||||
vehicle.setVehicleId(wmsTask.getVehicleId());
|
||||
vehicle.setVehicleStatus(WmsVehicleStatusEnums.ON.getCode());
|
||||
|
|
@ -534,27 +527,26 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
|
|||
appOrderOutService.removeBatchByIds(orderOuts);
|
||||
}
|
||||
}
|
||||
for (TAppOrderOut orderOut : orderOuts) {
|
||||
List<TAppTask> appTasks = vehicleIdToTaskMap.get(vehicleId);
|
||||
OrderOutCBReq orderOutCBReq = new OrderOutCBReq();
|
||||
orderOutCBReq.setTaskId(orderOut.getOrderId());
|
||||
orderOutCBReq.setVehicleNo(vehicleId);
|
||||
orderOutCBReq.setResult(OrderOutCBEnums.COMPLETE.getCode());
|
||||
orderOutCBReq.setResultMessage("出库完成");
|
||||
// for (TAppOrderOut orderOut : orderOuts) {
|
||||
// OrderOutCBReq orderOutCBReq = new OrderOutCBReq();
|
||||
// orderOutCBReq.setTaskId(orderOut.getOrderId());
|
||||
// orderOutCBReq.setVehicleNo(vehicleId);
|
||||
// orderOutCBReq.setResult(OrderOutCBEnums.COMPLETE.getCode());
|
||||
// orderOutCBReq.setResultMessage("出库完成");
|
||||
|
||||
int times = 0;
|
||||
MesApiResponse response = null;
|
||||
do {
|
||||
response = externalApiService.invokeOrderOutCB(orderOutCBReq);
|
||||
times++;
|
||||
Thread.sleep(15000L * times);
|
||||
} while (response.getCode() != 0 && times <= 10);
|
||||
if (response.getCode() != 0) {
|
||||
log.error("[WMS]上报失败");
|
||||
} else {
|
||||
log.info("[WMS]上报成功");
|
||||
}
|
||||
}
|
||||
// int times = 0;
|
||||
// MesApiResponse response = null;
|
||||
// do {
|
||||
// response = externalApiService.invokeOrderOutCB(orderOutCBReq);
|
||||
// times++;
|
||||
// Thread.sleep(15000L * times);
|
||||
// } while (response.getCode() != 0 && times <= 10);
|
||||
// if (response.getCode() != 0) {
|
||||
// log.error("[WMS]上报失败");
|
||||
// } else {
|
||||
// log.info("[WMS]上报成功");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
263
202504-Wms-MengYang-tp/wms_web_mengyang/CLAUDE.md
Normal file
263
202504-Wms-MengYang-tp/wms_web_mengyang/CLAUDE.md
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## 项目概述
|
||||
|
||||
这是宝应梦阳WMS前端项目(TP托盘库版本),基于Vue 3和Element Plus开发的现代化Web管理界面,专门用于托盘库存储场景的仓库管理系统操作和监控。
|
||||
|
||||
## 项目特点
|
||||
|
||||
**TP托盘库版本特性**
|
||||
- 专为托盘存储场景设计的UI界面
|
||||
- 支持大型货物的托盘化存储管理操作
|
||||
- 与BOX料箱库版本在业务功能上有所差异
|
||||
- 针对托盘库的专用业务流程和界面优化
|
||||
|
||||
## 开发环境设置
|
||||
|
||||
### 基本命令
|
||||
```bash
|
||||
# 进入项目目录
|
||||
cd 202504-Wms-MengYang-tp/wms_web_mengyang
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# 启动开发服务器
|
||||
npm run serve
|
||||
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
|
||||
# 代码检查和修复
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### 开发配置
|
||||
- **开发端口**:12306
|
||||
- **路由模式**:Hash路由 (`createWebHashHistory`)
|
||||
- **默认路由**:登录页面 (`/`) -> 主页 (`/home`) -> 库存页面 (`/stock`)
|
||||
- **代理配置**:Microsoft OAuth认证代理
|
||||
|
||||
### 与BOX版本的区别
|
||||
- 项目结构和技术栈基本相同
|
||||
- **主要差异在业务逻辑**:托盘存储相关的界面和交互
|
||||
- **后端API对接**:调用TP版本后端的专用接口
|
||||
- **数据展示**:针对托盘库的数据字段和格式
|
||||
|
||||
## 技术栈
|
||||
|
||||
### 核心框架
|
||||
- **Vue 3.2.13** - 前端框架(Composition API)
|
||||
- **Vue Router 4.0.3** - 路由管理
|
||||
- **Vuex 4.0.0** - 状态管理
|
||||
- **Element Plus 2.4.0** - UI组件库
|
||||
|
||||
### 主要依赖
|
||||
- **Axios 1.3.3** - HTTP请求库
|
||||
- **Moment 2.29.4** - 日期处理
|
||||
- **XLSX 0.18.5** - Excel文件处理
|
||||
- **QRCode.vue 3.4.1** - 二维码生成
|
||||
- **Vue3-print-nb 0.1.4** - 打印功能
|
||||
- **File-saver 2.0.5** - 文件下载
|
||||
|
||||
### 开发工具
|
||||
- **Sass 1.83.4** - CSS预处理器
|
||||
- **Vue CLI 5.0** - 构建工具
|
||||
- **ESLint** - 代码质量检查(已关闭未使用变量警告)
|
||||
|
||||
## 项目架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
src/
|
||||
├── api/ # API接口封装(托盘库专用接口)
|
||||
├── assets/ # 静态资源
|
||||
├── components/ # 可复用组件
|
||||
├── constant/ # 常量配置(托盘库相关常量)
|
||||
├── excel/ # Excel上传组件(托盘库数据)
|
||||
├── http/ # HTTP请求配置
|
||||
├── layout/ # 业务页面组件(托盘库业务界面)
|
||||
├── print/ # 打印相关组件
|
||||
├── router/ # 路由配置
|
||||
├── store/ # Vuex状态管理
|
||||
├── styles/ # 全局样式
|
||||
├── utils/ # 工具函数
|
||||
└── views/ # 主要视图组件
|
||||
```
|
||||
|
||||
### 核心业务模块(托盘库专用)
|
||||
|
||||
#### 1. 托盘仓库作业 (`layout/`)
|
||||
**库存管理**
|
||||
- `stock.vue` - 托盘库存查询和管理
|
||||
- `inventory.vue` - 托盘库存盘点
|
||||
- `inventoryRecord.vue` - 盘点记录
|
||||
|
||||
**入出库作业**
|
||||
- `goodsIn.vue` - 托盘入库作业界面
|
||||
- `goodsOut.vue` - 托盘出库作业界面
|
||||
- `orderIn.vue` - 托盘入库单管理
|
||||
- `orderOut.vue` - 托盘出库单管理
|
||||
|
||||
**任务监控**
|
||||
- `taskMonitor.vue` - 托盘任务执行监控
|
||||
- `pickTaskMonitor.vue` - 托盘拣选任务监控
|
||||
- `inTaskRecord.vue` - 入库任务记录
|
||||
- `outTaskRecord.vue` - 出库任务记录
|
||||
|
||||
#### 2. 托盘基础数据管理
|
||||
- `goods.vue` - 托盘物料信息管理
|
||||
- `locationsTable.vue` - 托盘库位信息管理
|
||||
- `standSettings.vue` - 托盘站台(库口)设置
|
||||
- `vehicle.vue` - 托盘载具监控
|
||||
|
||||
#### 3. 托盘配料系统
|
||||
- `kitting.vue` - 托盘配料作业
|
||||
- `kittingList.vue` - 托盘配料单管理
|
||||
- `kittingRelation.vue` - 托盘配料关系配置
|
||||
- `clcKanban.vue` - 托盘需求看板
|
||||
|
||||
#### 4. 系统管理
|
||||
- `wmsConfigNew.vue` - 托盘库系统配置
|
||||
- `role_user.vue` - 用户角色管理
|
||||
- `role_permission.vue` - 权限管理
|
||||
- `wmsLog.vue` - 系统日志
|
||||
|
||||
### API接口模块 (`api/`)
|
||||
|
||||
**托盘库核心业务接口**
|
||||
- `goods.js` - 托盘物料信息API
|
||||
- `stock.js` - 托盘库存相关API
|
||||
- `task.js` - 托盘任务管理API
|
||||
- `location.js` - 托盘库位管理API
|
||||
|
||||
**托盘作业流程接口**
|
||||
- `orderIn.js` - 托盘入库订单API
|
||||
- `orderOut.js` - 托盘出库订单API
|
||||
- `kateWork.js` - 托盘配料作业API
|
||||
|
||||
**系统功能接口**
|
||||
- `login.js` - 登录认证API
|
||||
- `user.js` - 用户管理API
|
||||
- `config.js` - 托盘库系统配置API
|
||||
- `excel.js` - 托盘库Excel处理API
|
||||
|
||||
### 公共组件 (`components/`)
|
||||
- `sideMenu.vue` - 侧边菜单导航(托盘库功能菜单)
|
||||
- `appTag.vue` - 标签页管理
|
||||
|
||||
### 工具模块 (`utils/`)
|
||||
- `dateUtils.js` - 日期处理工具
|
||||
- `formatter.js` - 数据格式化(托盘库数据格式)
|
||||
- `hashUtils.js` - 哈希计算
|
||||
- `stringUtils.js` - 字符串处理
|
||||
- `loading.js` - 加载状态管理
|
||||
- `myMessageBox.js` - 消息提示封装
|
||||
|
||||
## 托盘库特色功能
|
||||
|
||||
### 托盘存储特点
|
||||
- **大型货物管理**:支持重型和大尺寸货物的界面展示
|
||||
- **托盘堆叠显示**:可视化托盘堆叠状态和高度限制
|
||||
- **存取路径优化**:界面显示最优存取路径建议
|
||||
- **托盘载具追踪**:实时显示托盘在系统中的位置
|
||||
|
||||
### 与BOX版本的界面差异
|
||||
1. **数据字段不同**:托盘尺寸、重量、堆叠层数等专用字段
|
||||
2. **操作流程优化**:针对托盘存储的特殊操作步骤
|
||||
3. **监控界面**:托盘堆垛机状态、托盘载具位置等专用监控
|
||||
4. **报表格式**:托盘库专用的统计和报表格式
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
### 路由配置
|
||||
- 使用Hash路由模式,兼容性更好
|
||||
- 实现了路由守卫,未登录用户自动跳转登录页
|
||||
- 登录状态通过`sessionStorage`中的`user`字段判断
|
||||
|
||||
### 状态管理
|
||||
- 使用Vuex进行全局状态管理
|
||||
- 主要管理用户信息、菜单权限、标签页状态
|
||||
- **托盘库专用状态**:托盘载具状态、堆垛机状态等
|
||||
|
||||
### HTTP请求
|
||||
- 统一使用Axios进行API调用
|
||||
- 请求封装在`/http/request.js`中
|
||||
- API接口按托盘库业务模块分类组织
|
||||
- **注意**:对接TP版本后端API(端口12315)
|
||||
|
||||
### Excel处理(托盘库数据)
|
||||
- 支持托盘库专用Excel模板的上传和解析
|
||||
- 专门的Excel上传组件位于`excel/`目录
|
||||
- 支持托盘物料、库存、任务等数据的Excel导入导出
|
||||
|
||||
### 打印功能
|
||||
- 使用`vue3-print-nb`实现打印功能
|
||||
- 打印组件位于`print/`目录
|
||||
- **托盘库专用**:托盘标签、任务单等打印格式
|
||||
|
||||
### 样式规范
|
||||
- 使用Sass预处理器
|
||||
- 全局样式文件:`styles/index.scss`
|
||||
- 响应式设计,支持不同屏幕尺寸
|
||||
- **托盘库界面优化**:适配托盘库的数据展示需求
|
||||
|
||||
## 常见开发任务
|
||||
|
||||
### 添加托盘库新页面
|
||||
1. 在`layout/`目录创建Vue组件
|
||||
2. 在`router/index.js`中配置路由
|
||||
3. 如需API调用,在`api/`目录创建对应的托盘库接口文件
|
||||
4. 更新侧边菜单配置
|
||||
5. **注意**:考虑托盘库的业务特点和数据格式
|
||||
|
||||
### 托盘库Excel上传功能
|
||||
1. 参考`excel/`目录下的现有组件
|
||||
2. 使用Element Plus的上传组件
|
||||
3. 后端TP版本API处理托盘Excel数据解析
|
||||
4. **关键**:使用托盘库专用的Excel模板格式
|
||||
|
||||
### 新增托盘库API接口
|
||||
1. 在`api/`目录按模块创建文件
|
||||
2. 使用`@/http/request`进行请求封装
|
||||
3. 导出接口函数供组件使用
|
||||
4. **重要**:确保对接TP版本后端API
|
||||
|
||||
### 调试和测试
|
||||
- 使用Vue DevTools检查组件状态
|
||||
- 浏览器开发者工具调试网络请求
|
||||
- ESLint检查代码质量
|
||||
- 在不同浏览器中测试兼容性
|
||||
- **托盘库专用测试**:验证托盘数据格式和业务逻辑
|
||||
|
||||
## 后端API集成
|
||||
|
||||
### 默认后端地址
|
||||
根据当前配置,后端TP版本API地址需要在`http/request.js`中配置:
|
||||
- 开发环境:`http://localhost:12315`(TP版本后端)
|
||||
- 生产环境:`http://10.18.58.21:12315`
|
||||
|
||||
### 认证机制
|
||||
- 支持Microsoft OAuth认证代理
|
||||
- 登录状态存储在`sessionStorage`中
|
||||
- 路由守卫自动验证用户登录状态
|
||||
|
||||
## 开发建议
|
||||
|
||||
### TP与BOX版本协同开发
|
||||
1. **代码复用**:公共组件和工具函数可以复用
|
||||
2. **业务差异**:注意托盘库和料箱库的业务逻辑差异
|
||||
3. **数据格式**:确保使用正确的数据字段和格式
|
||||
4. **API对接**:确认对接的是TP版本后端而非BOX版本
|
||||
|
||||
### 性能优化
|
||||
- 托盘库数据量通常较大,注意列表分页和懒加载
|
||||
- 图表和监控界面的实时更新优化
|
||||
- Excel处理时的内存管理
|
||||
|
||||
### 用户体验
|
||||
- 托盘库操作相对复杂,提供清晰的操作指引
|
||||
- 错误提示和状态反馈要及时准确
|
||||
- 支持键盘快捷操作,提高操作效率
|
||||
Loading…
Reference in New Issue
Block a user