diff --git a/.gitignore b/.gitignore index ef84ab63..d63cd7b2 100644 --- a/.gitignore +++ b/.gitignore @@ -52,4 +52,9 @@ application-my.yaml /nl-ui-app/unpackage/ .DS_Store -**/.DS_Store \ No newline at end of file +**/.DS_Store +/.superpowers/ + + +# Local Git worktrees +.worktrees/ diff --git a/OAuth2-Token接口使用文档.md b/OAuth2-Token接口使用文档.md new file mode 100644 index 00000000..afc3bf58 --- /dev/null +++ b/OAuth2-Token接口使用文档.md @@ -0,0 +1,179 @@ +# OAuth2 Token 接口使用文档 + +## 接口地址 + +``` +POST http://{域名}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +``` + +## 通用规则 + +- 所有请求**必须**携带 HTTP Basic Auth 请求头:`Authorization: Basic base64(client_id:secret)` +- 响应格式:`{"code":0,"msg":"...","data":{...}}` +- `code=0` 表示成功 +- 默认客户端:`client_id=default`、`secret=admin123` + +--- + +## 支持的授权模式 + +### 1. 客户端模式 `client_credentials`(外部系统调用推荐) + +**适用场景**:机器对机器调用,无需用户登录。 + +```bash +curl -X POST "http://localhost:48080/system/oauth2/token" \ + -u "default:admin123" \ + -d "grant_type=client_credentials" +``` + +参数: + +| 参数 | 必填 | 说明 | +|------|------|------| +| `grant_type` | 是 | 固定值 `client_credentials` | +| `scope` | 否 | 授权范围,多个用空格分隔,如 `read write` | + +成功响应: + +```json +{ + "code": 0, + "data": { + "access_token": "a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "refresh_token": "r1r2r3r4-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "expires_in": 7200, + "token_type": "bearer", + "scope": "read write", + "user_id": 0 + } +} +``` + +--- + +### 2. 密码模式 `password` + +**适用场景**:用户直接用账号密码换取 token(如移动端 App 登录)。 + +```bash +curl -X POST "http://localhost:48080/system/oauth2/token" \ + -u "default:admin123" \ + -d "grant_type=password" \ + -d "username=admin" \ + -d "password=admin123" +``` + +参数: + +| 参数 | 必填 | 说明 | +|------|------|------| +| `grant_type` | 是 | 固定值 `password` | +| `username` | 是 | 用户账号 | +| `password` | 是 | 用户密码 | +| `scope` | 否 | 授权范围,多个用空格分隔 | + +--- + +### 3. 授权码模式 `authorization_code` + +**适用场景**:第三方应用需要用户授权后才能访问用户数据(如 SSO 单点登录)。 + +分两步走: + +**第一步**:用户浏览器访问授权页,拿到 `code` + +```bash +浏览器访问: +http://localhost:48080/system/oauth2/authorize?clientId=default +``` + +用户确认授权后,回调地址会带上 `code` 参数。 + +**第二步**:用 `code` 换 token + +```bash +curl -X POST "http://localhost:48080/system/oauth2/token" \ + -u "default:admin123" \ + -d "grant_type=authorization_code" \ + -d "code=xxxx" \ + -d "redirect_uri=https://回调地址" \ + -d "state=1" +``` + +参数: + +| 参数 | 必填 | 说明 | +|------|------|------| +| `grant_type` | 是 | 固定值 `authorization_code` | +| `code` | 是 | 第一步获取的授权码 | +| `redirect_uri` | 是 | 必须与第一步的回调地址一致 | +| `state` | 否 | 透传的状态值,用于防 CSRF | + +--- + +### 4. 刷新令牌 `refresh_token` + +**适用场景**:token 快过期时,用 `refresh_token` 换新 token,无需重新登录。 + +```bash +curl -X POST "http://localhost:48080/system/oauth2/token" \ + -u "default:admin123" \ + -d "grant_type=refresh_token" \ + -d "refresh_token=r1r2r3r4-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +``` + +参数: + +| 参数 | 必填 | 说明 | +|------|------|------| +| `grant_type` | 是 | 固定值 `refresh_token` | +| `refresh_token` | 是 | 之前获取的 refresh_token | + +--- + +## 其他接口 + +### 校验 Token + +```bash +curl -X POST "http://localhost:48080/system/oauth2/check-token" \ + -u "default:admin123" \ + -d "token=要校验的access_token" +``` + +### 撤销 Token(登出) + +```bash +curl -X DELETE "http://localhost:48080/system/oauth2/token?token=要撤销的access_token" \ + -u "default:admin123" +``` + +--- + +## 四种模式对比 + +| 模式 | grant_type 值 | 是否需用户参与 | 适用场景 | +|------|-------------|-------------|---------| +| 客户端模式 | `client_credentials` | 否 | 外部系统调用、定时任务、机器间通信 | +| 密码模式 | `password` | 是(提供账号密码) | 移动端 App 登录、信任的客户端 | +| 授权码模式 | `authorization_code` | 是(浏览器确认授权) | 第三方应用 SSO、开放平台 | +| 刷新令牌 | `refresh_token` | 否 | Token 续期,配合以上任意模式使用 | + +--- + +## 外部系统完整调用流程 + +``` +① 你在后台创建 OAuth2 客户端,拿到 client_id + secret + │ +② 外部系统用 client_credentials 模式换 token + curl -u "client_id:secret" -d "grant_type=client_credentials" + │ +③ 拿到 access_token,之后每个请求带上 + curl -H "Authorization: Bearer " /admin-api/xxx + │ +④ token 过期前,用 refresh_token 续期 + curl -u "client_id:secret" -d "grant_type=refresh_token" -d "refresh_token=xxx" +``` diff --git a/docs/superpowers/plans/2026-07-14-task-core-implementation.md b/docs/superpowers/plans/2026-07-14-task-core-implementation.md index 504166a1..2a4934a5 100644 --- a/docs/superpowers/plans/2026-07-14-task-core-implementation.md +++ b/docs/superpowers/plans/2026-07-14-task-core-implementation.md @@ -793,7 +793,7 @@ git commit -m "feat: 新增 TransportTaskStatusClient 同步 HTTP 回调客户 ```java package cn.code.nl.module.task.mq; -import cn.code.nl.module.task.mq.message.TaskEventMessage; +import cn.code.nl.module.task.message.TaskEventMessage; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.stereotype.Component; @@ -977,7 +977,7 @@ import cn.code.nl.module.task.client.TransportTaskStatusClient; import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO; import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper; import cn.code.nl.module.task.dto.AcsFeedbackReqDTO; -import cn.code.nl.module.task.mq.message.TaskEventMessage; +import cn.code.nl.module.task.message.TaskEventMessage; import cn.code.nl.module.task.dto.TaskStatusCallbackReqDTO; import cn.code.nl.module.task.dto.TaskStatusCallbackRespDTO; import cn.code.nl.module.task.enums.CallbackStatusEnum; diff --git a/docs/superpowers/plans/2026-07-15-task-operation-refactor.md b/docs/superpowers/plans/2026-07-15-task-operation-refactor.md index d2bf1e46..12cf48f7 100644 --- a/docs/superpowers/plans/2026-07-15-task-operation-refactor.md +++ b/docs/superpowers/plans/2026-07-15-task-operation-refactor.md @@ -202,7 +202,7 @@ import cn.code.nl.module.task.dto.AcsFeedbackReqDTO; import cn.code.nl.module.task.dto.TaskStatusCallbackReqDTO; import cn.code.nl.module.task.enums.TaskEventTypeEnum; import cn.code.nl.module.task.enums.TaskOperationTypeEnum; -import cn.code.nl.module.task.mq.message.TaskEventMessage; +import cn.code.nl.module.task.message.TaskEventMessage; import cn.code.nl.module.task.mq.producer.TaskEventProducer; import cn.hutool.core.util.StrUtil; import jakarta.annotation.PostConstruct; diff --git a/docs/superpowers/plans/2026-07-22-outbound-create-plan.md b/docs/superpowers/plans/2026-07-22-outbound-create-plan.md new file mode 100644 index 00000000..81aa2718 --- /dev/null +++ b/docs/superpowers/plans/2026-07-22-outbound-create-plan.md @@ -0,0 +1,410 @@ +# 出库单新增功能实现计划 + +> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。 + +**目标:** 按确认的布局实现出库单新增页,通过库存箱号展开全部可用子卷或手工新增物料汇总,并事务保存 `wms_iostorinv` 主表和 `wms_iostorinvdtl` 明细。 + +**架构:** 前端由主弹窗、库存选择弹窗、手工汇总弹窗组成,页面只维护现有表字段和临时展示字段。后端提供可用库存查询/箱号展开接口与聚合创建接口;聚合服务调用 base 编码 API、重新计算汇总值,并在一个事务内写入主表和明细。 + +**技术栈:** Java 17、Spring Boot、MyBatis XML、OpenFeign、Vue 3、TypeScript、Ant Design Vue Next、Vben Form、Vxe Grid、Vitest + +--- + +## 文件结构 + +### 后端 + +- 修改 `nl-module-wms/nl-module-wms-server/pom.xml`:引入 `nl-module-base-api`。 +- 创建 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/rpc/config/RpcConfiguration.java`:注册 `CodeGenApi` Feign 客户端。 +- 创建 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvCreateReqVO.java`:聚合创建请求及内部明细对象。 +- 创建 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/AvailableInventoryPageReqVO.java`:库存筛选与分页参数。 +- 创建 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/AvailableInventoryRespVO.java`:库存与页面展示结果。 +- 创建 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/ExpandAvailableInventoryReqVO.java`:仓库和已选箱号集合。 +- 修改 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinvdtl/IostorinvDtlMapper.java`:声明库存查询与按箱号展开方法。 +- 修改 `nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinvdtl/IostorinvDtlMapper.xml`:实现跨仓库结构和组盘库存的 SQL。 +- 修改 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvService.java`:声明库存查询、展开和聚合创建方法。 +- 修改 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceImpl.java`:实现校验、编码生成、汇总和事务写入。 +- 修改 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/IostorInvController.java`:暴露三个管理端接口。 +- 修改 `nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/enums/ErrorCodeConstants.java`:增加编码和库存失效错误码。 +- 创建 `nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceLocalSpringTest.java`:Spring 集成测试。 + +### 前端 + +- 修改 `nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/iostorinv/index.ts`:增加聚合请求、库存结果类型和接口函数。 +- 创建 `nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/detail-summary.ts`:纯函数计算明细数、总重量和去重键。 +- 创建 `nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/detail-summary.test.ts`:汇总联动的红绿测试。 +- 创建 `nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/inventory-select.vue`:库存筛选、多选和确认展开。 +- 创建 `nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/manual-detail.vue`:物料汇总新增。 +- 修改 `nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/form.vue`:实现确认布局、明细联动和聚合提交。 + +--- + +## 任务 1:建立后端请求契约与 RPC 依赖 + +- [ ] **步骤 1:先创建 Spring 集成测试骨架并验证当前编译失败** + +在 `IostorInvServiceLocalSpringTest.java` 中使用 `@SpringBootTest`、`@ActiveProfiles("local")` 和 `@Resource IostorInvService`,先引用尚不存在的 `IostorInvCreateReqVO` 与 `createOutbound`: + +```java +@SpringBootTest +@ActiveProfiles("local") +class IostorInvServiceLocalSpringTest { + @Resource + private IostorInvService iostorInvService; + + @Test + void createOutboundRejectsEmptyDetails() { + IostorInvCreateReqVO reqVO = new IostorInvCreateReqVO(); + Assertions.assertThrows(ConstraintViolationException.class, + () -> iostorInvService.createOutbound(reqVO)); + } +} +``` + +运行: + +```bash +mvn -pl nl-module-wms/nl-module-wms-server -am -DskipTests compile +``` + +预期:FAIL,提示 `IostorInvCreateReqVO` 或 `createOutbound` 不存在。 + +- [ ] **步骤 2:增加 base API 依赖和 Feign 注册** + +在 WMS server 的 `pom.xml` 增加: + +```xml + + cn.nl.cloud + nl-module-base-api + ${revision} + +``` + +创建 `RpcConfiguration`,使用 `@Configuration(value = "wmsRpcConfiguration", proxyBeanMethods = false)` 与 `@EnableFeignClients(clients = CodeGenApi.class)`。 + +- [ ] **步骤 3:创建带注解校验的聚合请求对象** + +`IostorInvCreateReqVO` 顶层包含 `@NotEmpty billType`、`@NotEmpty storId`、`@NotNull bizDate`、`remark`、`@NotEmpty @Valid List details`;内部 `Detail` 包含: + +```java +@NotEmpty(message = "物料编码不能为空") +private String materialCode; +private String materialId; +private String pcsn; +@NotNull(message = "出库重量不能为空") +@DecimalMin(value = "0.001", message = "出库重量必须大于0") +private BigDecimal planQty; +private String qtyUnitId; +private String qtyUnitName; +private String sourceBillCode; +private String sourceBillType; +private String sourceBilldtlId; +private String remark; +``` + +不接收 `billCode`、`billStatus`、`detailCount`、`totalWeight` 和 `seqNo`,这些字段全部由服务端生成。 + +- [ ] **步骤 4:声明 Service 方法并验证测试从编译失败进入校验失败/通过** + +```java +@Validated +public interface IostorInvService { + String createOutbound(@Valid IostorInvCreateReqVO reqVO); +} +``` + +运行: + +```bash +mvn -pl nl-module-wms/nl-module-wms-server -am -Dtest=IostorInvServiceLocalSpringTest -Dsurefire.failIfNoSpecifiedTests=false test +``` + +预期:测试能够启动且空请求因参数校验被拒绝;若 local 数据源不可用,保留测试并记录环境阻塞,继续用编译验证生产契约。 + +- [ ] **步骤 5:提交契约变更** + +```bash +git add nl-module-wms/nl-module-wms-server/pom.xml nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/rpc/config/RpcConfiguration.java nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvCreateReqVO.java nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvService.java nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceLocalSpringTest.java +git commit -m "feat: 定义出库单聚合创建契约" +``` + +## 任务 2:实现可用库存查询和按箱号展开 + +- [ ] **步骤 1:扩展失败测试,定义箱号展开行为** + +在集成测试准备同一仓库下箱号 `BOX-001` 的两个可用子卷和另一个仓库的同箱数据,断言: + +```java +List rows = iostorInvService.expandAvailableInventory( + "STOR-001", List.of("BOX-001", "BOX-001")); +Assertions.assertEquals(2, rows.size()); +Assertions.assertTrue(rows.stream().allMatch(row -> "BOX-001".equals(row.getVehicleCode()))); +``` + +运行指定测试,预期:FAIL,方法和响应对象尚不存在。 + +- [ ] **步骤 2:创建查询参数和响应对象** + +`AvailableInventoryPageReqVO extends PageParam`,字段为 `@NotEmpty storId`、`materialCode`、`vehicleCode`、`pcsn`;`AvailableInventoryRespVO` 使用库存现有字段:`vehicleCode`、`pcsn`、`materialId`、`materialCode`、`materialName`(仅返回展示)、`availableQty`、单位、来源字段及仓库标识。`ExpandAvailableInventoryReqVO` 包含 `@NotEmpty storId` 和 `@NotEmpty List vehicleCodes`。 + +- [ ] **步骤 3:声明 Mapper 方法** + +```java +PageResult selectAvailableInventoryPage(AvailableInventoryPageReqVO reqVO); + +List selectAvailableInventoryByVehicleCodes( + @Param("storId") String storId, + @Param("vehicleCodes") Collection vehicleCodes); +``` + +- [ ] **步骤 4:在 XML 实现统一库存 SQL** + +基础关联为 `wms_group_plate gp INNER JOIN wms_structattr sa ON sa.storagevehicle_code = gp.vehicle_code LEFT JOIN base_materialbase mb ON mb.material_id = gp.material_id AND mb.is_deleted = 0`,固定条件为 `sa.stor_id = #{storId}`、`gp.status = '可用'`、`gp.qty - gp.frozen_qty > 0` 和 WMS 两表 `is_deleted = 0`。分页查询增加物料、箱号、子卷号筛选;展开查询使用 `` 的箱号集合。结果中 `available_qty = gp.qty - gp.frozen_qty`,物料名称从 `mb.material_name` 返回但不写入明细表。 + +- [ ] **步骤 5:Service 对箱号去重后查询全部子卷** + +```java +List distinctVehicleCodes = vehicleCodes.stream().distinct().toList(); +return iostorinvDtlMapper.selectAvailableInventoryByVehicleCodes(storId, distinctVehicleCodes); +``` + +控制器提供: + +```java +@GetMapping("/availableInventoryPage") +public CommonResult> getAvailableInventoryPage( + @Valid AvailableInventoryPageReqVO reqVO) + +@PostMapping("/expandAvailableInventory") +public CommonResult> expandAvailableInventory( + @Valid @RequestBody ExpandAvailableInventoryReqVO reqVO) +``` + +- [ ] **步骤 6:运行集成测试和 Mapper 编译** + +```bash +mvn -pl nl-module-wms/nl-module-wms-server -am -Dtest=IostorInvServiceLocalSpringTest -Dsurefire.failIfNoSpecifiedTests=false test +``` + +预期:同箱两子卷全部返回、重复箱号不产生重复行、其他仓库数据不返回。 + +- [ ] **步骤 7:提交库存查询变更** + +```bash +git add nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinvdtl/IostorinvDtlMapper.java nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinvdtl/IostorinvDtlMapper.xml nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/IostorInvController.java nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceLocalSpringTest.java +git commit -m "feat: 支持按箱号展开可用库存子卷" +``` + +## 任务 3:实现主表与明细事务保存 + +- [ ] **步骤 1:补充失败测试** + +构造两条重量 `12.500`、`7.250` 的明细,创建后查询数据库并断言:主表 `ioType = "OUT"`、`billStatus = "生成"`、`detailCount = 2`、`totalWeight = 19.750`;明细序号为 1/2、`assignQty = 0`、`unassignQty = planQty`。测试请求不传任何汇总字段。 + +- [ ] **步骤 2:实现编码生成和事务写入** + +`createOutbound` 标记 `@Transactional(rollbackFor = Exception.class)`: + +1. 构造 `CodeGenerateReqDTO`,设置项目现有出入库规则编码 `IO_CODE`。 +2. 调用 `CodeGenApi.generate`,检查 `CommonResult.isSuccess()` 且编码非空;失败抛出中文业务异常。 +3. 手工逐字段创建 `IostorInvDO`,固定 `ioType = "OUT"`、`billStatus = "生成"`。 +4. 使用 `details.stream().map(Detail::getPlanQty).reduce(BigDecimal.ZERO, BigDecimal::add)` 计算总重量并设置明细数。 +5. 插入主表后,循环构造 `IostorinvDtlDO`,写入关联 ID、连续序号、物料、`pcsn`、计划重量、分配数量、单位、来源和备注。 + +- [ ] **步骤 3:增加控制器端点和错误码** + +```java +@PostMapping("/createOutbound") +@PreAuthorize("@ss.hasPermission('wms:iostor-inv:create')") +public CommonResult createOutbound(@Valid @RequestBody IostorInvCreateReqVO reqVO) { + return success(iostorInvService.createOutbound(reqVO)); +} +``` + +错误码仅增加“单据号生成失败”和“所选库存已不可用”,不新增数据库字段或表。 + +- [ ] **步骤 4:验证红绿与事务回滚** + +运行集成测试;再让测试用编码 API 失败配置触发异常,断言主表和明细数量均未增加。 + +- [ ] **步骤 5:提交聚合保存** + +```bash +git add nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/enums/ErrorCodeConstants.java nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceLocalSpringTest.java +git commit -m "feat: 事务保存出库单及明细" +``` + +## 任务 4:扩展前端 API 与明细汇总纯函数 + +- [ ] **步骤 1:先写失败的 Vitest 测试** + +```ts +import { describe, expect, it } from 'vitest'; +import { summarizeDetails } from './detail-summary'; + +describe('summarizeDetails', () => { + it('按明细条数和出库重量计算汇总', () => { + expect(summarizeDetails([{ planQty: 12.5 }, { planQty: 7.25 }])).toEqual({ + detailCount: 2, + totalWeight: 19.75, + }); + }); +}); +``` + +运行: + +```bash +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben vitest run apps/web-antdv-next/src/views/wms/iostorinv/modules/detail-summary.test.ts --dom +``` + +预期:FAIL,模块不存在。 + +- [ ] **步骤 2:实现最小汇总函数** + +```ts +export function summarizeDetails(details: Array<{ planQty?: number }>) { + return { + detailCount: details.length, + totalWeight: details.reduce((sum, item) => sum + Number(item.planQty || 0), 0), + }; +} +``` + +- [ ] **步骤 3:在 API 层增加明确类型和三个接口** + +定义 `OutboundDetail`、`OutboundCreateReq`、`AvailableInventory`、`AvailableInventoryPageReq`,并增加: + +```ts +export const getAvailableInventoryPage = (params: AvailableInventoryPageReq) => + requestClient.get>('/wms/iostor-inv/availableInventoryPage', { params }); +export const expandAvailableInventory = (storId: string, vehicleCodes: string[]) => + requestClient.post('/wms/iostor-inv/expandAvailableInventory', { storId, vehicleCodes }); +export const createOutbound = (data: OutboundCreateReq) => + requestClient.post('/wms/iostor-inv/createOutbound', data); +``` + +- [ ] **步骤 4:运行 Vitest 和类型检查** + +```bash +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben vitest run apps/web-antdv-next/src/views/wms/iostorinv/modules/detail-summary.test.ts --dom +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben --filter @vben/web-antdv-next typecheck +``` + +预期:汇总测试通过,新增 API 类型无错误。 + +- [ ] **步骤 5:提交前端基础能力** + +```bash +git add nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/iostorinv/index.ts nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/detail-summary.ts nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/detail-summary.test.ts +git commit -m "feat: 增加出库单前端聚合接口与汇总逻辑" +``` + +## 任务 5:实现库存选择与手工汇总弹窗 + +- [ ] **步骤 1:实现库存选择弹窗** + +`inventory-select.vue` 接收主弹窗传入的 `storId`,表单筛选物料编码、箱号、子卷号,Vxe Grid 使用服务端分页和多选。确认时只收集选中行的 `vehicleCode`,调用 `expandAvailableInventory`;返回结果逐子卷映射为明细,`planQty` 默认为 `availableQty`。勾选过程不自动修改其他子卷的选中状态。 + +- [ ] **步骤 2:实现手工汇总弹窗** + +复用 `views/base/materialbase/components/MaterialSelectModal.vue` 选择一个物料,填写大于 0 的总出库重量和备注;确认对象必须显式包含: + +```ts +{ + materialId, + materialCode, + materialName, + planQty, + qtyUnitId, + qtyUnitName, + vehicleCode: undefined, + pcsn: undefined, + sapBatchNo: undefined, + remark, +} +``` + +- [ ] **步骤 3:运行前端类型检查** + +```bash +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben --filter @vben/web-antdv-next typecheck +``` + +预期:两个弹窗 props、emit、API 结果映射均无类型错误。 + +- [ ] **步骤 4:提交两个弹窗** + +```bash +git add nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/inventory-select.vue nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/manual-detail.vue +git commit -m "feat: 增加出库库存选择和手工汇总弹窗" +``` + +## 任务 6:按参考图重构新增主弹窗 + +- [ ] **步骤 1:实现主表布局与默认值** + +重构 `form.vue` 为宽屏弹窗:单据号显示“保存时自动生成”;仓库和业务类型为必选下拉;状态只读“生成”;业务日期使用 `dayjs()` 默认为当天;明细数和总重量只读;备注跨列。仓库使用 `getBsrealStorAttrSimpleList`,业务类型从现有字典缓存中过滤出库业务类型。 + +- [ ] **步骤 2:实现明细表与两种入口** + +列顺序严格按确认原型:序号、物料编码、物料名称、箱号、子卷号、SAP 批次号、出库重量、单位、源单号、明细备注、操作。出库重量可编辑;删除、库存返回、手工汇总返回均调用 `summarizeDetails` 更新只读汇总。 + +- [ ] **步骤 3:实现仓库切换和提交** + +仓库值发生实际变化且明细非空时清空明细。提交只发送 `billType`、`storId`、`bizDate`、`remark` 及 `wms_iostorinvdtl` 可持久化字段;不得发送箱号、物料名称、SAP 批次号、单据号、状态和汇总字段。 + +- [ ] **步骤 4:运行前端测试、类型检查与构建** + +```bash +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben vitest run apps/web-antdv-next/src/views/wms/iostorinv/modules/detail-summary.test.ts --dom +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben --filter @vben/web-antdv-next typecheck +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben --filter @vben/web-antdv-next build +``` + +预期:测试、类型检查和生产构建均以退出码 0 完成。 + +- [ ] **步骤 5:提交主弹窗** + +```bash +git add nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/form.vue +git commit -m "feat: 按参考布局实现出库单新增页" +``` + +## 任务 7:端到端核对与最终验证 + +- [ ] **步骤 1:核对数据库字段边界** + +检查最终 diff,确认没有 DDL、迁移脚本或 DO 新字段;前端展示字段没有进入 `createOutbound` 请求;所有明细只通过 `IostorinvDtlMapper` 写入 `wms_iostorinvdtl`。 + +- [ ] **步骤 2:运行后端完整模块验证** + +```bash +mvn -pl nl-module-wms/nl-module-wms-server -am clean test -DskipTests=false +``` + +预期:WMS server 及依赖模块编译成功,测试失败数为 0。 + +- [ ] **步骤 3:运行前端完整验证** + +```bash +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben vitest run apps/web-antdv-next/src/views/wms/iostorinv/modules/detail-summary.test.ts --dom +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben --filter @vben/web-antdv-next typecheck +pnpm --dir nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben --filter @vben/web-antdv-next build +``` + +预期:三条命令均退出码 0。 + +- [ ] **步骤 4:人工验收关键流程** + +启动前后端后确认:新增页默认值正确;未选仓库不能选择库存;选择任一库存记录会按箱号带回全部子卷;勾选本身不联动;手工汇总的箱号、子卷号、SAP 批次号为空;明细汇总实时变化;切换仓库清空明细;保存后主表和全部明细同时存在。 + +- [ ] **步骤 5:提交验证阶段必要修正** + +仅当验证产生修正时提交相关文件: + +```bash +git add nl-module-wms nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/iostorinv nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv +git commit -m "fix: 完善出库单新增流程验证问题" +``` diff --git a/docs/superpowers/specs/2026-07-22-outbound-create-design.md b/docs/superpowers/specs/2026-07-22-outbound-create-design.md new file mode 100644 index 00000000..bf815e8f --- /dev/null +++ b/docs/superpowers/specs/2026-07-22-outbound-create-design.md @@ -0,0 +1,117 @@ +# 出库单新增功能设计 + +## 目标与范围 + +按照 `.image/出库新增.png` 重构出入库单主表的新增布局,支持从仓库可用库存选择和手工新增物料汇总两种明细添加方式,并将主表与明细作为一个聚合事务保存。 + +本次仅实现出库新增,不新增数据库字段,不扩展入库、明细编辑、分配、确认或回传流程。主表使用 `wms_iostorinv`,明细写入 `wms_iostorinvdtl`。 + +## 页面布局 + +新增页采用已确认的参考图布局: + +- 顶部操作区提供“保存”和“关闭”。 +- 主表区域展示单据号、仓库、业务类型、单据状态、明细数、总重量、业务日期和备注。 +- 明细区域提供“选择库存”和“新增汇总”两个入口。 +- 明细表展示序号、物料编码、物料名称、箱号、子卷号、SAP 批次号、出库重量、单位、源单号、明细备注和操作。 +- 初次打开时明细表为空。 + +## 主表字段与默认值 + +| 页面字段 | `wms_iostorinv` 字段 | 行为 | +| --- | --- | --- | +| 单据号 | `billCode` | 只读;保存时通过 base 模块编码生成 API 生成 | +| 仓库 | `storId`、`storCode`、`storName` | 必填,可选择 | +| 业务类型 | `billType` | 必填,可选择 | +| 出入类型 | `ioType` | 后端固定为出库 | +| 单据状态 | `billStatus` | 默认并固定为“生成” | +| 明细数 | `detailCount` | 根据明细条数自动计算 | +| 总重量 | `totalWeight` | 汇总明细的出库重量 | +| 业务日期 | `bizDate` | 默认当天,可修改 | +| 备注 | `remark` | 选填 | + +前端在明细增删和重量变化时即时更新明细数与总重量。后端保存时必须根据请求明细重新计算,不能直接信任前端汇总字段。 + +## 明细字段与持久化边界 + +明细使用 `wms_iostorinvdtl` 的现有字段: + +| 业务含义 | 明细字段 | 保存规则 | +| --- | --- | --- | +| 主表关联 | `iostorinvId` | 主表插入后回填 | +| 序号 | `seqNo` | 从 1 开始连续生成 | +| 物料 | `materialId`、`materialCode` | 必填 | +| 子卷号 | `pcsn` | 库存明细带入;手工汇总为空 | +| 出库重量 | `planQty` | 必须大于 0 | +| 已分配数量 | `assignQty` | 新增时为 0 | +| 未分配数量 | `unassignQty` | 新增时等于出库重量 | +| 单位 | `qtyUnitId`、`qtyUnitName` | 从库存或物料信息带入 | +| 来源单据 | `sourceBillCode`、`sourceBillType`、`sourceBilldtlId` | 库存存在来源时带入 | +| 备注 | `remark` | 选填 | + +箱号、物料名称和独立 SAP 批次号在 `wms_iostorinvdtl` 中没有对应字段,只用于新增页面展示,不落库,也不与其他字段混用。手工汇总明细的箱号、子卷号和 SAP 批次号均为空。 + +## 明细新增方式 + +### 从库存选择 + +1. 用户必须先选择仓库。 +2. 库存弹窗查询该仓库下的可用库存,并支持按物料、箱号、子卷号等现有库存字段筛选。 +3. 用户可独立勾选库存记录,界面不自动联动勾选同箱的其他子卷。 +4. 确认时以后端为准,提取已选记录涉及的箱号,去重后重新查询这些箱号在所选仓库下的全部可用子卷。 +5. 将查询出的每个子卷逐条带回出库明细表;默认出库重量为该子卷当前可用重量。 +6. 同一箱号重复选择只展开一次,避免重复明细。 + +### 新增物料汇总 + +1. 用户选择物料并输入总出库重量,可填写备注。 +2. 单位从物料现有信息带出。 +3. 新增一条汇总明细,箱号、子卷号和 SAP 批次号保持为空。 + +## 接口与事务设计 + +采用主表与明细聚合保存方案: + +- 新增“创建出库单(含明细)”接口,接收主表可编辑字段和明细列表。 +- 新增按仓库和筛选条件查询可用库存的接口。 +- 库存确认或保存前由后端按箱号展开全部可用子卷,确保展开结果属于当前仓库且仍然可用。 +- 保存服务开启事务,先调用 base 模块编码生成 API 获取单据号,再构造主表、计算汇总、插入主表,最后插入全部 `wms_iostorinvdtl` 明细。 +- 编码生成、主表插入或任一明细插入失败时整体回滚。 + +单据号规则沿用项目已有的出入库编码规则配置和 `CodeGenApi` 调用方式,不在本功能中创建新的编码规则或字段。 + +## 数据校验与错误处理 + +- 仓库、业务类型和业务日期必填。 +- 保存时至少存在一条明细。 +- 每条明细必须包含物料,且出库重量大于 0。 +- 切换仓库时清空当前明细,避免跨仓库数据混用。 +- 库存带入时校验箱号属于所选仓库,并以当前可用库存重新展开;库存已不可用时返回明确的业务错误。 +- 重复箱号在展开前去重。 +- 编码 API 返回失败或空编码时终止保存并回滚。 +- 后端固定出库类型和生成状态,并重新计算明细数、总重量、序号及初始分配数量,防止客户端篡改。 + +## 测试与验收 + +后端测试覆盖: + +- base 编码 API 生成的单据号写入主表。 +- 默认出库类型和生成状态正确。 +- 后端根据明细重算明细数和总重量。 +- 主表与明细在同一事务中写入,异常时整体回滚。 +- 库存查询限定所选仓库和可用数量。 +- 任意选中一个箱号下的记录后,返回该箱号全部可用子卷。 +- 多条选中记录包含重复箱号时只展开一次。 +- 物料缺失、重量非正数、空明细及失效库存被拒绝。 + +前端测试或可自动化验证覆盖: + +- 新增页业务日期默认为当天,状态为生成,明细为空。 +- 明细增删和重量修改会更新明细数与总重量。 +- 未选择仓库不能打开库存选择流程。 +- 库存确认结果逐子卷进入明细表。 +- 手工汇总行的箱号、子卷号和 SAP 批次号为空。 +- 切换仓库会清空现有明细。 +- 提交数据只使用现有主表和明细字段。 + +完成后运行 WMS 模块相关单元测试、前端类型检查和构建,并对照参考图检查新增页布局与两种明细添加流程。 diff --git a/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/pojo/AcsBaseReqDTO.java b/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/pojo/AcsBaseReqDTO.java new file mode 100644 index 00000000..23fff4ab --- /dev/null +++ b/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/pojo/AcsBaseReqDTO.java @@ -0,0 +1,22 @@ +package cn.code.nl.framework.common.pojo; + +import lombok.Data; + +/** + * 基础DTO对象 + * @Author: liyongde + * @Date: 2026/7/24 8:49 + */ +@Data +public class AcsBaseReqDTO { + /** + * 请求号: traceId + */ + private String traceId; + + /** + * + * 时间 + */ + private Long timestamp; +} diff --git a/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/pojo/AcsBaseRespDTO.java b/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/pojo/AcsBaseRespDTO.java new file mode 100644 index 00000000..91c763ea --- /dev/null +++ b/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/pojo/AcsBaseRespDTO.java @@ -0,0 +1,26 @@ +package cn.code.nl.framework.common.pojo; + +import lombok.Data; + +/** + * acs返回基础对象 + * @Author: liyongde + * @Date: 2026/7/24 10:27 + */ +@Data +public class AcsBaseRespDTO { + /** + * 是否整体成功 + */ + private Boolean success; + + /** + * 响应编码 + */ + private String code; + + /** + * 响应消息 + */ + private String msg; +} diff --git a/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/util/http/AcsUtil.java b/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/util/http/AcsUtil.java new file mode 100644 index 00000000..0ada5947 --- /dev/null +++ b/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/util/http/AcsUtil.java @@ -0,0 +1,78 @@ +package cn.code.nl.framework.common.util.http; + +import cn.code.nl.framework.common.exception.ServerException; +import cn.code.nl.framework.common.exception.ServiceException; +import cn.code.nl.framework.common.util.json.JsonUtils; +import cn.hutool.core.util.StrUtil; + +import java.net.ConnectException; +import java.net.NoRouteToHostException; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.Collections; +import java.util.Map; + +/** + * ACS 调用工具 + */ +public class AcsUtil { + + /** + * 发送 POST 请求并解析响应 + * + * @param serverAddress ACS 服务地址 + * @param api API 路径 + * @param request 请求参数 + * @param responseType 响应类型 + * @return 响应对象 + */ + public static T post(String serverAddress, String api, Object request, Class responseType) { + String url = buildUrl(serverAddress, api); + String response; + try { + response = HttpUtils.post(url, headers(), JsonUtils.toJsonString(request)); + } catch (RuntimeException ex) { + if (isNetworkException(ex)) { + throw new ServiceException(500, "ACS服务网络不通"); + } + throw ex; + } + return JsonUtils.parseObject(response, responseType); + } + + /** + * 拼接服务地址和 API + */ + private static String buildUrl(String serverAddress, String api) { + String baseUrl = StrUtil.removeSuffix(serverAddress, StrUtil.SLASH); + String apiPath = StrUtil.addPrefixIfNot(api, StrUtil.SLASH); + return baseUrl + apiPath; + } + + /** + * 构建 JSON 请求头 + */ + private static Map headers() { + return Collections.singletonMap("Content-Type", "application/json;charset=UTF-8"); + } + + /** + * 判断是否为 ACS 网络连接异常 + */ + private static boolean isNetworkException(Throwable ex) { + Throwable cause = ex; + while (cause != null) { + if (cause instanceof ConnectException + || cause instanceof SocketTimeoutException + || cause instanceof UnknownHostException + || cause instanceof NoRouteToHostException + || cause instanceof SocketException) { + return true; + } + cause = cause.getCause(); + } + return false; + } + +} diff --git a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/AbstractTaskCommonApiImpl.java b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/AbstractTaskCommonApiImpl.java new file mode 100644 index 00000000..9f4fb1e5 --- /dev/null +++ b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/AbstractTaskCommonApiImpl.java @@ -0,0 +1,115 @@ +package cn.code.nl.framework.execute.biz.api; + +import cn.code.nl.framework.common.exception.ServiceException; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.execute.biz.dto.TaskStatusCallApiReqDTO; +import cn.code.nl.framework.execute.biz.vo.AcsApplyActionRespVO; +import cn.code.nl.framework.execute.core.AbstractTask; +import cn.code.nl.framework.execute.core.TaskFactory; +import cn.code.nl.framework.execute.core.dto.TaskExecuteDTO; +import jakarta.annotation.Resource; + +/** + * 任务通用 API 公共实现 + * + * @author liyongde + */ +public abstract class AbstractTaskCommonApiImpl implements TaskCommonApi { + + /** + * 任务处理器工厂 + */ + @Resource + private TaskFactory taskFactory; + + /** + * 处理取货完成 + */ + @Override + public CommonResult doHandlePicked(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { + return execute(taskStatusCallApiReqDTO, (task, taskExecuteDTO) -> { + task.doHandlePicked(taskExecuteDTO); + return null; + }); + } + + /** + * 处理二次请求 + */ + @Override + public CommonResult doHandleApplyAgain(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { + return execute(taskStatusCallApiReqDTO, AbstractTask::againApply); + } + + /** + * 处理请求放货 + */ + @Override + public CommonResult doHandleRequestRelease(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { + return execute(taskStatusCallApiReqDTO, AbstractTask::requestPutAway); + } + + /** + * 处理请求取货 + */ + @Override + public CommonResult doHandleRequestPick(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { + return execute(taskStatusCallApiReqDTO, AbstractTask::requestPickGoods); + } + + /** + * 处理请求离开 + */ + @Override + public CommonResult doHandleRequestLeave(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { + return execute(taskStatusCallApiReqDTO, AbstractTask::requestOut); + } + + /** + * 处理请求进入 + */ + @Override + public CommonResult doHandleRequestEnter(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { + return execute(taskStatusCallApiReqDTO, AbstractTask::requestIn); + } + + /** + * 根据 handleCode 路由到具体任务处理器 + */ + private CommonResult execute(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO, + TaskActionInvoker taskActionInvoker) { + AbstractTask task = taskFactory.getTask(taskStatusCallApiReqDTO.getHandleCode()); + if (task == null) { + throw new ServiceException(500, "未找到任务处理器:" + taskStatusCallApiReqDTO.getHandleCode()); + } + Object data = taskActionInvoker.invoke(task, buildTaskExecuteDTO(taskStatusCallApiReqDTO)); + + AcsApplyActionRespVO respVO = new AcsApplyActionRespVO(); + respVO.setTaskId(taskStatusCallApiReqDTO.getTaskId()); + respVO.setTaskCode(taskStatusCallApiReqDTO.getTaskCode()); + respVO.setData(data); + return CommonResult.success(respVO); + } + + /** + * 构建任务执行参数 + */ + private TaskExecuteDTO buildTaskExecuteDTO(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { + return TaskExecuteDTO.builder() + .taskId(taskStatusCallApiReqDTO.getTaskId()) + .payload(taskStatusCallApiReqDTO.getPayload()) + .build(); + } + + /** + * 任务动作调用器 + */ + @FunctionalInterface + private interface TaskActionInvoker { + + /** + * 调用任务动作 + */ + Object invoke(AbstractTask task, TaskExecuteDTO taskExecuteDTO); + } +} diff --git a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/TaskCommonApi.java b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/TaskCommonApi.java index 66d9a473..fff86e58 100644 --- a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/TaskCommonApi.java +++ b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/TaskCommonApi.java @@ -4,8 +4,8 @@ import cn.code.nl.framework.common.pojo.CommonResult; import cn.code.nl.framework.execute.biz.dto.TaskStatusCallApiReqDTO; import cn.code.nl.framework.execute.biz.vo.AcsApplyActionRespVO; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Schema; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; /** * @@ -16,25 +16,25 @@ public interface TaskCommonApi { @Operation(summary = "请求取货") @PostMapping("/do-handle-picked") - CommonResult doHandlePicked(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); + CommonResult doHandlePicked(@RequestBody TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); @Operation(summary = "二次请求") @PostMapping("/do-handle-apply-again") - CommonResult doHandleApplyAgain(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); + CommonResult doHandleApplyAgain(@RequestBody TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); @Operation(summary = "处理请求放货") @PostMapping("/do-handle-request-release") - CommonResult doHandleRequestRelease(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); + CommonResult doHandleRequestRelease(@RequestBody TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); @Operation(summary = "处理请求取货") @PostMapping("/do-handle-request-pick") - CommonResult doHandleRequestPick(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); + CommonResult doHandleRequestPick(@RequestBody TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); @Operation(summary = "处理请求离开") @PostMapping("/do-handle-request-leave") - CommonResult doHandleRequestLeave(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); + CommonResult doHandleRequestLeave(@RequestBody TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); @Operation(summary = "处理请求进入") @PostMapping("/do-handle-request-enter") - CommonResult doHandleRequestEnter(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); + CommonResult doHandleRequestEnter(@RequestBody TaskStatusCallApiReqDTO taskStatusCallApiReqDTO); } diff --git a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/lms/LmsTaskCommonApi.java b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/lms/LmsTaskCommonApi.java index 3bd8ff04..ac559a20 100644 --- a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/lms/LmsTaskCommonApi.java +++ b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/lms/LmsTaskCommonApi.java @@ -4,15 +4,14 @@ import cn.code.nl.framework.common.enums.RpcConstants; import cn.code.nl.framework.execute.biz.api.TaskCommonApi; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.RequestMapping; +import io.swagger.v3.oas.annotations.tags.Tag; /** * lms通用API * @Author: liyongde * @Date: 2026/7/15 14:39 */ -@FeignClient(name = RpcConstants.LMS_NAME, primary = false) // TODO 芋艿:fallbackFactory = -@RequestMapping("/lms") +@FeignClient(name = RpcConstants.LMS_NAME, path = RpcConstants.RPC_API_PREFIX + "/lms", primary = false) // TODO 芋艿:fallbackFactory = @Tag(name = "RPC 服务 - lms任务") public interface LmsTaskCommonApi extends TaskCommonApi { } diff --git a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/wms/WmsTaskCommonApi.java b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/wms/WmsTaskCommonApi.java index 2e442ddb..d4977342 100644 --- a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/wms/WmsTaskCommonApi.java +++ b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/api/wms/WmsTaskCommonApi.java @@ -4,15 +4,14 @@ import cn.code.nl.framework.common.enums.RpcConstants; import cn.code.nl.framework.execute.biz.api.TaskCommonApi; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.RequestMapping; +import io.swagger.v3.oas.annotations.tags.Tag; /** * * @Author: liyongde * @Date: 2026/7/15 14:48 */ -@FeignClient(name = RpcConstants.WMS_NAME, primary = false) // TODO 芋艿:fallbackFactory = -@RequestMapping("/wms") +@FeignClient(name = RpcConstants.WMS_NAME, path = RpcConstants.RPC_API_PREFIX + "/wms", primary = false) // TODO 芋艿:fallbackFactory = @Tag(name = "RPC 服务 - wms任务") public interface WmsTaskCommonApi extends TaskCommonApi { } diff --git a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/vo/AcsApplyActionRespVO.java b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/vo/AcsApplyActionRespVO.java index 5096efe6..2a395188 100644 --- a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/vo/AcsApplyActionRespVO.java +++ b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/biz/vo/AcsApplyActionRespVO.java @@ -1,6 +1,5 @@ package cn.code.nl.framework.execute.biz.vo; -import com.alibaba.fastjson.JSONObject; import lombok.Data; /** @@ -25,5 +24,5 @@ public class AcsApplyActionRespVO { /** * 数据 */ - private JSONObject data; + private Object data; } diff --git a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/core/TaskFactory.java b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/core/TaskFactory.java index 4b16f8c9..14d4e455 100644 --- a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/core/TaskFactory.java +++ b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/core/TaskFactory.java @@ -1,37 +1,31 @@ package cn.code.nl.framework.execute.core; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** - * * @Author: liyongde * @Date: 2026/7/15 15:32 */ @Component public class TaskFactory implements BeanPostProcessor { - private final Map taskMap; - @Autowired - public TaskFactory() { - taskMap = new HashMap<>(); - } + private final Map taskMap = new ConcurrentHashMap<>(); @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (bean instanceof AbstractTask) { - taskMap.put(beanName, (AbstractTask) bean); + if (bean instanceof AbstractTask task) { + taskMap.put(beanName, task); } return bean; } public AbstractTask getTask(String handleCode) { - if (handleCode == null) { + if (handleCode == null || handleCode.isBlank()) { return null; } return taskMap.get(handleCode); diff --git a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/core/dto/TaskExecuteDTO.java b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/core/dto/TaskExecuteDTO.java index dc07f545..e0cff2a4 100644 --- a/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/core/dto/TaskExecuteDTO.java +++ b/nl-framework/nl-spring-boot-starter-execute/src/main/java/cn/code/nl/framework/execute/core/dto/TaskExecuteDTO.java @@ -2,7 +2,10 @@ package cn.code.nl.framework.execute.core.dto; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import java.util.Map; @@ -12,6 +15,9 @@ import java.util.Map; * @Date: 2026/7/16 14:57 */ @Data +@Builder +@NoArgsConstructor +@AllArgsConstructor public class TaskExecuteDTO { @Schema(description = "任务id") diff --git a/nl-framework/nl-spring-boot-starter-mybatis/src/main/java/cn/code/nl/framework/mybatis/core/query/LambdaQueryWrapperX.java b/nl-framework/nl-spring-boot-starter-mybatis/src/main/java/cn/code/nl/framework/mybatis/core/query/LambdaQueryWrapperX.java index daf258e0..94dfface 100644 --- a/nl-framework/nl-spring-boot-starter-mybatis/src/main/java/cn/code/nl/framework/mybatis/core/query/LambdaQueryWrapperX.java +++ b/nl-framework/nl-spring-boot-starter-mybatis/src/main/java/cn/code/nl/framework/mybatis/core/query/LambdaQueryWrapperX.java @@ -126,6 +126,12 @@ public class LambdaQueryWrapperX extends LambdaQueryWrapper { return this; } + @Override + public LambdaQueryWrapperX orderByAsc(SFunction column) { + super.orderByAsc(true, column); + return this; + } + @Override public LambdaQueryWrapperX last(String lastSql) { super.last(lastSql); diff --git a/nl-gateway/src/main/resources/application-dev.yaml b/nl-gateway/src/main/resources/application-dev.yaml index 02342c5d..1c16ab0b 100644 --- a/nl-gateway/src/main/resources/application-dev.yaml +++ b/nl-gateway/src/main/resources/application-dev.yaml @@ -7,10 +7,10 @@ spring: username: nacos password: nacos discovery: # 【配置中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP config: # 【注册中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP --- #################### 监控相关配置 #################### diff --git a/nl-module-base/nl-module-base-api/src/main/java/cn/code/nl/module/base/api/classstandard/ClassStandardApi.java b/nl-module-base/nl-module-base-api/src/main/java/cn/code/nl/module/base/api/classstandard/ClassStandardApi.java new file mode 100644 index 00000000..503e325a --- /dev/null +++ b/nl-module-base/nl-module-base-api/src/main/java/cn/code/nl/module/base/api/classstandard/ClassStandardApi.java @@ -0,0 +1,34 @@ +package cn.code.nl.module.base.api.classstandard; + +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.module.base.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +/** + * RPC 服务 - 基础数据分类标准 + * + * @author zhouz + */ +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 基础数据分类标准") +public interface ClassStandardApi { + + String PREFIX = ApiConstants.PREFIX + "/class-standard"; + + /** + * 根据分类编码获取该分类及所有子分类编码 + * + * @param classCode 分类编码 + * @return 分类编码列表 + */ + @GetMapping(PREFIX + "/code-list-by-code") + @Operation(summary = "根据分类编码获取该分类及所有子分类编码") + CommonResult> getClassStandardCodeListByCode(@RequestParam("classCode") String classCode); + +} diff --git a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/api/ClassStandardApiController.java b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/api/ClassStandardApiController.java new file mode 100644 index 00000000..78f90bbe --- /dev/null +++ b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/api/ClassStandardApiController.java @@ -0,0 +1,46 @@ +package cn.code.nl.module.base.api; + +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.module.base.api.classstandard.ClassStandardApi; +import cn.code.nl.module.base.dal.dataobject.classstandard.ClassStandardDO; +import cn.code.nl.module.base.service.classstandard.ClassStandardService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.code.nl.framework.common.pojo.CommonResult.success; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList; + +/** + * RPC API - 基础数据分类标准(供其它模块 Feign 调用) + * + * @author zhouz + */ +@Tag(name = "RPC API - 基础数据分类标准") +@RestController +@RequestMapping("/rpc-api/base/class-standard") +@Validated +public class ClassStandardApiController implements ClassStandardApi { + + @Resource + private ClassStandardService classStandardService; + + /** + * 根据分类编码获取该分类及所有子分类编码 + */ + @GetMapping("/code-list-by-code") + @Operation(summary = "根据分类编码获取该分类及所有子分类编码") + @Override + public CommonResult> getClassStandardCodeListByCode(@RequestParam("classCode") String classCode) { + List list = classStandardService.getClassStandardListByCode(classCode); + return success(convertList(list, ClassStandardDO::getClassCode)); + } + +} diff --git a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/controller/api/CodeGenController.java b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/api/CodeGenController.java similarity index 90% rename from nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/controller/api/CodeGenController.java rename to nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/api/CodeGenController.java index 8cb27cb1..5da28e09 100644 --- a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/controller/api/CodeGenController.java +++ b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/api/CodeGenController.java @@ -1,6 +1,7 @@ -package cn.code.nl.module.base.controller.api; +package cn.code.nl.module.base.api; import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.module.base.api.codegen.CodeGenApi; import cn.code.nl.module.base.api.codegen.dto.CodeGenerateReqDTO; import cn.code.nl.module.base.service.codegen.CodeGenService; import io.swagger.v3.oas.annotations.Operation; @@ -26,7 +27,7 @@ import static cn.code.nl.framework.common.pojo.CommonResult.success; @RestController @RequestMapping("/rpc-api/base/code-gen") @Validated -public class CodeGenController { +public class CodeGenController implements CodeGenApi { @Resource private CodeGenService codeGenService; @@ -36,6 +37,7 @@ public class CodeGenController { */ @PostMapping("/generate") @Operation(summary = "生成编码") + @Override public CommonResult generate(@Valid @RequestBody CodeGenerateReqDTO reqDTO) { String code = codeGenService.generate(reqDTO.getRuleCode()); return success(code); @@ -43,9 +45,9 @@ public class CodeGenController { @GetMapping("/preview") @Operation(summary = "预览下一个编码(不消耗序号)") + @Override public CommonResult preview(@RequestParam("ruleCode") String ruleCode) { String code = codeGenService.preview(ruleCode); return success(code); } - } diff --git a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/controller/admin/classstandard/vo/ClassStandardSimpleRespVO.java b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/controller/admin/classstandard/vo/ClassStandardSimpleRespVO.java index a4de7532..12ba7fe9 100644 --- a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/controller/admin/classstandard/vo/ClassStandardSimpleRespVO.java +++ b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/controller/admin/classstandard/vo/ClassStandardSimpleRespVO.java @@ -15,6 +15,9 @@ public class ClassStandardSimpleRespVO { @Schema(description = "分类标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long classId; + @Schema(description = "分类编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "原材料") + private String classCode; + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "原材料") private String className; diff --git a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/dal/mysql/codegen/CodeSequenceMapper.java b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/dal/mysql/codegen/CodeSequenceMapper.java index 9a8a82b3..4682cd9d 100644 --- a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/dal/mysql/codegen/CodeSequenceMapper.java +++ b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/dal/mysql/codegen/CodeSequenceMapper.java @@ -2,6 +2,7 @@ package cn.code.nl.module.base.dal.mysql.codegen; import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; import cn.code.nl.module.base.dal.dataobject.codegen.CodeSequenceDO; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -35,6 +36,7 @@ public interface CodeSequenceMapper extends BaseMapperX { * @param maxValue 最大值上限 * @return 更新行数 */ + @InterceptorIgnore(dataPermission = "true") int updateCurrentValueBySegment(@Param("ruleId") Long ruleId, @Param("resetKey") String resetKey, @Param("step") int step, diff --git a/nl-module-base/nl-module-base-server/src/main/resources/application-dev.yaml b/nl-module-base/nl-module-base-server/src/main/resources/application-dev.yaml index e08ede1d..37d19abb 100644 --- a/nl-module-base/nl-module-base-server/src/main/resources/application-dev.yaml +++ b/nl-module-base/nl-module-base-server/src/main/resources/application-dev.yaml @@ -3,16 +3,16 @@ spring: cloud: nacos: - server-addr: http://192.168.81.193:8848 # Nacos 服务器地址 + server-addr: 192.168.81.193:8848 # Nacos 服务器地址 username: nacos password: nacos discovery: # 【配置中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP metadata: version: 1.0.0 # 服务实例的版本号,可用于灰度发布 config: # 【注册中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP --- #################### 数据库相关配置 #################### @@ -57,14 +57,14 @@ spring: primary: master datasource: master: - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: @@ -95,11 +95,11 @@ spring: xxl: job: admin: - addresses: http://localhost:8080/xxl-job-admin # 调度中心部署跟地址 - accessToken: 123456 # 执行器通讯TOKEN + addresses: http://192.168.81.193:8080/xxl-job-admin # 调度中心部署跟地址 + accessToken: default_token # 执行器通讯TOKEN executor: - ip: localhost - port: 9993 + ip: 192.168.81.193 + port: 8993 --- #################### 服务保障相关配置 #################### diff --git a/nl-module-base/nl-module-base-server/src/main/resources/application-test.yaml b/nl-module-base/nl-module-base-server/src/main/resources/application-test.yaml index ab781cd6..d3e3ce0c 100644 --- a/nl-module-base/nl-module-base-server/src/main/resources/application-test.yaml +++ b/nl-module-base/nl-module-base-server/src/main/resources/application-test.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-base/nl-module-base-server/src/main/resources/mapper/codegen/CodeSequenceMapper.xml b/nl-module-base/nl-module-base-server/src/main/resources/mapper/codegen/CodeSequenceMapper.xml index 74909a0f..5d3572b8 100644 --- a/nl-module-base/nl-module-base-server/src/main/resources/mapper/codegen/CodeSequenceMapper.xml +++ b/nl-module-base/nl-module-base-server/src/main/resources/mapper/codegen/CodeSequenceMapper.xml @@ -14,7 +14,8 @@ VALUES (#{ruleId}, #{resetKey}, #{startAt} + #{step} - 1, #{maxValue}) ON DUPLICATE KEY UPDATE current_value = current_value + #{step}, - max_value = #{maxValue} + max_value = #{maxValue}, + deleted = 0 diff --git a/nl-module-infra/nl-module-infra-server/src/main/resources/application-dev.yaml b/nl-module-infra/nl-module-infra-server/src/main/resources/application-dev.yaml index 9ccd9bc1..bd488096 100644 --- a/nl-module-infra/nl-module-infra-server/src/main/resources/application-dev.yaml +++ b/nl-module-infra/nl-module-infra-server/src/main/resources/application-dev.yaml @@ -7,12 +7,12 @@ spring: username: nacos password: nacos discovery: # 【配置中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP metadata: version: 1.0.0 # 服务实例的版本号,可用于灰度发布 config: # 【注册中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP --- #################### 数据库相关配置 #################### @@ -57,14 +57,14 @@ spring: primary: master datasource: master: - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: @@ -96,10 +96,10 @@ xxl: job: admin: addresses: http://192.168.81.193:8080/xxl-job-admin # 调度中心部署跟地址 - accessToken: 123456 # 执行器通讯TOKEN + accessToken: default_token # 执行器通讯TOKEN executor: ip: 192.168.81.193 - port: 9991 + port: 8991 --- #################### 服务保障相关配置 #################### diff --git a/nl-module-infra/nl-module-infra-server/src/main/resources/application-test.yaml b/nl-module-infra/nl-module-infra-server/src/main/resources/application-test.yaml index ba155ba6..e0daf805 100644 --- a/nl-module-infra/nl-module-infra-server/src/main/resources/application-test.yaml +++ b/nl-module-infra/nl-module-infra-server/src/main/resources/application-test.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-lms/nl-module-lms-server/pom.xml b/nl-module-lms/nl-module-lms-server/pom.xml index af41c812..dab9a5e7 100644 --- a/nl-module-lms/nl-module-lms-server/pom.xml +++ b/nl-module-lms/nl-module-lms-server/pom.xml @@ -38,6 +38,11 @@ ${revision} + + cn.nl.cloud + nl-module-task-api + ${revision} + cn.nl.cloud diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/api/LmsTaskExecuteApiImpl.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/api/LmsTaskExecuteApiImpl.java new file mode 100644 index 00000000..994681d3 --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/api/LmsTaskExecuteApiImpl.java @@ -0,0 +1,21 @@ +package cn.code.nl.module.lms.api; + +import cn.code.nl.framework.common.enums.RpcConstants; +import cn.code.nl.framework.execute.biz.api.AbstractTaskCommonApiImpl; +import cn.code.nl.framework.execute.biz.api.lms.LmsTaskCommonApi; +import org.springframework.context.annotation.Primary; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * LMS 任务通用 API 实现 + * + * @author liyongde + */ +@RestController +@Validated +@Primary +@RequestMapping(RpcConstants.LMS_PREFIX) +public class LmsTaskExecuteApiImpl extends AbstractTaskCommonApiImpl implements LmsTaskCommonApi { +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/demo/DemoApi.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/demo/DemoApi.java deleted file mode 100644 index a1b44f70..00000000 --- a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/demo/DemoApi.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.code.nl.module.lms.demo; - -import cn.code.nl.framework.common.pojo.CommonResult; -import cn.code.nl.framework.execute.biz.api.lms.LmsTaskCommonApi; -import cn.code.nl.framework.execute.biz.dto.TaskStatusCallApiReqDTO; -import cn.code.nl.framework.execute.biz.vo.AcsApplyActionRespVO; -import com.alibaba.fastjson.JSON; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RestController; - -import static cn.code.nl.framework.common.pojo.CommonResult.success; - -/** - * - * @Author: liyongde - * @Date: 2026/7/15 15:25 - */ -@RestController // 提供 RESTful API 接口,给 Feign 调用 -@Validated -public class DemoApi implements LmsTaskCommonApi { - @Override - public CommonResult doHandlePicked(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { - // 构建外层VO - AcsApplyActionRespVO respVO = new AcsApplyActionRespVO(); - respVO.setTaskId(10001L); - respVO.setTaskCode("ACS20260716001"); - // 内层data赋值 "success" - return success(respVO); - } - - @Override - public CommonResult doHandleApplyAgain(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { - DemoRespVO demoRespVO = new DemoRespVO(); - demoRespVO.setTargetPoint("A_10001"); - - // 构建外层VO - AcsApplyActionRespVO respVO = new AcsApplyActionRespVO(); - respVO.setTaskId(10001L); - respVO.setTaskCode("ACS20260716001"); - // 内层data赋值 "success" - respVO.setData(JSON.parseObject(JSON.toJSONString(demoRespVO))); - return success(respVO); - } - - @Override - public CommonResult doHandleRequestRelease(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { - // 构建外层VO - AcsApplyActionRespVO respVO = new AcsApplyActionRespVO(); - respVO.setTaskId(10001L); - respVO.setTaskCode("ACS20260716001"); - return success(respVO); - } - - @Override - public CommonResult doHandleRequestPick(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { - // 构建外层VO - AcsApplyActionRespVO respVO = new AcsApplyActionRespVO(); - respVO.setTaskId(10001L); - respVO.setTaskCode("ACS20260716001"); - return success(respVO); - } - - @Override - public CommonResult doHandleRequestLeave(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { - // 构建外层VO - AcsApplyActionRespVO respVO = new AcsApplyActionRespVO(); - respVO.setTaskId(10001L); - respVO.setTaskCode("ACS20260716001"); - return success(respVO); - } - - @Override - public CommonResult doHandleRequestEnter(TaskStatusCallApiReqDTO taskStatusCallApiReqDTO) { - // 构建外层VO - AcsApplyActionRespVO respVO = new AcsApplyActionRespVO(); - respVO.setTaskId(10001L); - respVO.setTaskCode("ACS20260716001"); - return success(respVO); - } -} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/manage/package-info.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/manage/package-info.java new file mode 100644 index 00000000..9e091556 --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/manage/package-info.java @@ -0,0 +1,6 @@ +/** + * + * @Author: liyongde + * @Date: 2026/7/23 14:41 + */ +package cn.code.nl.module.lms.manage; \ No newline at end of file diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/mq/consumer/LmsTaskStatusChangeConsumer.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/mq/consumer/LmsTaskStatusChangeConsumer.java new file mode 100644 index 00000000..ae2959ca --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/mq/consumer/LmsTaskStatusChangeConsumer.java @@ -0,0 +1,118 @@ +package cn.code.nl.module.lms.mq.consumer; + +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.execute.core.AbstractTask; +import cn.code.nl.framework.execute.core.TaskFactory; +import cn.code.nl.framework.execute.core.dto.TaskExecuteDTO; +import cn.code.nl.module.task.api.TransportTaskApi; +import cn.code.nl.module.task.dto.TaskInfoDTO; +import cn.code.nl.module.task.enums.TransportTaskStatusEnum; +import cn.code.nl.module.task.message.TaskEventMessage; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Component; + +import static cn.code.nl.module.task.message.LockKeyConstants.TASK_STATUS_CHANGE_LOCK_KEY; + +/** + * 监听任务状态变更,根据 handleCode 定位任务子类并执行完成/取消逻辑 + * + * @Author: liyongde + * @Date: 2026/7/20 10:28 + */ +@Slf4j +@Component +@RocketMQMessageListener( + topic = "${rocketmq.consumer.lms-task-operate.topic}", + consumerGroup = "${rocketmq.consumer.lms-task-operate.group}" +) +public class LmsTaskStatusChangeConsumer implements RocketMQListener { + + @Resource + private TaskFactory taskFactory; + + @Resource + private TransportTaskApi transportTaskApi; + + @Resource + private RedissonClient redissonClient; + + @Override + public void onMessage(TaskEventMessage message) { + String handleCode = message.getHandleCode(); + String eventType = message.getEventType(); + log.info("收到任务状态变更消息, handleCode={}, eventType={}, taskId={}", handleCode, eventType, message.getTaskId()); + + RLock lock = redissonClient.getLock(TASK_STATUS_CHANGE_LOCK_KEY + message.getTaskId()); + if (!lock.tryLock()) { + log.warn("任务状态变更消息正在消费中,等待 MQ 重试, taskId={}, eventType={}", message.getTaskId(), eventType); + throw new IllegalStateException("任务状态变更消息正在消费中"); + } + try { + if (!isTaskCallbackPending(message)) { + return; + } + executeTaskHandler(message, handleCode, eventType); + } finally { + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + } + + /** + * 判断任务是否处于当前事件对应的待业务处理状态 + */ + private boolean isTaskCallbackPending(TaskEventMessage message) { + String eventType = message.getEventType(); + String expectedStatus; + if (TaskEventMessage.EVENT_TYPE_FINISHED.equals(eventType)) { + expectedStatus = TransportTaskStatusEnum.FINISHED_CALLBACK_PENDING.getCode(); + } else if (TaskEventMessage.EVENT_TYPE_CANCELLED.equals(eventType)) { + expectedStatus = TransportTaskStatusEnum.CANCEL_CALLBACK_PENDING.getCode(); + } else { + log.warn("未知任务事件类型, eventType={}, taskId={}", eventType, message.getTaskId()); + return false; + } + + CommonResult result = transportTaskApi.getTaskById(message.getTaskId()); + TaskInfoDTO taskInfo = result.getCheckedData(); + if (taskInfo == null) { + log.warn("任务不存在,跳过任务状态变更消息, taskId={}, eventType={}", message.getTaskId(), eventType); + return false; + } + if (!expectedStatus.equals(taskInfo.getTaskStatus())) { + log.info("任务状态已处理,跳过重复消息, taskId={}, eventType={}, currentStatus={}, expectedStatus={}", + message.getTaskId(), eventType, taskInfo.getTaskStatus(), expectedStatus); + return false; + } + return true; + } + + /** + * 执行任务完成或取消业务处理器 + */ + private void executeTaskHandler(TaskEventMessage message, String handleCode, String eventType) { + AbstractTask task = taskFactory.getTask(handleCode); + if (task == null) { + log.warn("未找到对应任务处理器, handleCode={}", handleCode); + return; + } + + TaskExecuteDTO dto = new TaskExecuteDTO(); + dto.setTaskId(message.getTaskId()); + dto.setPayload(message.getPayload()); + + if (TaskEventMessage.EVENT_TYPE_FINISHED.equals(eventType)) { + task.doHandleFinish(dto); + } else if (TaskEventMessage.EVENT_TYPE_CANCELLED.equals(eventType)) { + task.doHandleCancel(dto); + } else { + log.warn("未知事件类型, eventType={}, handleCode={}", eventType, handleCode); + } + } +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/mq/package-info.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/mq/package-info.java new file mode 100644 index 00000000..dfa0616a --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/mq/package-info.java @@ -0,0 +1,6 @@ +/** + * + * @Author: liyongde + * @Date: 2026/7/23 16:21 + */ +package cn.code.nl.module.lms.mq; \ No newline at end of file diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/application-dev.yaml b/nl-module-lms/nl-module-lms-server/src/main/resources/application-dev.yaml index e9e05859..6379951a 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/resources/application-dev.yaml +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/application-dev.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/application-local.yaml b/nl-module-lms/nl-module-lms-server/src/main/resources/application-local.yaml index 82a2b44f..7d51d4e1 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/resources/application-local.yaml +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/application-local.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/application-mq-dev.yaml b/nl-module-lms/nl-module-lms-server/src/main/resources/application-mq-dev.yaml new file mode 100644 index 00000000..cb823736 --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/application-mq-dev.yaml @@ -0,0 +1,11 @@ +--- #################### MQ 消息队列相关配置 #################### +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 192.168.81.193:9876 + producer: + group: lms_producer_dev_group # 事务消息需要配置一样 + send-message-timeout: 3000 + consumer: + lms-task-operate: + group: lms_task_status_change_dev_group + topic: lms_task_status_change_dev_topic \ No newline at end of file diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/application-test.yaml b/nl-module-lms/nl-module-lms-server/src/main/resources/application-test.yaml index 5658794f..616c39f4 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/resources/application-test.yaml +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/application-test.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/application.yaml b/nl-module-lms/nl-module-lms-server/src/main/resources/application.yaml index aa71aa8b..d811bc01 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/resources/application.yaml +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/application.yaml @@ -13,6 +13,7 @@ spring: import: - optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置 - optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置 + - optional:classpath:application-mq-${spring.profiles.active}.yaml # 加载 MQ 配置 # Servlet 配置 servlet: diff --git a/nl-module-system/nl-module-system-api/src/main/java/cn/code/nl/module/system/enums/LogRecordConstants.java b/nl-module-system/nl-module-system-api/src/main/java/cn/code/nl/module/system/enums/LogRecordConstants.java index d2cc6d94..75fdbaf9 100644 --- a/nl-module-system/nl-module-system-api/src/main/java/cn/code/nl/module/system/enums/LogRecordConstants.java +++ b/nl-module-system/nl-module-system-api/src/main/java/cn/code/nl/module/system/enums/LogRecordConstants.java @@ -30,4 +30,13 @@ public interface LogRecordConstants { String SYSTEM_ROLE_DELETE_SUB_TYPE = "删除角色"; String SYSTEM_ROLE_DELETE_SUCCESS = "删除了角色【{{#role.name}}】"; + // ======================= WMS_GROUP 组盘信息 ======================= + String WMS_GROUP_PLATE = "组盘信息"; + String WMS_GROUP_PLATE_UPDATE = "修改组盘信息"; + String WMS_GROUP_PLATE_SUCCESS = "{{#loginUserNickname}} 更新了组盘信息: {{#group.vehicleCode}}"; + + // ======================= TASK 任务信息 ======================= + String TASK_INFO = "任务信息"; + String TASK_INFO_OPERATE_TYPE = "操作任务状态"; + String TASK_INFO_OPERATE_SUCCESS = "{{#loginUserNickname}}对任务操作了{{#operateName}}"; } diff --git a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/controller/admin/oauth2/OAuth2OpenController.http b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/controller/admin/oauth2/OAuth2OpenController.http index cdcebbfb..11292c83 100644 --- a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/controller/admin/oauth2/OAuth2OpenController.http +++ b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/controller/admin/oauth2/OAuth2OpenController.http @@ -60,3 +60,24 @@ tenant-id: {{adminTenantId}} POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106 Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== tenant-id: {{adminTenantId}} + + + +@host = http://localhost:48080 +@clientId = huachuang-acs +@clientSecret = 1001open + +### 1、客户端模式 client_credentials(你最开始curl对应的请求) +POST http://localhost:48080/system/oauth2/token +Authorization: Bearer 32a8c752af4947d392809f954e32fadf +Content-Type: application/x-www-form-urlencoded + + +### +POST http://localhost:48080/system/oauth2/token +Authorization: Basic default admin123 +Content-Type: application/x-www-form-urlencoded + +grant_type = client_credentials + +### \ No newline at end of file diff --git a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/framework/security/config/SecurityConfiguration.java b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/framework/security/config/SecurityConfiguration.java index 4ac4c0b9..b767699d 100644 --- a/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/framework/security/config/SecurityConfiguration.java +++ b/nl-module-system/nl-module-system-server/src/main/java/cn/code/nl/module/system/framework/security/config/SecurityConfiguration.java @@ -32,6 +32,8 @@ public class SecurityConfiguration { .requestMatchers("/actuator/**").permitAll(); // RPC 服务的安全配置 registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); + // OAuth2 开放接口,无需登录即可访问 + registry.requestMatchers("/admin-api/system/oauth2/**").permitAll(); } }; diff --git a/nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml b/nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml index 4acc8c8e..c6d5d1a5 100644 --- a/nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml +++ b/nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml @@ -4,15 +4,15 @@ spring: cloud: nacos: server-addr: 192.168.81.193:8848 # Nacos 服务器地址 - username: # Nacos 账号 - password: # Nacos 密码 + username: nacos + password: nacos discovery: # 【配置中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP metadata: version: 1.0.0 # 服务实例的版本号,可用于灰度发布 config: # 【注册中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP --- #################### 数据库相关配置 #################### @@ -57,14 +57,14 @@ spring: primary: master datasource: master: - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: @@ -99,7 +99,7 @@ xxl: accessToken: 123456 # 执行器通讯TOKEN executor: ip: 192.168.81.193 - port: 9992 + port: 8992 --- #################### 服务保障相关配置 #################### diff --git a/nl-module-system/nl-module-system-server/src/main/resources/application-test.yaml b/nl-module-system/nl-module-system-server/src/main/resources/application-test.yaml index eadf7bfc..90c16fac 100644 --- a/nl-module-system/nl-module-system-server/src/main/resources/application-test.yaml +++ b/nl-module-system/nl-module-system-server/src/main/resources/application-test.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/api/TransportTaskApi.java b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/api/TransportTaskApi.java index 05928de0..e6567d05 100644 --- a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/api/TransportTaskApi.java +++ b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/api/TransportTaskApi.java @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import jakarta.validation.Valid; +import java.util.List; /** * Task 服务 RPC API 接口 @@ -34,6 +35,10 @@ public interface TransportTaskApi { @Operation(summary = "接收 LMS/WMS 业务处理结果") CommonResult receiveCallbackResult(@Valid @RequestBody TaskCallbackResultReqDTO reqDTO); + @PostMapping(PREFIX + "/issue") + @Operation(summary = "根据 taskId 下发搬运任务") + CommonResult issueTransportTask(@RequestParam("taskId") Long taskId); + @GetMapping(PREFIX + "/getTaskById") @Operation(summary = "根据 taskId 查询任务") CommonResult getTaskById(@RequestParam("taskId") Long taskId); @@ -41,4 +46,14 @@ public interface TransportTaskApi { @GetMapping(PREFIX + "/getTaskByCode") @Operation(summary = "根据 taskCode 查询任务") CommonResult getTaskByCode(@RequestParam("taskCode") String taskCode); + + @GetMapping(PREFIX + "/getRunningTaskByMaterialId") + @Operation(summary = "根据 materialId 和 ownerService 查询运行中任务") + CommonResult> getRunningTaskByMaterialId(@RequestParam("materialId") Long materialId, + @RequestParam("ownerService") String ownerService); + + @GetMapping(PREFIX + "/getRunningTaskByMaterialCode") + @Operation(summary = "根据 materialCode 和 ownerService 查询运行中任务") + CommonResult> getRunningTaskByMaterialCode(@RequestParam("materialCode") String materialCode, + @RequestParam("ownerService") String ownerService); } diff --git a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/dto/TaskInfoDTO.java b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/dto/TaskInfoDTO.java index b4be444f..12177096 100644 --- a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/dto/TaskInfoDTO.java +++ b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/dto/TaskInfoDTO.java @@ -91,6 +91,14 @@ public class TaskInfoDTO implements Serializable { * 载具编码2 */ private String vehicleCode2; + /** + * 物料id + */ + private Long materialId; + /** + * 物料编码 + */ + private String materialCode; /** * 车号 */ diff --git a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/dto/TransportTaskCreateReqDTO.java b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/dto/TransportTaskCreateReqDTO.java index 7a00c298..2334120f 100644 --- a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/dto/TransportTaskCreateReqDTO.java +++ b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/dto/TransportTaskCreateReqDTO.java @@ -21,14 +21,6 @@ public class TransportTaskCreateReqDTO { @NotEmpty(message = "业务归属服务不能为空") private String ownerService; - @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "业务类型不能为空") - private String bizType; - - @Schema(description = "业务侧标识", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "业务侧标识不能为空") - private String bizId; - @Schema(description = "业务回调处理器编码", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "业务回调处理器编码不能为空") private String handleCode; @@ -59,6 +51,12 @@ public class TransportTaskCreateReqDTO { @Schema(description = "载具编码2") private String vehicleCode2; + @Schema(description = "物料id") + private Long materialId; + + @Schema(description = "物料编码") + private String materialCode; + @Schema(description = "优先级") private String priority; diff --git a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/ErrorCodeConstants.java b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/ErrorCodeConstants.java index 41e2a96a..6d7f5290 100644 --- a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/ErrorCodeConstants.java +++ b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/ErrorCodeConstants.java @@ -16,5 +16,6 @@ public interface ErrorCodeConstants { ErrorCode TRANSPORT_TASK_RUNNING_ALREADY_EXIST = new ErrorCode(5005, "已存在运行中的任务"); ErrorCode TRANSPORT_TASK_OPERATION_NOT_SUPPORTED = new ErrorCode(5006, "不支持的任务操作类型"); ErrorCode TRANSPORT_TASK_ALREADY_FINAL = new ErrorCode(5007, "任务已处于终态,不允许操作"); + ErrorCode TRANSPORT_TASK_AUTO_ISSUE_NOT_ALLOW_MANUAL = new ErrorCode(5008, "自动任务不允许手动下发"); } diff --git a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskCreateModelEnum.java b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskCreateModelEnum.java new file mode 100644 index 00000000..6c919a64 --- /dev/null +++ b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskCreateModelEnum.java @@ -0,0 +1,22 @@ +package cn.code.nl.module.task.enums; + +import lombok.Getter; + +/** + * + * @Author: liyongde + * @Date: 2026/7/24 16:13 + */ +@Getter +public enum TaskCreateModelEnum { + AUTO("1", "自动创建"), + MANUAL("0", "创建人工"); + + private final String code; + private final String name; + + TaskCreateModelEnum(String code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskOperationTypeEnum.java b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskOperationTypeEnum.java index 508e2e22..d89540d6 100644 --- a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskOperationTypeEnum.java +++ b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskOperationTypeEnum.java @@ -15,6 +15,8 @@ public enum TaskOperationTypeEnum { EXECUTING("EXECUTING", "执行中", true, false), + ISSUE("ISSUE", "下发任务", false, true), + FINISHED("FINISHED", "完成任务", true, true), CANCELLED("CANCELLED", "取消任务", true, true), diff --git a/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/message/LockKeyConstants.java b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/message/LockKeyConstants.java new file mode 100644 index 00000000..689443b6 --- /dev/null +++ b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/message/LockKeyConstants.java @@ -0,0 +1,12 @@ +package cn.code.nl.module.task.message; + +/** + * 全局锁的key 或 前缀 + * @Author: liyongde + * @Date: 2026/7/27 10:16 + */ +public interface LockKeyConstants { + + /** 任务状态变更消费锁前缀 */ + String TASK_STATUS_CHANGE_LOCK_KEY = "task:task-status-change:"; +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/mq/message/TaskEventMessage.java b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/message/TaskEventMessage.java similarity index 67% rename from nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/mq/message/TaskEventMessage.java rename to nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/message/TaskEventMessage.java index 63ffe8a1..5d7752bc 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/mq/message/TaskEventMessage.java +++ b/nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/message/TaskEventMessage.java @@ -1,4 +1,4 @@ -package cn.code.nl.module.task.mq.message; +package cn.code.nl.module.task.message; import lombok.Data; @@ -10,10 +10,15 @@ import java.util.Map; @Data public class TaskEventMessage { + /** 任务完成 */ + public static final String EVENT_TYPE_FINISHED = "TASK_FINISHED"; + /** 任务取消 */ + public static final String EVENT_TYPE_CANCELLED = "TASK_CANCELLED"; + /** 事件ID */ private String eventId; - /** 事件类型:TASK_FINISHED / TASK_CANCELLED */ + /** 事件类型,取值:{@link #EVENT_TYPE_FINISHED} / {@link #EVENT_TYPE_CANCELLED} */ private String eventType; /** 任务ID */ diff --git a/nl-module-task/nl-module-task-server/pom.xml b/nl-module-task/nl-module-task-server/pom.xml index 31c04b18..0941178c 100644 --- a/nl-module-task/nl-module-task-server/pom.xml +++ b/nl-module-task/nl-module-task-server/pom.xml @@ -42,6 +42,11 @@ nl-module-task-api ${revision} + + cn.nl.cloud + nl-module-base-api + ${revision} + @@ -164,4 +169,4 @@ - \ No newline at end of file + diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/api/TransportTaskApiImpl.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/api/TransportTaskApiImpl.java index c397dcac..bd873ea6 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/api/TransportTaskApiImpl.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/api/TransportTaskApiImpl.java @@ -10,6 +10,8 @@ import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + import static cn.code.nl.framework.common.pojo.CommonResult.success; /** @@ -36,6 +38,12 @@ public class TransportTaskApiImpl implements TransportTaskApi { return success(true); } + @Override + public CommonResult issueTransportTask(Long taskId) { + transportTaskService.issueTransportTask(taskId); + return success(true); + } + @Override public CommonResult getTaskById(Long taskId) { return success(transportTaskService.getTaskInfoById(taskId)); @@ -45,4 +53,14 @@ public class TransportTaskApiImpl implements TransportTaskApi { public CommonResult getTaskByCode(String taskCode) { return success(transportTaskService.getTaskInfoByCode(taskCode)); } + + @Override + public CommonResult> getRunningTaskByMaterialId(Long materialId, String ownerService) { + return success(transportTaskService.getRunningTaskInfoByMaterialId(materialId, ownerService)); + } + + @Override + public CommonResult> getRunningTaskByMaterialCode(String materialCode, String ownerService) { + return success(transportTaskService.getRunningTaskInfoByMaterialCode(materialCode, ownerService)); + } } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/TransportTaskController.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/TransportTaskController.java index dc056006..5f452518 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/TransportTaskController.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/TransportTaskController.java @@ -1,112 +1,112 @@ -package cn.code.nl.module.task.controller.admin.transporttask; - -import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import org.springframework.validation.annotation.Validated; -import org.springframework.security.access.prepost.PreAuthorize; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Operation; - -import jakarta.validation.constraints.*; -import jakarta.validation.*; -import jakarta.servlet.http.*; -import java.util.*; -import java.io.IOException; - -import cn.code.nl.framework.common.pojo.PageParam; -import cn.code.nl.framework.common.pojo.PageResult; -import cn.code.nl.framework.common.pojo.CommonResult; -import cn.code.nl.framework.common.util.object.BeanUtils; -import static cn.code.nl.framework.common.pojo.CommonResult.success; - -import cn.code.nl.framework.excel.core.util.ExcelUtils; - -import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; -import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; - -import cn.code.nl.module.task.controller.admin.transporttask.vo.*; -import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO; -import cn.code.nl.module.task.service.transporttask.TransportTaskService; - -@Tag(name = "管理后台 - 搬运任务") -@RestController -@RequestMapping("/task/transport-task") -@Validated -public class TransportTaskController { - - @Resource - private TransportTaskService transportTaskService; - - @PostMapping("/create") - @Operation(summary = "创建搬运任务") - @PreAuthorize("@ss.hasPermission('task:transport-task:create')") - public CommonResult createTransportTask(@Valid @RequestBody TransportTaskSaveReqVO createReqVO) { - return success(transportTaskService.createTransportTask(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新搬运任务") - @PreAuthorize("@ss.hasPermission('task:transport-task:update')") - public CommonResult updateTransportTask(@Valid @RequestBody TransportTaskSaveReqVO updateReqVO) { - transportTaskService.updateTransportTask(updateReqVO); - return success(true); - } - - @PostMapping("/operate") - @Operation(summary = "PC 端操作搬运任务(完成/取消/强制完成)") - @PreAuthorize("@ss.hasPermission('task:transport-task:operate')") - public CommonResult operateTransportTask(@Valid @RequestBody TransportTaskOperateReqVO reqVO) { - transportTaskService.operateTransportTask(reqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除搬运任务") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('task:transport-task:delete')") - public CommonResult deleteTransportTask(@RequestParam("id") Long id) { - transportTaskService.deleteTransportTask(id); - return success(true); - } - - @DeleteMapping("/delete-list") - @Parameter(name = "ids", description = "编号", required = true) - @Operation(summary = "批量删除搬运任务") - @PreAuthorize("@ss.hasPermission('task:transport-task:delete')") - public CommonResult deleteTransportTaskList(@RequestParam("ids") List ids) { - transportTaskService.deleteTransportTaskListByIds(ids); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得搬运任务") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('task:transport-task:query')") - public CommonResult getTransportTask(@RequestParam("id") Long id) { - TransportTaskDO transportTask = transportTaskService.getTransportTask(id); - return success(BeanUtils.toBean(transportTask, TransportTaskRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得搬运任务分页") - @PreAuthorize("@ss.hasPermission('task:transport-task:query')") - public CommonResult> getTransportTaskPage(@Valid TransportTaskPageReqVO pageReqVO) { - PageResult pageResult = transportTaskService.getTransportTaskPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, TransportTaskRespVO.class)); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出搬运任务 Excel") - @PreAuthorize("@ss.hasPermission('task:transport-task:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportTransportTaskExcel(@Valid TransportTaskPageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = transportTaskService.getTransportTaskPage(pageReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "搬运任务.xls", "数据", TransportTaskRespVO.class, - BeanUtils.toBean(list, TransportTaskRespVO.class)); - } - -} \ No newline at end of file +package cn.code.nl.module.task.controller.admin.transporttask; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.task.controller.admin.transporttask.vo.*; +import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO; +import cn.code.nl.module.task.service.transporttask.TransportTaskService; + +@Tag(name = "管理后台 - 搬运任务") +@RestController +@RequestMapping("/task/transport-task") +@Validated +public class TransportTaskController { + + @Resource + private TransportTaskService transportTaskService; + + @PostMapping("/create") + @Operation(summary = "创建搬运任务") + @PreAuthorize("@ss.hasPermission('task:transport-task:create')") + public CommonResult createTransportTask(@Valid @RequestBody TransportTaskSaveReqVO createReqVO) { + return success(transportTaskService.createTransportTask(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新搬运任务") + @PreAuthorize("@ss.hasPermission('task:transport-task:update')") + public CommonResult updateTransportTask(@Valid @RequestBody TransportTaskSaveReqVO updateReqVO) { + transportTaskService.updateTransportTask(updateReqVO); + return success(true); + } + + @PostMapping("/operate") + @Operation(summary = "PC 端操作搬运任务(下发/完成/取消/强制完成)") + @PreAuthorize("@ss.hasPermission('task:transport-task:operate')") + public CommonResult operateTransportTask(@Valid @RequestBody TransportTaskOperateReqVO reqVO) { + transportTaskService.operateTransportTask(reqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除搬运任务") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('task:transport-task:delete')") + public CommonResult deleteTransportTask(@RequestParam("id") Long id) { + transportTaskService.deleteTransportTask(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除搬运任务") + @PreAuthorize("@ss.hasPermission('task:transport-task:delete')") + public CommonResult deleteTransportTaskList(@RequestParam("ids") List ids) { + transportTaskService.deleteTransportTaskListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得搬运任务") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('task:transport-task:query')") + public CommonResult getTransportTask(@RequestParam("id") Long id) { + TransportTaskDO transportTask = transportTaskService.getTransportTask(id); + return success(BeanUtils.toBean(transportTask, TransportTaskRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得搬运任务分页") + @PreAuthorize("@ss.hasPermission('task:transport-task:query')") + public CommonResult> getTransportTaskPage(@Valid TransportTaskPageReqVO pageReqVO) { + PageResult pageResult = transportTaskService.getTransportTaskPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, TransportTaskRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出搬运任务 Excel") + @PreAuthorize("@ss.hasPermission('task:transport-task:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportTransportTaskExcel(@Valid TransportTaskPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = transportTaskService.getTransportTaskPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "搬运任务.xls", "数据", TransportTaskRespVO.class, + BeanUtils.toBean(list, TransportTaskRespVO.class)); + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskOperateReqVO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskOperateReqVO.java index 1d56ada9..4fa3f70e 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskOperateReqVO.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskOperateReqVO.java @@ -19,7 +19,7 @@ public class TransportTaskOperateReqVO { @NotNull(message = "任务ID不能为空") private Long taskId; - @Schema(description = "操作类型:FINISHED/CANCELLED/FORCE-FINISH", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "操作类型:ISSUE/FINISHED/CANCELLED/FORCE-FINISH", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "操作类型不能为空") private String operationType; } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskPageReqVO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskPageReqVO.java index 1576581b..ddb17613 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskPageReqVO.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskPageReqVO.java @@ -34,6 +34,9 @@ public class TransportTaskPageReqVO extends PageParam { @Schema(description = "任务类型", example = "2") private String taskType; + @Schema(description = "任务类型及子类型编码列表", hidden = true) + private List taskTypeList; + @Schema(description = "任务状态(支持多选)", example = "[\"10\", \"50\"]") private List taskStatus; @@ -119,4 +122,4 @@ public class TransportTaskPageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; -} \ No newline at end of file +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskRespVO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskRespVO.java index 387e8aa4..80e71307 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskRespVO.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskRespVO.java @@ -1,162 +1,162 @@ -package cn.code.nl.module.task.controller.admin.transporttask.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.util.*; -import org.springframework.format.annotation.DateTimeFormat; -import java.time.LocalDateTime; -import cn.idev.excel.annotation.*; -import cn.code.nl.framework.excel.core.annotations.DictFormat; -import cn.code.nl.framework.excel.core.convert.DictConvert; - -@Schema(description = "管理后台 - 搬运任务 Response VO") -@Data -@ExcelIgnoreUnannotated -public class TransportTaskRespVO { - - @Schema(description = "任务标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "11528") - @ExcelProperty("任务标识") - private Long taskId; - - @Schema(description = "任务编码", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("任务编码") - private String taskCode; - - @Schema(description = "任务名称", example = "张三") - @ExcelProperty("任务名称") - private String taskName; - - @Schema(description = "业务归属服务:LMS/WMS,用于完成取消事件一级路由", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("业务归属服务:LMS/WMS,用于完成取消事件一级路由") - private String ownerService; - - @Schema(description = "业务类型", example = "2") - @ExcelProperty("业务类型") - private String bizType; - - @Schema(description = "业务侧标识", example = "31008") - @ExcelProperty("业务侧标识") - private String bizId; - - @Schema(description = "业务回调处理器编码") - @ExcelProperty("业务回调处理器编码") - private String handleCode; - - @Schema(description = "任务类型", example = "2") - @ExcelProperty("任务类型") - private String taskType; - - @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @ExcelProperty("任务状态") - private String taskStatus; - - @Schema(description = "ACS任务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("ACS任务类型") - private String acsTaskType; - - @Schema(description = "AGV系统类型", example = "1") - @ExcelProperty("AGV系统类型") - private String agvSystemType; - - @Schema(description = "ACS外部任务号") - @ExcelProperty("ACS外部任务号") - private String externalTaskNo; - - @Schema(description = "取货点1") - @ExcelProperty("取货点1") - private String pointCode1; - - @Schema(description = "放货点1") - @ExcelProperty("放货点1") - private String pointCode2; - - @Schema(description = "取货点2") - @ExcelProperty("取货点2") - private String pointCode3; - - @Schema(description = "放货点2") - @ExcelProperty("放货点2") - private String pointCode4; - - @Schema(description = "载具类型", example = "2") - @ExcelProperty("载具类型") - private String vehicleType; - - @Schema(description = "载具数量", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("载具数量") - private Long vehicleQty; - - @Schema(description = "载具编码") - @ExcelProperty("载具编码") - private String vehicleCode; - - @Schema(description = "载具编码2") - @ExcelProperty("载具编码2") - private String vehicleCode2; - - @Schema(description = "车号") - @ExcelProperty("车号") - private String carNo; - - @Schema(description = "优先级", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("优先级") - private String priority; - - @Schema(description = "生产区域") - @ExcelProperty("生产区域") - private String productArea; - - @Schema(description = "是否自动下发", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("是否自动下发") - private String isAutoIssue; - - @Schema(description = "任务组标识", example = "21169") - @ExcelProperty("任务组标识") - private Long taskGroupId; - - @Schema(description = "任务组顺序号", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("任务组顺序号") - private Long sortSeq; - - @Schema(description = "任务完成类型", example = "1") - @ExcelProperty("任务完成类型") - private String finishedType; - - @Schema(description = "业务回调状态:PENDING/SUCCESS/FAILED", example = "2") - @ExcelProperty("业务回调状态:PENDING/SUCCESS/FAILED") - private String callbackStatus; - - @Schema(description = "业务回调重试次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2146") - @ExcelProperty("业务回调重试次数") - private Integer callbackRetryCount; - - @Schema(description = "业务回调失败原因") - @ExcelProperty("业务回调失败原因") - private String callbackErrorMsg; - - @Schema(description = "生成方式", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty(value = "生成方式", converter = DictConvert.class) - @DictFormat("user_type") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 - private String createMode; - - @Schema(description = "创建任务请求参数") - @ExcelProperty("创建任务请求参数") - private String requestParam; - - @Schema(description = "下发ACS的AcsTaskDto扩展报文") - @ExcelProperty("下发ACS的AcsTaskDto扩展报文") - private String dispatchParam; - - @Schema(description = "ACS反馈参数") - @ExcelProperty("ACS反馈参数") - private String resultParam; - - @Schema(description = "备注", example = "你说的对") - @ExcelProperty("备注") - private String remark; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - -} \ No newline at end of file +package cn.code.nl.module.task.controller.admin.transporttask.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; +import cn.code.nl.framework.excel.core.annotations.DictFormat; +import cn.code.nl.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 搬运任务 Response VO") +@Data +@ExcelIgnoreUnannotated +public class TransportTaskRespVO { + + @Schema(description = "任务标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "11528") + @ExcelProperty("任务标识") + private Long taskId; + + @Schema(description = "任务编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("任务编码") + private String taskCode; + + @Schema(description = "任务名称", example = "张三") + @ExcelProperty("任务名称") + private String taskName; + + @Schema(description = "业务归属服务:LMS/WMS,用于完成取消事件一级路由", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("业务归属服务:LMS/WMS,用于完成取消事件一级路由") + private String ownerService; + + @Schema(description = "业务类型", example = "2") + @ExcelProperty("业务类型") + private String bizType; + + @Schema(description = "业务侧标识", example = "31008") + @ExcelProperty("业务侧标识") + private String bizId; + + @Schema(description = "业务回调处理器编码") + @ExcelProperty("业务回调处理器编码") + private String handleCode; + + @Schema(description = "任务类型", example = "2") + @ExcelProperty("任务类型") + private String taskType; + + @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("任务状态") + private String taskStatus; + + @Schema(description = "ACS任务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("ACS任务类型") + private String acsTaskType; + + @Schema(description = "AGV系统类型", example = "1") + @ExcelProperty("AGV系统类型") + private String agvSystemType; + + @Schema(description = "ACS外部任务号") + @ExcelProperty("ACS外部任务号") + private String externalTaskNo; + + @Schema(description = "取货点1") + @ExcelProperty("取货点1") + private String pointCode1; + + @Schema(description = "放货点1") + @ExcelProperty("放货点1") + private String pointCode2; + + @Schema(description = "取货点2") + @ExcelProperty("取货点2") + private String pointCode3; + + @Schema(description = "放货点2") + @ExcelProperty("放货点2") + private String pointCode4; + + @Schema(description = "载具类型", example = "2") + @ExcelProperty("载具类型") + private String vehicleType; + + @Schema(description = "载具数量", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("载具数量") + private Long vehicleQty; + + @Schema(description = "载具编码") + @ExcelProperty("载具编码") + private String vehicleCode; + + @Schema(description = "载具编码2") + @ExcelProperty("载具编码2") + private String vehicleCode2; + + @Schema(description = "车号") + @ExcelProperty("车号") + private String carNo; + + @Schema(description = "优先级", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("优先级") + private String priority; + + @Schema(description = "生产区域") + @ExcelProperty("生产区域") + private String productArea; + + @Schema(description = "是否自动下发", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("是否自动下发") + private String isAutoIssue; + + @Schema(description = "任务组标识", example = "21169") + @ExcelProperty("任务组标识") + private Long taskGroupId; + + @Schema(description = "任务组顺序号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("任务组顺序号") + private Long sortSeq; + + @Schema(description = "任务完成类型", example = "1") + @ExcelProperty("任务完成类型") + private String finishedType; + + @Schema(description = "业务回调状态:PENDING/SUCCESS/FAILED", example = "2") + @ExcelProperty("业务回调状态:PENDING/SUCCESS/FAILED") + private String callbackStatus; + + @Schema(description = "业务回调重试次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2146") + @ExcelProperty("业务回调重试次数") + private Integer callbackRetryCount; + + @Schema(description = "业务回调失败原因") + @ExcelProperty("业务回调失败原因") + private String callbackErrorMsg; + + @Schema(description = "生成方式", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "生成方式", converter = DictConvert.class) + @DictFormat("task_create_mode") + private String createMode; + + @Schema(description = "创建任务请求参数") + @ExcelProperty("创建任务请求参数") + private String requestParam; + + @Schema(description = "下发ACS的AcsTaskDto扩展报文") + @ExcelProperty("下发ACS的AcsTaskDto扩展报文") + private String dispatchParam; + + @Schema(description = "ACS反馈参数") + @ExcelProperty("ACS反馈参数") + private String resultParam; + + @Schema(description = "备注", example = "你说的对") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/convert/transporttask/TransportTaskConvert.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/convert/transporttask/TransportTaskConvert.java index 1f5ca666..fbdeab20 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/convert/transporttask/TransportTaskConvert.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/convert/transporttask/TransportTaskConvert.java @@ -5,6 +5,8 @@ import cn.code.nl.module.task.dto.TaskInfoDTO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +import java.util.List; + /** * 搬运任务 Convert * @@ -20,4 +22,9 @@ public interface TransportTaskConvert { * DO 转 RPC 全量信息 DTO(字段同名,零配置映射) */ TaskInfoDTO convert(TransportTaskDO bean); + + /** + * DO 列表转 RPC 全量信息 DTO 列表 + */ + List convertList(List list); } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/dataobject/transporttask/TransportTaskDO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/dataobject/transporttask/TransportTaskDO.java index 687fbc6c..a0c0c51a 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/dataobject/transporttask/TransportTaskDO.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/dataobject/transporttask/TransportTaskDO.java @@ -1,170 +1,178 @@ -package cn.code.nl.module.task.dal.dataobject.transporttask; - -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; -import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; - -/** - * 搬运任务 DO - * - * @author 诺力管理员 - */ -@TableName("task_transport_job") -@KeySequence("task_transport_job_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class TransportTaskDO extends BaseDO { - - /** - * 任务标识 - */ - @TableId - private Long taskId; - /** - * 任务编码 - */ - private String taskCode; - /** - * 任务名称 - */ - private String taskName; - /** - * 业务归属服务:LMS/WMS,用于完成取消事件一级路由 - */ - private String ownerService; - /** - * 业务类型 - */ - private String bizType; - /** - * 业务侧标识 - */ - private String bizId; - /** - * 业务回调处理器编码 - */ - private String handleCode; - /** - * 任务类型 - */ - private String taskType; - /** - * 任务状态 - */ - private String taskStatus; - /** - * ACS任务类型 - */ - private String acsTaskType; - /** - * AGV系统类型 - */ - private String agvSystemType; - /** - * ACS外部任务号 - */ - private String externalTaskNo; - /** - * 取货点1 - */ - private String pointCode1; - /** - * 放货点1 - */ - private String pointCode2; - /** - * 取货点2 - */ - private String pointCode3; - /** - * 放货点2 - */ - private String pointCode4; - /** - * 载具类型 - */ - private String vehicleType; - /** - * 载具数量 - */ - private Long vehicleQty; - /** - * 载具编码 - */ - private String vehicleCode; - /** - * 载具编码2 - */ - private String vehicleCode2; - /** - * 车号 - */ - private String carNo; - /** - * 优先级 - */ - private String priority; - /** - * 生产区域 - */ - private String productArea; - /** - * 是否自动下发 - */ - private String isAutoIssue; - /** - * 任务组标识 - */ - private Long taskGroupId; - /** - * 任务组顺序号 - */ - private Long sortSeq; - /** - * 任务完成类型 - */ - private String finishedType; - /** - * 业务回调状态:PENDING/SUCCESS/FAILED - */ - private String callbackStatus; - /** - * 业务回调重试次数 - */ - private Integer callbackRetryCount; - /** - * 业务回调失败原因 - */ - private String callbackErrorMsg; - /** - * 生成方式 - * - * 枚举 {@link TODO user_type 对应的类} - */ - private String createMode; - /** - * 创建任务请求参数 - */ - private String requestParam; - /** - * 下发ACS的AcsTaskDto扩展报文 - */ - private String dispatchParam; - /** - * ACS反馈参数 - */ - private String resultParam; - /** - * 备注 - */ - private String remark; - - -} \ No newline at end of file +package cn.code.nl.module.task.dal.dataobject.transporttask; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 搬运任务 DO + * + * @author 诺力管理员 + */ +@TableName("task_transport_job") +@KeySequence("task_transport_job_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TransportTaskDO extends BaseDO { + + /** + * 任务标识 + */ + @TableId + private Long taskId; + /** + * 任务编码 + */ + private String taskCode; + /** + * 任务名称 + */ + private String taskName; + /** + * 业务归属服务:LMS/WMS,用于完成取消事件一级路由 + */ + private String ownerService; + /** + * 业务类型 todo: 暂时不用 + */ + private String bizType; + /** + * 业务侧标识 todo: 暂时不用 + */ + private String bizId; + /** + * 业务回调处理器编码 + */ + private String handleCode; + /** + * 任务类型 + */ + private String taskType; + /** + * 任务状态 + */ + private String taskStatus; + /** + * ACS任务类型 + */ + private String acsTaskType; + /** + * AGV系统类型 + */ + private String agvSystemType; + /** + * ACS外部任务号 + */ + private String externalTaskNo; + /** + * 取货点1 + */ + private String pointCode1; + /** + * 放货点1 + */ + private String pointCode2; + /** + * 取货点2 + */ + private String pointCode3; + /** + * 放货点2 + */ + private String pointCode4; + /** + * 载具类型 + */ + private String vehicleType; + /** + * 载具数量 + */ + private Long vehicleQty; + /** + * 载具编码 + */ + private String vehicleCode; + /** + * 载具编码2 + */ + private String vehicleCode2; + /** + * 物料id + */ + private Long materialId; + /** + * 物料编码 + */ + private String materialCode; + /** + * 车号 + */ + private String carNo; + /** + * 优先级 + */ + private String priority; + /** + * 生产区域 + */ + private String productArea; + /** + * 是否自动下发 + */ + private String isAutoIssue; + /** + * 任务组标识 + */ + private Long taskGroupId; + /** + * 任务组顺序号 + */ + private Long sortSeq; + /** + * 任务完成类型 + */ + private String finishedType; + /** + * 业务回调状态:PENDING/SUCCESS/FAILED + */ + private String callbackStatus; + /** + * 业务回调重试次数 + */ + private Integer callbackRetryCount; + /** + * 业务回调失败原因 + */ + private String callbackErrorMsg; + /** + * 生成方式 + * + * 枚举 + */ + private String createMode; + /** + * 创建任务请求参数 + */ + private String requestParam; + /** + * 下发ACS的AcsTaskDto扩展报文 + */ + private String dispatchParam; + /** + * ACS反馈参数 + */ + private String resultParam; + /** + * 备注 + */ + private String remark; + + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java index 8acdbfac..3028c4f1 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java @@ -27,7 +27,7 @@ public interface TransportTaskMapper extends BaseMapperX { .eqIfPresent(TransportTaskDO::getBizType, reqVO.getBizType()) .eqIfPresent(TransportTaskDO::getBizId, reqVO.getBizId()) .eqIfPresent(TransportTaskDO::getHandleCode, reqVO.getHandleCode()) - .eqIfPresent(TransportTaskDO::getTaskType, reqVO.getTaskType()) + .inIfPresent(TransportTaskDO::getTaskType, reqVO.getTaskTypeList()) .inIfPresent(TransportTaskDO::getTaskStatus, reqVO.getTaskStatus()) .eqIfPresent(TransportTaskDO::getAcsTaskType, reqVO.getAcsTaskType()) .eqIfPresent(TransportTaskDO::getAgvSystemType, reqVO.getAgvSystemType()) @@ -66,6 +66,17 @@ public interface TransportTaskMapper extends BaseMapperX { return selectOne(TransportTaskDO::getTaskCode, taskCode); } + /** + * 查询自动下发的待下发任务 + */ + default List selectAutoIssueReadyList() { + return selectList(new LambdaQueryWrapperX() + .eq(TransportTaskDO::getIsAutoIssue, "1") + .eq(TransportTaskDO::getTaskStatus, TransportTaskStatusEnum.READY.getCode()) + .orderByDesc(TransportTaskDO::getPriority) + .orderByAsc(TransportTaskDO::getTaskId)); + } + /** * 按业务归属查询未完结任务(幂等校验用) */ @@ -76,6 +87,28 @@ public interface TransportTaskMapper extends BaseMapperX { .lt(TransportTaskDO::getTaskStatus, TransportTaskStatusEnum.FINISHED_CALLBACK_PENDING.getCode())); } + /** + * 根据物料ID和业务归属查询运行中任务 + */ + default List selectRunningListByMaterialId(Long materialId, String ownerService) { + return selectList(new LambdaQueryWrapperX() + .eq(TransportTaskDO::getMaterialId, materialId) + .eq(TransportTaskDO::getOwnerService, ownerService) + .lt(TransportTaskDO::getTaskStatus, TransportTaskStatusEnum.FINISHED_CALLBACK_PENDING.getCode()) + .orderByDesc(TransportTaskDO::getTaskId)); + } + + /** + * 根据物料编码和业务归属查询运行中任务 + */ + default List selectRunningListByMaterialCode(String materialCode, String ownerService) { + return selectList(new LambdaQueryWrapperX() + .eq(TransportTaskDO::getMaterialCode, materialCode) + .eq(TransportTaskDO::getOwnerService, ownerService) + .lt(TransportTaskDO::getTaskStatus, TransportTaskStatusEnum.FINISHED_CALLBACK_PENDING.getCode()) + .orderByDesc(TransportTaskDO::getTaskId)); + } + /** * 条件更新任务状态(CAS 抢占) */ @@ -87,4 +120,16 @@ public interface TransportTaskMapper extends BaseMapperX { return update(null, wrapper) > 0; } -} \ No newline at end of file + /** + * 更新下发结果 + */ + default void updateIssueResult(Long taskId, String taskStatus, String resultParam, String remark) { + TransportTaskDO updateObj = new TransportTaskDO(); + updateObj.setTaskId(taskId); + updateObj.setTaskStatus(taskStatus); + updateObj.setResultParam(resultParam); + updateObj.setRemark(remark); + updateById(updateObj); + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/enums/AcsApiConstants.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/enums/AcsApiConstants.java new file mode 100644 index 00000000..7fa5265e --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/enums/AcsApiConstants.java @@ -0,0 +1,16 @@ +package cn.code.nl.module.task.enums; + +/** + * 请求ACS 接口 定义常量 + * @Author: liyongde + * @Date: 2026/7/27 9:45 + */ +public interface AcsApiConstants { + + /** 下发任务 */ + String ACS_TASK_API = "/acs-api/wms/issue-task"; + + /** 检测任务 */ + String ACS_OPERATE_CHECK_API = "/acs-api/wms/check-enable-operate"; + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/enums/package-info.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/enums/package-info.java new file mode 100644 index 00000000..4cc3285b --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/enums/package-info.java @@ -0,0 +1,6 @@ +/** + * 任务模块自身使用的枚举 + * @Author: liyongde + * @Date: 2026/7/27 9:44 + */ +package cn.code.nl.module.task.enums; \ No newline at end of file diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/TaskScheduleJob.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/TaskScheduleJob.java index 3fc005da..40540120 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/TaskScheduleJob.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/TaskScheduleJob.java @@ -1,28 +1,38 @@ package cn.code.nl.module.task.job; import cn.code.nl.framework.tenant.core.job.TenantJob; +import cn.code.nl.module.task.service.transporttask.TransportTaskService; import com.xxl.job.core.context.XxlJobHelper; import com.xxl.job.core.handler.annotation.XxlJob; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** * 任务相关的定时任务 + * * @Author: liyongde * @Date: 2026/7/13 14:01 */ +@Slf4j @Component public class TaskScheduleJob { + @Resource + private TransportTaskService transportTaskService; + @XxlJob("autoTaskAssignmentJob") @TenantJob public void autoTaskAssignmentJob() { + log.info("自动下发任务开始....."); XxlJobHelper.log("自动下发任务开始"); - // todo: 具体业务 + transportTaskService.autoIssueTransportTasks(); - String msg = "自动下发任务成功"; + String msg = "自动下发任务结束"; XxlJobHelper.log(msg); XxlJobHelper.handleSuccess(msg); + log.info(msg); } } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsIssueResultRespDTO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsIssueResultRespDTO.java new file mode 100644 index 00000000..388bce41 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsIssueResultRespDTO.java @@ -0,0 +1,37 @@ +package cn.code.nl.module.task.job.dto; + +import cn.code.nl.framework.common.pojo.AcsBaseRespDTO; +import lombok.Data; + +import java.util.List; + +/** + * ACS 任务下发响应 + */ +@Data +public class AcsIssueResultRespDTO extends AcsBaseRespDTO { + + /** + * 下发失败的任务 + */ + private List failedTasks; + + /** + * ACS 失败任务明细 + */ + @Data + public static class FailedTask { + + /** + * 任务标识 + */ + private Long taskId; + + /** + * 错误信息 + */ + private String errorMessage; + + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsOperateCheckReqDTO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsOperateCheckReqDTO.java new file mode 100644 index 00000000..876c5865 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsOperateCheckReqDTO.java @@ -0,0 +1,31 @@ +package cn.code.nl.module.task.job.dto; + +import lombok.Data; + +/** + * ACS 任务操作校验请求 + */ +@Data +public class AcsOperateCheckReqDTO { + + /** + * 任务标识 + */ + private Long taskId; + + /** + * 任务编码 + */ + private String taskCode; + + /** + * 操作类型 + */ + private String operationType; + + /** + * 生产区域 + */ + private String productArea; + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsOperateCheckRespDTO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsOperateCheckRespDTO.java new file mode 100644 index 00000000..ab4278bb --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsOperateCheckRespDTO.java @@ -0,0 +1,32 @@ +package cn.code.nl.module.task.job.dto; + +import cn.code.nl.framework.common.pojo.AcsBaseRespDTO; +import lombok.Data; + +/** + * ACS 任务操作校验响应 + */ +@Data +public class AcsOperateCheckRespDTO extends AcsBaseRespDTO { + + /** + * 是否允许操作 + */ + private Boolean enableOperate; + + /** + * 是否允许操作,兼容 ACS 字段 + */ + private Boolean canOperate; + + /** + * 是否允许操作,兼容通用 data 字段 + */ + private Boolean data; + + /** + * 不允许操作的原因 + */ + private String message; + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsTaskDTO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsTaskDTO.java new file mode 100644 index 00000000..7aa6bf79 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsTaskDTO.java @@ -0,0 +1,74 @@ +package cn.code.nl.module.task.job.dto; + +import lombok.Data; + +import cn.code.nl.framework.common.pojo.AcsBaseReqDTO; + +import java.util.Map; + +/** + * 下发给ACS的实体 + * + * @Author: liyongde + * @Date: 2026/7/23 17:10 + */ +@Data +public class AcsTaskDTO extends AcsBaseReqDTO { + /** + * 任务标识 + */ + private Long taskId; + /** + * 任务编码 + */ + private String taskCode; + /** + * 取货点1 + */ + private String startDeviceCode; + /** + * 放货点1 + */ + private String nextDeviceCode; + /** + * 取货点2 + */ + private String startDeviceCode2; + /** + * 放货点2 + */ + private String nextDeviceCode2; + /** + * 优先级 + */ + private String priority; + /** + * 载具号 + */ + private String vehicleCode; + /** + * 载具号2 + */ + private String vehicleCode2; + /** + * 任务类型 + */ + private String taskType; + /** + * Agv系统类型 + */ + private String agvSystemType; + + /** + * 备注 + */ + private String remark; + /** + * 扩展参数 + */ + private Map payload; + /** + * 生产区域 + */ + private String productArea; +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskBusinessOperationManager.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskBusinessOperationManager.java index 1d24db11..7c492c2c 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskBusinessOperationManager.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskBusinessOperationManager.java @@ -11,7 +11,6 @@ import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper; import cn.code.nl.module.task.dto.AcsFeedbackReqDTO; import cn.code.nl.module.task.enums.AcsBusinessOperationTypeEnum; import cn.code.nl.module.task.enums.TransportTaskStatusEnum; -import com.alibaba.fastjson.JSON; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -104,68 +103,63 @@ public class TransportTaskBusinessOperationManager { TaskCommonApi serverApi = taskCommonApiFactory.getByServerName(task.getOwnerService()); CommonResult result = serverApi.doHandlePicked(buildReq(task, reqDTO)); - return result.getData(); + return result.getCheckedData(); } /** * 处理二次请求 */ private AcsApplyActionRespVO handleApplyAgain(TransportTaskDO task, AcsFeedbackReqDTO reqDTO) { - // TODO 二次请求业务待开发 - log.info("二次请求业务待开发, taskId={}", task.getTaskId()); + log.info("二次请求, taskId={}", task.getTaskId()); // 调用具体的服务去执行取货完成操作。 TaskCommonApi serverApi = taskCommonApiFactory.getByServerName(task.getOwnerService()); CommonResult result = serverApi.doHandleApplyAgain(buildReq(task, reqDTO)); - return result.getData(); + return result.getCheckedData(); } /** * 处理请求放货 */ private Object handleRequestRelease(TransportTaskDO task, AcsFeedbackReqDTO reqDTO) { - // TODO 请求放货业务待开发 - log.info("请求放货业务待开发, taskId={}", task.getTaskId()); + log.info("请求放货, taskId={}", task.getTaskId()); TaskCommonApi serverApi = taskCommonApiFactory.getByServerName(task.getOwnerService()); CommonResult result = serverApi.doHandleRequestRelease(buildReq(task, reqDTO)); - return result.getData(); + return result.getCheckedData(); } /** * 处理请求取货 */ private Object handleRequestPick(TransportTaskDO task, AcsFeedbackReqDTO reqDTO) { - // TODO 请求取货业务待开发 - log.info("请求取货业务待开发, taskId={}", task.getTaskId()); + log.info("请求取货, taskId={}", task.getTaskId()); TaskCommonApi serverApi = taskCommonApiFactory.getByServerName(task.getOwnerService()); CommonResult result = serverApi.doHandleRequestPick(buildReq(task, reqDTO)); - return result.getData(); + return result.getCheckedData(); } /** * 处理请求离开 */ private Object handleRequestLeave(TransportTaskDO task, AcsFeedbackReqDTO reqDTO) { - // TODO 请求离开业务待开发 - log.info("请求离开业务待开发, taskId={}", task.getTaskId()); + log.info("请求离开, taskId={}", task.getTaskId()); TaskCommonApi serverApi = taskCommonApiFactory.getByServerName(task.getOwnerService()); CommonResult result = serverApi.doHandleRequestLeave(buildReq(task, reqDTO)); - return result.getData(); + return result.getCheckedData(); } /** * 处理请求进入 */ private Object handleRequestEnter(TransportTaskDO task, AcsFeedbackReqDTO reqDTO) { - // TODO 请求进入业务待开发 - log.info("请求进入业务待开发, taskId={}", task.getTaskId()); + log.info("请求进入, taskId={}", task.getTaskId()); TaskCommonApi serverApi = taskCommonApiFactory.getByServerName(task.getOwnerService()); CommonResult result = serverApi.doHandleRequestEnter(buildReq(task, reqDTO)); - return result.getData(); + return result.getCheckedData(); } /** @@ -175,7 +169,7 @@ public class TransportTaskBusinessOperationManager { AcsApplyActionRespVO respVO = new AcsApplyActionRespVO(); respVO.setTaskId(task.getTaskId()); respVO.setTaskCode(task.getTaskCode()); - respVO.setData(JSON.parseObject(JSON.toJSONString(data))); + respVO.setData(data); return respVO; } /** @@ -185,7 +179,7 @@ public class TransportTaskBusinessOperationManager { TaskStatusCallApiReqDTO req = new TaskStatusCallApiReqDTO(); req.setTaskId(task.getTaskId()); req.setTaskCode(task.getTaskCode()); - req.setStatus(TransportTaskStatusEnum.PICKED.getCode()); + req.setStatus(reqDTO.getStatus()); req.setOwnerService(task.getOwnerService()); req.setBizType(task.getBizType()); req.setBizId(task.getBizId()); diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskIssueManager.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskIssueManager.java new file mode 100644 index 00000000..53af8afe --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskIssueManager.java @@ -0,0 +1,139 @@ +package cn.code.nl.module.task.manage; + +import cn.code.nl.framework.common.exception.ServiceException; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.http.AcsUtil; +import cn.code.nl.framework.common.util.json.JsonUtils; +import cn.code.nl.module.infra.api.config.ConfigApi; +import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO; +import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper; +import cn.code.nl.module.task.enums.TransportTaskStatusEnum; +import cn.code.nl.module.task.job.dto.AcsIssueResultRespDTO; +import cn.code.nl.module.task.job.dto.AcsTaskDTO; +import cn.code.nl.module.task.utils.AcsTaskUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static cn.code.nl.module.task.enums.AcsApiConstants.ACS_TASK_API; + +/** + * 搬运任务下发管理器 + */ +@Slf4j +@Component +public class TransportTaskIssueManager { + + private static final String ACS_SERVER_ADDRESS_CONFIG_SUFFIX = "-acs-server-address"; + + @Resource + private TransportTaskMapper transportTaskMapper; + + @Resource + private ConfigApi configApi; + + /** + * 按生产区域分组下发任务 + * + * @param tasks 待下发任务 + */ + public void issueTasks(List tasks) { + tasks.stream() + .filter(task -> StrUtil.isBlank(task.getProductArea())) + .forEach(task -> + updateIssueFailed(task.getTaskId(), "生产区域为空,无法获取 ACS 服务地址", null)); + Map> taskMap = tasks.stream() + .filter(task -> StrUtil.isNotBlank(task.getProductArea())) + .collect(Collectors.groupingBy(TransportTaskDO::getProductArea)); + taskMap.forEach(this::issueProductAreaTasks); + } + + /** + * 下发单个生产区域的任务 + * + * @param productArea 生产区域 + * @param tasks 待下发任务 + */ + private void issueProductAreaTasks(String productArea, List tasks) { + List acsTasks = tasks.stream().map(AcsTaskUtil::buildAcsTaskDTO).toList(); + String requestJson = JsonUtils.toJsonString(acsTasks); + try { + String serverAddress = getAcsServerAddress(productArea); + AcsIssueResultRespDTO result = AcsUtil.post(serverAddress, ACS_TASK_API, acsTasks, AcsIssueResultRespDTO.class); + handleIssueResult(tasks, result); + } catch (Exception ex) { + log.error("自动下发任务失败,productArea={},tasks={}", productArea, requestJson, ex); + tasks.forEach(task -> updateIssueFailed(task.getTaskId(), ex.getMessage(), null)); + } + } + + /** + * 获取 ACS 服务地址 + * + * @param productArea 生产区域 + * @return ACS 服务地址 + */ + private String getAcsServerAddress(String productArea) { + String configKey = productArea + ACS_SERVER_ADDRESS_CONFIG_SUFFIX; + CommonResult result = configApi.getConfigValueByKey(configKey); + String serverAddress = result.getCheckedData(); + if (StrUtil.isBlank(serverAddress)) { + throw new ServiceException(500, "未配置 ACS 服务地址:" + configKey); + } + return serverAddress; + } + + /** + * 处理 ACS 下发响应 + * + * @param tasks 本次下发任务 + * @param result ACS 响应 + */ + private void handleIssueResult(List tasks, AcsIssueResultRespDTO result) { + if (result == null) { + tasks.forEach(task -> updateIssueFailed(task.getTaskId(), "ACS 返回为空", null)); + return; + } + String resultJson = JsonUtils.toJsonString(result); + List failedTasks = result.getFailedTasks() == null + ? Collections.emptyList() + : result.getFailedTasks(); + if (Boolean.FALSE.equals(result.getSuccess()) && CollUtil.isEmpty(failedTasks)) { + String errorMessage = StrUtil.blankToDefault(result.getMsg(), "ACS 下发失败"); + tasks.forEach(task -> updateIssueFailed(task.getTaskId(), errorMessage, resultJson)); + return; + } + Map failedTaskMap = failedTasks.stream() + .filter(failedTask -> failedTask.getTaskId() != null) + .collect(Collectors.toMap(AcsIssueResultRespDTO.FailedTask::getTaskId, Function.identity(), (first, second) -> first)); + Set failedTaskIds = failedTaskMap.keySet(); + for (TransportTaskDO task : tasks) { + if (failedTaskIds.contains(task.getTaskId())) { + updateIssueFailed(task.getTaskId(), failedTaskMap.get(task.getTaskId()).getErrorMessage(), resultJson); + } else { + transportTaskMapper.updateIssueResult(task.getTaskId(), TransportTaskStatusEnum.ISSUED.getCode(), resultJson, null); + } + } + } + + /** + * 更新任务为下发失败 + * + * @param taskId 任务标识 + * @param errorMessage 错误信息 + * @param resultJson ACS 响应 JSON + */ + private void updateIssueFailed(Long taskId, String errorMessage, String resultJson) { + transportTaskMapper.updateIssueResult(taskId, TransportTaskStatusEnum.FAILED.getCode(), resultJson, errorMessage); + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskOperateCheckManager.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskOperateCheckManager.java new file mode 100644 index 00000000..bd6085bd --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskOperateCheckManager.java @@ -0,0 +1,140 @@ +package cn.code.nl.module.task.manage; + +import cn.code.nl.framework.common.exception.ServiceException; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.http.AcsUtil; +import cn.code.nl.framework.common.util.json.JsonUtils; +import cn.code.nl.module.infra.api.config.ConfigApi; +import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO; +import cn.code.nl.module.task.enums.TaskOperationTypeEnum; +import cn.code.nl.module.task.job.dto.AcsOperateCheckRespDTO; +import cn.code.nl.module.task.job.dto.AcsOperateCheckReqDTO; +import cn.hutool.core.util.StrUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import static cn.code.nl.module.task.enums.AcsApiConstants.ACS_OPERATE_CHECK_API; + +/** + * PC 端任务操作 ACS 校验管理器 + */ +@Slf4j +@Component +public class TransportTaskOperateCheckManager { + + private static final String TASK_OPERATE_ENABLE_CONFIG_KEY = "task-operate-enable"; + private static final String TASK_OPERATE_ENABLE_VALUE = "1"; + private static final String ACS_SERVER_ADDRESS_CONFIG_SUFFIX = "-acs-server-address"; + + @Resource + private ConfigApi configApi; + + /** + * 按配置校验 PC 端是否允许完成或取消任务 + * + * @param task 任务信息 + * @param type 操作类型 + */ + public void checkEnableOperate(TransportTaskDO task, TaskOperationTypeEnum type) { + if (!needCheckAcs()) { + return; + } + String serverAddress = getAcsServerAddress(task.getProductArea()); + AcsOperateCheckReqDTO reqDTO = buildReqDTO(task, type); + AcsOperateCheckRespDTO result; + try { + result = AcsUtil.post(serverAddress, ACS_OPERATE_CHECK_API, reqDTO, AcsOperateCheckRespDTO.class); + } catch (ServiceException ex) { + log.error("ACS 操作校验请求失败,reqDTO={}", JsonUtils.toJsonString(reqDTO), ex); + throw ex; + } catch (Exception ex) { + log.error("ACS 操作校验请求失败,reqDTO={}", JsonUtils.toJsonString(reqDTO), ex); + throw new ServiceException(500, "ACS操作校验失败"); + } + handleCheckResult(reqDTO, result); + } + + /** + * 判断是否需要请求 ACS 校验 + */ + private boolean needCheckAcs() { + CommonResult result = configApi.getConfigValueByKey(TASK_OPERATE_ENABLE_CONFIG_KEY); + return TASK_OPERATE_ENABLE_VALUE.equals(result.getCheckedData()); + } + + /** + * 获取 ACS 服务地址 + * + * @param productArea 生产区域 + * @return ACS 服务地址 + */ + private String getAcsServerAddress(String productArea) { + if (StrUtil.isBlank(productArea)) { + throw new ServiceException(500, "生产区域为空,无法获取 ACS 服务地址"); + } + String configKey = productArea + ACS_SERVER_ADDRESS_CONFIG_SUFFIX; + CommonResult result = configApi.getConfigValueByKey(configKey); + String serverAddress = result.getCheckedData(); + if (StrUtil.isBlank(serverAddress)) { + throw new ServiceException(500, "未配置 ACS 服务地址:" + configKey); + } + return serverAddress; + } + + /** + * 构建 ACS 操作校验请求 + */ + private AcsOperateCheckReqDTO buildReqDTO(TransportTaskDO task, TaskOperationTypeEnum type) { + AcsOperateCheckReqDTO reqDTO = new AcsOperateCheckReqDTO(); + reqDTO.setTaskId(task.getTaskId()); + reqDTO.setTaskCode(task.getTaskCode()); + reqDTO.setOperationType(type.getCode()); + reqDTO.setProductArea(task.getProductArea()); + return reqDTO; + } + + /** + * 处理 ACS 操作校验结果 + */ + private void handleCheckResult(AcsOperateCheckReqDTO reqDTO, AcsOperateCheckRespDTO result) { + if (result == null) { + throw new ServiceException(500, "ACS 操作校验返回为空"); + } + Boolean enableOperate = getEnableOperate(result); + if (Boolean.TRUE.equals(enableOperate)) { + return; + } + String message = getMessage(result); + log.warn("ACS 拒绝 PC 端任务操作,reqDTO={},result={}", + JsonUtils.toJsonString(reqDTO), JsonUtils.toJsonString(result)); + throw new ServiceException(500, message); + } + + /** + * 获取 ACS 是否允许操作 + */ + private Boolean getEnableOperate(AcsOperateCheckRespDTO result) { + if (result.getEnableOperate() != null) { + return result.getEnableOperate(); + } + if (result.getCanOperate() != null) { + return result.getCanOperate(); + } + if (result.getData() != null) { + return result.getData(); + } + return result.getSuccess(); + } + + /** + * 获取 ACS 拒绝原因 + */ + private String getMessage(AcsOperateCheckRespDTO result) { + if (StrUtil.isNotBlank(result.getMessage())) { + return result.getMessage(); + } + return StrUtil.blankToDefault(result.getMsg(), "ACS 不允许执行该操作"); + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskOperationManager.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskOperationManager.java index e0c3785f..28e334b5 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskOperationManager.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskOperationManager.java @@ -9,7 +9,7 @@ import cn.code.nl.module.task.enums.FinishedTypeEnum; import cn.code.nl.module.task.enums.TaskEventTypeEnum; import cn.code.nl.module.task.enums.TaskOperationTypeEnum; import cn.code.nl.module.task.enums.TransportTaskStatusEnum; -import cn.code.nl.module.task.mq.message.TaskEventMessage; +import cn.code.nl.module.task.message.TaskEventMessage; import cn.code.nl.module.task.mq.producer.TaskEventProducer; import cn.hutool.core.util.StrUtil; import jakarta.annotation.PostConstruct; @@ -18,13 +18,21 @@ import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.stereotype.Component; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import java.util.EnumMap; +import java.util.List; import java.util.Map; import java.util.function.BiConsumer; +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_AUTO_ISSUE_NOT_ALLOW_MANUAL; +import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_STATUS_NOT_ALLOW; import static cn.code.nl.module.task.framework.common.util.TaskUtil.isAllowedFrom; +import static cn.code.nl.module.task.message.LockKeyConstants.TASK_STATUS_CHANGE_LOCK_KEY; + /** * 搬运任务状态操作分发管理器 */ @@ -38,6 +46,9 @@ public class TransportTaskOperationManager { @Resource private TaskEventProducer taskEventProducer; + @Resource + private TransportTaskIssueManager transportTaskIssueManager; + @Resource private RedissonClient redissonClient; @@ -51,6 +62,7 @@ public class TransportTaskOperationManager { @PostConstruct public void initOperationHandlers() { operationHandlers.put(TaskOperationTypeEnum.EXECUTING, this::handleExecuting); + operationHandlers.put(TaskOperationTypeEnum.ISSUE, (task, reqDTO) -> handleIssue(task)); operationHandlers.put(TaskOperationTypeEnum.FINISHED, this::handleFinished); operationHandlers.put(TaskOperationTypeEnum.CANCELLED, this::handleCancelled); operationHandlers.put(TaskOperationTypeEnum.FORCE_FINISH, (task, reqDTO) -> handleForceFinish(task)); @@ -60,7 +72,7 @@ public class TransportTaskOperationManager { * 按操作类型查路由表分发 */ public void dispatchOperation(TransportTaskDO task, TaskOperationTypeEnum type, AcsFeedbackReqDTO reqDTO) { - RLock lock = redissonClient.getLock(String.valueOf(task.getTaskId())); + RLock lock = redissonClient.getLock(TASK_STATUS_CHANGE_LOCK_KEY + task.getTaskId()); if (lock.tryLock()) { try { BiConsumer handler = operationHandlers.get(type); @@ -70,7 +82,11 @@ public class TransportTaskOperationManager { } handler.accept(task, reqDTO); } catch (Exception ex) { + if (ex instanceof ServiceException serviceException) { + throw serviceException; + } log.error("[messageResend][执行异常][lockKey={}]", task.getTaskId(), ex); + throw new ServiceException(500, ex.getMessage()); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); @@ -81,6 +97,19 @@ public class TransportTaskOperationManager { } } + /** + * 处理下发任务 + */ + private void handleIssue(TransportTaskDO task) { + if ("1".equals(task.getIsAutoIssue())) { + throw exception(TRANSPORT_TASK_AUTO_ISSUE_NOT_ALLOW_MANUAL); + } + if (!TransportTaskStatusEnum.READY.getCode().equals(task.getTaskStatus())) { + throw exception(TRANSPORT_TASK_STATUS_NOT_ALLOW); + } + transportTaskIssueManager.issueTasks(List.of(task)); + } + /** * 处理执行中 */ @@ -116,7 +145,19 @@ public class TransportTaskOperationManager { task.setCallbackStatus(CallbackStatusEnum.PENDING.getCode()); transportTaskMapper.updateById(task); - publishEvent(task, TaskEventTypeEnum.TASK_FINISHED, reqDTO.getPayload()); + // MQ 在事务提交后发送,避免 Consumer 读到未提交的数据 + Map payload = reqDTO.getPayload(); + if (TransactionSynchronizationManager.isSynchronizationActive()) { + TransactionSynchronizationManager.registerSynchronization( + new TransactionSynchronization() { + @Override + public void afterCommit() { + publishEvent(task, TaskEventTypeEnum.TASK_FINISHED, payload); + } + }); + } else { + publishEvent(task, TaskEventTypeEnum.TASK_FINISHED, payload); + } } /** @@ -139,7 +180,19 @@ public class TransportTaskOperationManager { task.setCallbackStatus(CallbackStatusEnum.PENDING.getCode()); transportTaskMapper.updateById(task); - publishEvent(task, TaskEventTypeEnum.TASK_CANCELLED, reqDTO.getPayload()); + // MQ 在事务提交后发送,避免 Consumer 读到未提交的数据 + Map payload = reqDTO.getPayload(); + if (TransactionSynchronizationManager.isSynchronizationActive()) { + TransactionSynchronizationManager.registerSynchronization( + new TransactionSynchronization() { + @Override + public void afterCommit() { + publishEvent(task, TaskEventTypeEnum.TASK_CANCELLED, payload); + } + }); + } else { + publishEvent(task, TaskEventTypeEnum.TASK_CANCELLED, payload); + } } /** diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/mq/producer/TaskEventProducer.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/mq/producer/TaskEventProducer.java index 4168d271..0c5c14ae 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/mq/producer/TaskEventProducer.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/mq/producer/TaskEventProducer.java @@ -1,24 +1,26 @@ package cn.code.nl.module.task.mq.producer; -import cn.code.nl.module.task.mq.message.TaskEventMessage; +import cn.code.nl.module.task.message.TaskEventMessage; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.stereotype.Component; import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Value; import java.util.UUID; /** * 任务事件 MQ 生产者 *

- * Topic: TASK_EVENT_TOPIC + * Topic 从 YAML 配置 rocketmq.consumer.task.topic 读取 * Tag: ownerService (LMS / WMS) */ @Slf4j @Component public class TaskEventProducer { - private static final String TOPIC = "TASK_EVENT_TOPIC"; + @Value("${rocketmq.consumer.task.topic}") + private String topic; @Resource private RocketMQTemplate rocketMQTemplate; @@ -29,12 +31,9 @@ public class TaskEventProducer { * @param message 事件消息 */ public void publishEvent(TaskEventMessage message) { - // 补齐 eventId - if (message.getEventId() == null || message.getEventId().isEmpty()) { - message.setEventId(UUID.randomUUID().toString()); - } + message.setEventId(message.getTaskId().toString()); - String destination = TOPIC + "_" + message.getOwnerService(); + String destination = message.getOwnerService() + "_" + topic; try { rocketMQTemplate.syncSend(destination, message); log.info("MQ 发送成功, destination={}, taskId={}, eventType={}", diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java index b7fdb0ef..92d41856 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java @@ -76,6 +76,13 @@ public interface TransportTaskService { */ void operateTransportTask(@Valid TransportTaskOperateReqVO reqVO); + /** + * 根据任务ID下发搬运任务到 ACS + * + * @param taskId 任务ID + */ + void issueTransportTask(Long taskId); + /** * 根据 taskId 查询任务全量信息(RPC 用,自动过滤逻辑删除,查不到返回 null) * @@ -92,4 +99,27 @@ public interface TransportTaskService { */ TaskInfoDTO getTaskInfoByCode(String taskCode); + /** + * 根据物料ID和业务归属查询运行中任务(状态小于75) + * + * @param materialId 物料ID + * @param ownerService 业务归属服务 + * @return 运行中任务列表 + */ + List getRunningTaskInfoByMaterialId(Long materialId, String ownerService); + + /** + * 根据物料编码和业务归属查询运行中任务(状态小于75) + * + * @param materialCode 物料编码 + * @param ownerService 业务归属服务 + * @return 运行中任务列表 + */ + List getRunningTaskInfoByMaterialCode(String materialCode, String ownerService); + + /** + * 自动下发待下发任务到 ACS + */ + void autoIssueTransportTasks(); + } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java index f8e26b69..8181a758 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java @@ -2,6 +2,8 @@ package cn.code.nl.module.task.service.transporttask; import cn.code.nl.framework.common.pojo.PageResult; import cn.code.nl.framework.common.util.object.BeanUtils; +import cn.code.nl.framework.security.core.util.SecurityFrameworkUtils; +import cn.code.nl.module.base.api.classstandard.ClassStandardApi; import cn.code.nl.module.task.controller.admin.transporttask.vo.TransportTaskOperateReqVO; import cn.code.nl.module.task.controller.admin.transporttask.vo.TransportTaskPageReqVO; import cn.code.nl.module.task.controller.admin.transporttask.vo.TransportTaskSaveReqVO; @@ -11,8 +13,17 @@ import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper; import cn.code.nl.module.task.dto.AcsFeedbackReqDTO; import cn.code.nl.module.task.dto.TaskInfoDTO; import cn.code.nl.module.task.dto.TransportTaskCreateReqDTO; -import cn.code.nl.module.task.enums.*; +import cn.code.nl.module.task.enums.CallbackStatusEnum; +import cn.code.nl.module.task.enums.FinishedTypeEnum; +import cn.code.nl.module.task.enums.TaskOperationTypeEnum; +import cn.code.nl.module.task.enums.TransportTaskStatusEnum; +import cn.code.nl.module.task.manage.TransportTaskIssueManager; +import cn.code.nl.module.task.manage.TransportTaskOperateCheckManager; import cn.code.nl.module.task.manage.TransportTaskOperationManager; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -22,6 +33,7 @@ import org.springframework.validation.annotation.Validated; import java.util.List; import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.module.system.enums.LogRecordConstants.*; import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ALREADY_FINAL; import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_NOT_EXISTS; import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_OPERATION_NOT_SUPPORTED; @@ -42,21 +54,25 @@ public class TransportTaskServiceImpl implements TransportTaskService { @Resource private TransportTaskOperationManager transportTaskOperationManager; + @Resource + private TransportTaskIssueManager transportTaskIssueManager; + + @Resource + private TransportTaskOperateCheckManager transportTaskOperateCheckManager; + + @Resource + private ClassStandardApi classStandardApi; + @Override public Long createTransportTask(TransportTaskSaveReqVO createReqVO) { - // 插入 TransportTaskDO transportTask = BeanUtils.toBean(createReqVO, TransportTaskDO.class); transportTaskMapper.insert(transportTask); - - // 返回 return transportTask.getTaskId(); } @Override public Long createTransportTaskByRpc(TransportTaskCreateReqDTO reqDTO) { - // 1. 构建 DO 并保存 TransportTaskDO task = BeanUtils.toBean(reqDTO, TransportTaskDO.class); - // 参数完整 → 待下发(040),否则 → 生成(010) task.setTaskStatus(reqDTO.getIsCreateFinish() ? TransportTaskStatusEnum.READY.getCode() : TransportTaskStatusEnum.CREATED.getCode()); @@ -70,28 +86,27 @@ public class TransportTaskServiceImpl implements TransportTaskService { @Override public void updateTransportTask(TransportTaskSaveReqVO updateReqVO) { - // 校验存在 validateTransportTaskExists(updateReqVO.getTaskId()); - // 更新 TransportTaskDO updateObj = BeanUtils.toBean(updateReqVO, TransportTaskDO.class); transportTaskMapper.updateById(updateObj); } @Override public void deleteTransportTask(Long id) { - // 校验存在 validateTransportTaskExists(id); - // 删除 transportTaskMapper.deleteById(id); } @Override - public void deleteTransportTaskListByIds(List ids) { - // 删除 + public void deleteTransportTaskListByIds(List ids) { transportTaskMapper.deleteByIds(ids); - } - + } + /** + * 校验搬运任务是否存在 + * + * @param id 任务标识 + */ private void validateTransportTaskExists(Long id) { if (transportTaskMapper.selectById(id) == null) { throw exception(TRANSPORT_TASK_NOT_EXISTS); @@ -105,59 +120,105 @@ public class TransportTaskServiceImpl implements TransportTaskService { @Override public PageResult getTransportTaskPage(TransportTaskPageReqVO pageReqVO) { + if (StrUtil.isNotBlank(pageReqVO.getTaskType())) { + List taskTypeList = classStandardApi.getClassStandardCodeListByCode(pageReqVO.getTaskType()).getCheckedData(); + pageReqVO.setTaskTypeList(CollUtil.isNotEmpty(taskTypeList) ? taskTypeList : List.of(pageReqVO.getTaskType())); + } return transportTaskMapper.selectPage(pageReqVO); } /** - * PC 端操作搬运任务(完成/取消/强制完成):先校验再走统一路由表分发 + * PC 端操作搬运任务,统一走状态操作分发 + * + * @param reqVO 操作请求 */ @Override @Transactional(rollbackFor = Exception.class) + @LogRecord(type = TASK_INFO, + subType = TASK_INFO_OPERATE_TYPE, + bizNo = "{{#reqVO.taskId}}", + success = TASK_INFO_OPERATE_SUCCESS) public void operateTransportTask(TransportTaskOperateReqVO reqVO) { - // 1. 校验任务存在 TransportTaskDO task = transportTaskMapper.selectById(reqVO.getTaskId()); if (task == null) { throw exception(TRANSPORT_TASK_NOT_EXISTS); } - // 2. 校验操作类型允许 PC 端触发 TaskOperationTypeEnum type = TaskOperationTypeEnum.getByCode(reqVO.getOperationType()); if (type == null || !type.isPcAllowed()) { throw exception(TRANSPORT_TASK_OPERATION_NOT_SUPPORTED); } - // 3. 终态校验:已完成/已取消不允许再操作 if (TransportTaskStatusEnum.FINISHED.getCode().equals(task.getTaskStatus()) || TransportTaskStatusEnum.CANCELLED.getCode().equals(task.getTaskStatus())) { throw exception(TRANSPORT_TASK_ALREADY_FINAL); } - // 4. PC 端与 ACS 的差异点:记录完成类型 + if (type == TaskOperationTypeEnum.FINISHED || type == TaskOperationTypeEnum.CANCELLED) { + transportTaskOperateCheckManager.checkEnableOperate(task, type); + } if (type == TaskOperationTypeEnum.FINISHED) { task.setFinishedType(FinishedTypeEnum.MANUAL.getCode()); } else if (type == TaskOperationTypeEnum.FORCE_FINISH) { task.setFinishedType(FinishedTypeEnum.MANUAL_FORCE.getCode()); } - // 5. 构造精简反馈对象,走统一路由表分发 AcsFeedbackReqDTO reqDTO = new AcsFeedbackReqDTO(); reqDTO.setTaskId(task.getTaskId()); reqDTO.setStatus(type.getCode()); transportTaskOperationManager.dispatchOperation(task, type, reqDTO); + LogRecordContext.putVariable("loginUserNickname", SecurityFrameworkUtils.getLoginUserNickname()); + LogRecordContext.putVariable("operateName", type.getName()); } /** - * 根据 taskId 查询任务全量信息:查不到返回 null,由调用方判断 + * 根据任务ID手动下发任务到 ACS,复用自动下发的数组接口逻辑 + * + * @param taskId 任务ID */ + @Override + public void issueTransportTask(Long taskId) { + TransportTaskDO task = transportTaskMapper.selectById(taskId); + if (task == null) { + throw exception(TRANSPORT_TASK_NOT_EXISTS); + } + AcsFeedbackReqDTO reqDTO = new AcsFeedbackReqDTO(); + reqDTO.setTaskId(task.getTaskId()); + reqDTO.setStatus(TaskOperationTypeEnum.ISSUE.getCode()); + transportTaskOperationManager.dispatchOperation(task, TaskOperationTypeEnum.ISSUE, reqDTO); + } + @Override public TaskInfoDTO getTaskInfoById(Long taskId) { TransportTaskDO task = transportTaskMapper.selectById(taskId); return TransportTaskConvert.INSTANCE.convert(task); } - /** - * 根据 taskCode 查询任务全量信息:查不到返回 null,由调用方判断 - */ @Override public TaskInfoDTO getTaskInfoByCode(String taskCode) { TransportTaskDO task = transportTaskMapper.selectByTaskCode(taskCode); return TransportTaskConvert.INSTANCE.convert(task); } + @Override + public List getRunningTaskInfoByMaterialId(Long materialId, String ownerService) { + List tasks = transportTaskMapper.selectRunningListByMaterialId(materialId, ownerService); + return TransportTaskConvert.INSTANCE.convertList(tasks); + } + + @Override + public List getRunningTaskInfoByMaterialCode(String materialCode, String ownerService) { + List tasks = transportTaskMapper.selectRunningListByMaterialCode(materialCode, ownerService); + return TransportTaskConvert.INSTANCE.convertList(tasks); + } + + /** + * 查询待下发任务,并委托下发管理器按生产区域下发到 ACS + */ + @Override + public void autoIssueTransportTasks() { + List tasks = transportTaskMapper.selectAutoIssueReadyList(); + if (CollUtil.isEmpty(tasks)) { + log.info("自动下发任务结束:没有待下发任务"); + return; + } + transportTaskIssueManager.issueTasks(tasks); + } + } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/AcsTaskUtil.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/AcsTaskUtil.java new file mode 100644 index 00000000..418f7956 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/AcsTaskUtil.java @@ -0,0 +1,41 @@ +package cn.code.nl.module.task.utils; + +import cn.code.nl.framework.common.util.json.JsonUtils; +import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO; +import cn.code.nl.module.task.job.dto.AcsTaskDTO; + +import java.util.UUID; + +/** + * ACS 任务工具类 + */ +public class AcsTaskUtil { + + /** + * 构建 ACS 下发任务 + * + * @param task 搬运任务 + * @return ACS 下发任务 + */ + public static AcsTaskDTO buildAcsTaskDTO(TransportTaskDO task) { + AcsTaskDTO dto = new AcsTaskDTO(); + dto.setTraceId(UUID.randomUUID().toString()); + dto.setTimestamp(System.currentTimeMillis()); + dto.setTaskId(task.getTaskId()); + dto.setTaskCode(task.getTaskCode()); + dto.setStartDeviceCode(task.getPointCode1()); + dto.setNextDeviceCode(task.getPointCode2()); + dto.setStartDeviceCode2(task.getPointCode3()); + dto.setNextDeviceCode2(task.getPointCode4()); + dto.setPriority(task.getPriority()); + dto.setVehicleCode(task.getVehicleCode()); + dto.setVehicleCode2(task.getVehicleCode2()); + dto.setTaskType(task.getAcsTaskType()); + dto.setAgvSystemType(task.getAgvSystemType()); + dto.setRemark(task.getRemark()); + dto.setPayload(JsonUtils.parseMap(task.getDispatchParam())); + dto.setProductArea(task.getProductArea()); + return dto; + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/package-info.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/package-info.java new file mode 100644 index 00000000..136b5a0c --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/package-info.java @@ -0,0 +1,6 @@ +/** + * 本模块业务员这中使用工具类 + * @Author: liyongde + * @Date: 2026/7/23 17:02 + */ +package cn.code.nl.module.task.utils; \ No newline at end of file diff --git a/nl-module-task/nl-module-task-server/src/main/resources/application-dev.yaml b/nl-module-task/nl-module-task-server/src/main/resources/application-dev.yaml index f47a45a2..06832135 100644 --- a/nl-module-task/nl-module-task-server/src/main/resources/application-dev.yaml +++ b/nl-module-task/nl-module-task-server/src/main/resources/application-dev.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: @@ -78,9 +78,12 @@ spring: # rocketmq 配置项,对应 RocketMQProperties 配置类 rocketmq: - name-server: 127.0.0.1:9876 # RocketMQ Namesrv + name-server: 192.168.81.193:9876 # RocketMQ Namesrv producer: - group: ${spring.application.name}_TASK_DEV_PRODUCER # 生产者分组 + group: task_producer_dev_group # 生产者分组 + consumer: + task: + topic: task-status-change-dev-topic spring: # RabbitMQ 配置项,对应 RabbitProperties 配置类 diff --git a/nl-module-task/nl-module-task-server/src/main/resources/application-local.yaml b/nl-module-task/nl-module-task-server/src/main/resources/application-local.yaml index f3c6b3c9..bc06865d 100644 --- a/nl-module-task/nl-module-task-server/src/main/resources/application-local.yaml +++ b/nl-module-task/nl-module-task-server/src/main/resources/application-local.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-task/nl-module-task-server/src/main/resources/application-test.yaml b/nl-module-task/nl-module-task-server/src/main/resources/application-test.yaml index dcba8642..225f82de 100644 --- a/nl-module-task/nl-module-task-server/src/main/resources/application-test.yaml +++ b/nl-module-task/nl-module-task-server/src/main/resources/application-test.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-wms/nl-module-wms-api/src/main/java/cn/code/nl/module/wms/enums/ErrorCodeConstants.java b/nl-module-wms/nl-module-wms-api/src/main/java/cn/code/nl/module/wms/enums/ErrorCodeConstants.java index 625654a9..632a1e2c 100644 --- a/nl-module-wms/nl-module-wms-api/src/main/java/cn/code/nl/module/wms/enums/ErrorCodeConstants.java +++ b/nl-module-wms/nl-module-wms-api/src/main/java/cn/code/nl/module/wms/enums/ErrorCodeConstants.java @@ -4,4 +4,35 @@ import cn.code.nl.framework.common.exception.ErrorCode; public interface ErrorCodeConstants { ErrorCode BSREAL_STOR_ATTR_NOT_EXISTS = new ErrorCode(1, "实物库属性不存在"); + + ErrorCode SECT_ATTR_NOT_EXISTS = new ErrorCode(2, "库区属性不存在"); + + ErrorCode STRUC_ATTR_NOT_EXISTS = new ErrorCode(3, "仓位属性不存在"); + + // ================ 出入库表相关错误码 ================= + ErrorCode IOSTOR_INV_NOT_EXISTS = new ErrorCode(4, "出入库单主表不存在"); + + ErrorCode IOSTOR_INV_CODE_GENERATE_FAILED = new ErrorCode(6_000_4, "单据号生成失败"); + + ErrorCode IOSTOR_INV_INVENTORY_INVALID = new ErrorCode(6_000_5, "出库库存已变化,请刷新后重新选择完整箱库存"); + + ErrorCode IOSTORINV_DTL_NOT_EXISTS = new ErrorCode(5, "出入库单明细不存在"); + + ErrorCode IOSTORINV_DIS_NOT_EXISTS = new ErrorCode(6, "出入库单分配不存在"); + + // ================ 仓储策略相关错误码 ================= + ErrorCode WAREHOUSE_STRATEGY_CONFIG_NOT_EXISTS = new ErrorCode(6_000_1, "仓储策略配置不存在"); + + ErrorCode WAREHOUSE_STRATEGY_NOT_EXISTS = new ErrorCode(6_000_2, "出入库策略不存在"); + + ErrorCode ALLEY_AVE_NO_AVAILABLE_LOCATION = new ErrorCode(6_000_3, "均衡策略结果:载具号:{},当前分配策略无可用货位"); + + // ================ 组盘记录相关错误码 ================= + ErrorCode GROUP_PLATE_NOT_EXISTS = new ErrorCode(9, "组盘记录不存在"); + + // ========== 载具信息相关错误码 ========== + ErrorCode STORAGE_VEHICLE_INFO_NOT_EXISTS = new ErrorCode(11, "载具信息不存在"); + + // ========== 载具扩展属性信息 ========== + ErrorCode STORAGE_VEHICLE_EXT_NOT_EXISTS = new ErrorCode(12, "载具扩展属性信息不存在"); } diff --git a/nl-module-wms/nl-module-wms-server/pom.xml b/nl-module-wms/nl-module-wms-server/pom.xml index 7ed07635..26dc0cdf 100644 --- a/nl-module-wms/nl-module-wms-server/pom.xml +++ b/nl-module-wms/nl-module-wms-server/pom.xml @@ -32,6 +32,21 @@ nl-module-wms-api ${revision} + + cn.nl.cloud + nl-module-system-api + ${revision} + + + cn.nl.cloud + nl-module-task-api + ${revision} + + + cn.nl.cloud + nl-module-base-api + ${revision} + @@ -114,6 +129,18 @@ cn.nl.cloud nl-spring-boot-starter-monitor + + + + org.springframework.boot + spring-boot-starter-test + test + + + com.h2database + h2 + test + @@ -136,4 +163,4 @@ - \ No newline at end of file + diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/api/WmsTaskExecuteApiImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/api/WmsTaskExecuteApiImpl.java new file mode 100644 index 00000000..d1710fc2 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/api/WmsTaskExecuteApiImpl.java @@ -0,0 +1,21 @@ +package cn.code.nl.module.wms.api; + +import cn.code.nl.framework.common.enums.RpcConstants; +import cn.code.nl.framework.execute.biz.api.AbstractTaskCommonApiImpl; +import cn.code.nl.framework.execute.biz.api.wms.WmsTaskCommonApi; +import org.springframework.context.annotation.Primary; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * WMS 任务通用 API 实现 + * + * @author liyongde + */ +@RestController +@Validated +@Primary +@RequestMapping(RpcConstants.WMS_PREFIX) +public class WmsTaskExecuteApiImpl extends AbstractTaskCommonApiImpl implements WmsTaskCommonApi { +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/BsrealStorAttrController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/BsrealStorAttrController.java index 13058b05..86ef65d1 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/BsrealStorAttrController.java +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/BsrealStorAttrController.java @@ -101,4 +101,11 @@ public class BsrealStorAttrController { BeanUtils.toBean(list, BsrealStorAttrRespVO.class)); } + @GetMapping("/simple-list") + @Operation(summary = "获得启用的实物库属性精简列表") + public CommonResult> getBsrealStorAttrSimpleList() { + List list = bsrealStorAttrService.getBsrealStorAttrSimpleList(); + return success(BeanUtils.toBean(list, BsrealStorAttrSimpleRespVO.class)); + } + } \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/vo/BsrealStorAttrRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/vo/BsrealStorAttrRespVO.java index f0f086ce..ca361a9e 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/vo/BsrealStorAttrRespVO.java +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/vo/BsrealStorAttrRespVO.java @@ -121,11 +121,11 @@ public class BsrealStorAttrRespVO { @ExcelProperty("拥有者ID") private String sysownerid; - @Schema(description = "部门ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26732") + @Schema(description = "部门ID") @ExcelProperty("部门ID") private String sysdeptid; - @Schema(description = "公司ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21831") + @Schema(description = "公司ID") @ExcelProperty("公司ID") private String syscompanyid; diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/vo/BsrealStorAttrSimpleRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/vo/BsrealStorAttrSimpleRespVO.java new file mode 100644 index 00000000..3126f0b7 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/bsrealstorattr/vo/BsrealStorAttrSimpleRespVO.java @@ -0,0 +1,19 @@ +package cn.code.nl.module.wms.controller.admin.bsrealstorattr.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 实物库属性精简 Response VO") +@Data +public class BsrealStorAttrSimpleRespVO { + + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String storId; + + @Schema(description = "仓库编码", example = "CK001") + private String storCode; + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "一号仓库") + private String storName; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/GroupPlateController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/GroupPlateController.java new file mode 100644 index 00000000..be7beaf2 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/GroupPlateController.java @@ -0,0 +1,107 @@ +package cn.code.nl.module.wms.controller.admin.groupplate; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.groupplate.vo.*; +import cn.code.nl.module.wms.dal.dataobject.groupplate.GroupPlateDO; +import cn.code.nl.module.wms.service.groupplate.GroupPlateService; + +import org.dromara.core.trans.anno.TransMethodResult; + +@Tag(name = "管理后台 - 组盘记录") +@RestController +@RequestMapping("/wms/group-plate") +@Validated +public class GroupPlateController { + + @Resource + private GroupPlateService groupPlateService; + + @PostMapping("/create") + @Operation(summary = "创建组盘记录") + @PreAuthorize("@ss.hasPermission('wms:group-plate:create')") + public CommonResult createGroupPlate(@Valid @RequestBody GroupPlateSaveReqVO createReqVO) { + return success(groupPlateService.createGroupPlate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新组盘记录") + @PreAuthorize("@ss.hasPermission('wms:group-plate:update')") + public CommonResult updateGroupPlate(@Valid @RequestBody GroupPlateSaveReqVO updateReqVO) { + groupPlateService.updateGroupPlate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除组盘记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:group-plate:delete')") + public CommonResult deleteGroupPlate(@RequestParam("id") String id) { + groupPlateService.deleteGroupPlate(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除组盘记录") + @PreAuthorize("@ss.hasPermission('wms:group-plate:delete')") + public CommonResult deleteGroupPlateList(@RequestParam("ids") List ids) { + groupPlateService.deleteGroupPlateListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得组盘记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:group-plate:query')") + public CommonResult getGroupPlate(@RequestParam("id") String id) { + GroupPlateDO groupPlate = groupPlateService.getGroupPlate(id); + return success(BeanUtils.toBean(groupPlate, GroupPlateRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得组盘记录分页") + @TransMethodResult + @PreAuthorize("@ss.hasPermission('wms:group-plate:query')") + public CommonResult> getGroupPlatePage(@Valid GroupPlatePageReqVO pageReqVO) { + PageResult pageResult = groupPlateService.getGroupPlatePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, GroupPlateRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出组盘记录 Excel") + @PreAuthorize("@ss.hasPermission('wms:group-plate:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportGroupPlateExcel(@Valid GroupPlatePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = groupPlateService.getGroupPlatePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "组盘记录.xls", "数据", GroupPlateRespVO.class, + BeanUtils.toBean(list, GroupPlateRespVO.class)); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlatePageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlatePageReqVO.java new file mode 100644 index 00000000..bbc68857 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlatePageReqVO.java @@ -0,0 +1,63 @@ +package cn.code.nl.module.wms.controller.admin.groupplate.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 组盘记录分页 Request VO") +@Data +public class GroupPlatePageReqVO extends PageParam { + + @Schema(description = "载具编码") + private String vehicleCode; + + @Schema(description = "状态", example = "1") + private String status; + + @Schema(description = "物料id", example = "1670") + private String materialId; + + @Schema(description = "批次") + private String pcsn; + + @Schema(description = "组盘数量") + private BigDecimal qty; + + @Schema(description = "冻结数量") + private BigDecimal frozenQty; + + @Schema(description = "计量单位标识", example = "21005") + private String qtyUnitId; + + @Schema(description = "计量单位名称", example = "王五") + private String qtyUnitName; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "来源单据号") + private String extCode; + + @Schema(description = "来源单据类型", example = "1") + private String extType; + + @Schema(description = "来源单据明细号") + private String extDtlCode; + + @Schema(description = "md5") + private String md5; + + @Schema(description = "物料编码") + private String materialCode; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlateRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlateRespVO.java new file mode 100644 index 00000000..84fc10fe --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlateRespVO.java @@ -0,0 +1,105 @@ +package cn.code.nl.module.wms.controller.admin.groupplate.vo; + +import cn.code.nl.module.system.api.user.AdminUserApi; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; + +import org.dromara.core.trans.anno.Trans; +import org.dromara.core.trans.constant.TransType; +import org.dromara.core.trans.vo.VO; + +@Schema(description = "管理后台 - 组盘记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class GroupPlateRespVO implements VO { + + @TableId + private Long groupId; + + @Schema(description = "载具编码") + @ExcelProperty("载具编码") + private String vehicleCode; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("状态") + private String status; + + @Schema(description = "物料id", example = "1670") + @ExcelProperty("物料id") + private String materialId; + + @Schema(description = "批次", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("批次") + private String pcsn; + + @Schema(description = "组盘数量", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("组盘数量") + private BigDecimal qty; + + @Schema(description = "冻结数量") + @ExcelProperty("冻结数量") + private BigDecimal frozenQty; + + @Schema(description = "计量单位标识", example = "21005") + @ExcelProperty("计量单位标识") + private String qtyUnitId; + + @Schema(description = "计量单位名称", example = "王五") + @ExcelProperty("计量单位名称") + private String qtyUnitName; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "来源单据号") + @ExcelProperty("来源单据号") + private String extCode; + + @Schema(description = "来源单据类型", example = "1") + @ExcelProperty("来源单据类型") + private String extType; + + @Schema(description = "来源单据明细号") + @ExcelProperty("来源单据明细号") + private String extDtlCode; + + @Schema(description = "md5") + @ExcelProperty("md5") + private String md5; + + @Schema(description = "物料编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("物料编码") + private String materialCode; + + @Schema(description = "创建者") + @ExcelProperty("创建者") + @Trans(type = TransType.AUTO_TRANS, key = AdminUserApi.PREFIX, fields = "nickname", ref = "creatorName") + private String creator; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "创建者名称") + private String creatorName; + + @Schema(description = "更新者") + @ExcelProperty("更新者") + @Trans(type = TransType.AUTO_TRANS, key = AdminUserApi.PREFIX, fields = "nickname", ref = "updaterName") + private String updater; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + + @Schema(description = "更新者名称") + private String updaterName; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlateSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlateSaveReqVO.java new file mode 100644 index 00000000..cc9512a3 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/groupplate/vo/GroupPlateSaveReqVO.java @@ -0,0 +1,61 @@ +package cn.code.nl.module.wms.controller.admin.groupplate.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 组盘记录新增/修改 Request VO") +@Data +public class GroupPlateSaveReqVO { + + private String groupId; + + @Schema(description = "载具编码") + private String vehicleCode; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "状态不能为空") + private String status; + + @Schema(description = "物料id", example = "1670") + private String materialId; + + @Schema(description = "批次", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "批次不能为空") + private String pcsn; + + @Schema(description = "组盘数量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "组盘数量不能为空") + private BigDecimal qty; + + @Schema(description = "冻结数量") + private BigDecimal frozenQty; + + @Schema(description = "计量单位标识", example = "21005") + private String qtyUnitId; + + @Schema(description = "计量单位名称", example = "王五") + private String qtyUnitName; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "来源单据号") + private String extCode; + + @Schema(description = "来源单据类型", example = "1") + private String extType; + + @Schema(description = "来源单据明细号") + private String extDtlCode; + + @Schema(description = "md5") + private String md5; + + @Schema(description = "物料编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "物料编码不能为空") + private String materialCode; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/IostorInvController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/IostorInvController.java new file mode 100644 index 00000000..635fdf5f --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/IostorInvController.java @@ -0,0 +1,127 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinv.IostorInvDO; +import cn.code.nl.module.wms.service.iostorinv.IostorInvService; + +@Tag(name = "管理后台 - 出入库单主表") +@RestController +@RequestMapping("/wms/iostor-inv") +@Validated +public class IostorInvController { + + @Resource + private IostorInvService iostorInvService; + + @PostMapping("/createOutbound") + @Operation(summary = "创建出库单及明细") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:create')") + public CommonResult createOutbound(@Valid @RequestBody IostorInvCreateReqVO reqVO) { + return success(iostorInvService.createOutbound(reqVO)); + } + + @GetMapping("/availableInventoryPage") + @Operation(summary = "获得可用库存分页") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:query')") + public CommonResult> getAvailableInventoryPage( + @Valid AvailableInventoryPageReqVO reqVO) { + return success(iostorInvService.getAvailableInventoryPage(reqVO)); + } + + @PostMapping("/expandAvailableInventory") + @Operation(summary = "按箱号展开全部可用子卷") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:query')") + public CommonResult> expandAvailableInventory( + @Valid @RequestBody ExpandAvailableInventoryReqVO reqVO) { + return success(iostorInvService.expandAvailableInventory(reqVO)); + } + + @PostMapping("/create") + @Operation(summary = "创建出入库单主表") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:create')") + public CommonResult createIostorInv(@Valid @RequestBody IostorInvSaveReqVO createReqVO) { + return success(iostorInvService.createIostorInv(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新出入库单主表") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:update')") + public CommonResult updateIostorInv(@Valid @RequestBody IostorInvSaveReqVO updateReqVO) { + iostorInvService.updateIostorInv(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除出入库单主表") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:delete')") + public CommonResult deleteIostorInv(@RequestParam("id") String id) { + iostorInvService.deleteIostorInv(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除出入库单主表") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:delete')") + public CommonResult deleteIostorInvList(@RequestParam("ids") List ids) { + iostorInvService.deleteIostorInvListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得出入库单主表") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:query')") + public CommonResult getIostorInv(@RequestParam("id") String id) { + IostorInvDO iostorInv = iostorInvService.getIostorInv(id); + return success(BeanUtils.toBean(iostorInv, IostorInvRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得出入库单主表分页") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:query')") + public CommonResult> getIostorInvPage(@Valid IostorInvPageReqVO pageReqVO) { + PageResult pageResult = iostorInvService.getIostorInvPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IostorInvRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出出入库单主表 Excel") + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportIostorInvExcel(@Valid IostorInvPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = iostorInvService.getIostorInvPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "出入库单主表.xls", "数据", IostorInvRespVO.class, + BeanUtils.toBean(list, IostorInvRespVO.class)); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/AvailableInventoryPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/AvailableInventoryPageReqVO.java new file mode 100644 index 00000000..afc4f5fe --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/AvailableInventoryPageReqVO.java @@ -0,0 +1,27 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import cn.code.nl.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 可用库存分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class AvailableInventoryPageReqVO extends PageParam { + + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "仓库标识不能为空") + private String storId; + + @Schema(description = "物料编码") + private String materialCode; + + @Schema(description = "箱号") + private String vehicleCode; + + @Schema(description = "批次") + private String pcsn; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/AvailableInventoryRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/AvailableInventoryRespVO.java new file mode 100644 index 00000000..9046b1cb --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/AvailableInventoryRespVO.java @@ -0,0 +1,43 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 可用库存 Response VO") +@Data +public class AvailableInventoryRespVO { + + @Schema(description = "组盘记录标识") + private Long groupId; + @Schema(description = "箱号") + private String vehicleCode; + @Schema(description = "批次") + private String pcsn; + @Schema(description = "物料标识") + private String materialId; + @Schema(description = "物料编码") + private String materialCode; + @Schema(description = "物料名称") + private String materialName; + @Schema(description = "可用数量") + private BigDecimal availableQty; + @Schema(description = "计量单位标识") + private String qtyUnitId; + @Schema(description = "计量单位名称") + private String qtyUnitName; + @Schema(description = "来源单据号") + private String extCode; + @Schema(description = "来源单据类型") + private String extType; + @Schema(description = "来源单据明细号") + private String extDtlCode; + @Schema(description = "仓库标识") + private String storId; + @Schema(description = "仓库编码") + private String storCode; + @Schema(description = "仓库名称") + private String storName; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/ExpandAvailableInventoryReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/ExpandAvailableInventoryReqVO.java new file mode 100644 index 00000000..f35adf56 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/ExpandAvailableInventoryReqVO.java @@ -0,0 +1,24 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 按箱号展开可用库存 Request VO") +@Data +public class ExpandAvailableInventoryReqVO { + + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "仓库标识不能为空") + private String storId; + + @Schema(description = "箱号列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "箱号列表不能为空") + @Size(max = 500, message = "箱号数量不能超过 500 个") + private List<@NotBlank(message = "箱号不能为空") String> vehicleCodes; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvCreateReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvCreateReqVO.java new file mode 100644 index 00000000..2b5faf60 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvCreateReqVO.java @@ -0,0 +1,81 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 出库单新增 Request VO") +@Data +public class IostorInvCreateReqVO { + + @Schema(description = "单据类型", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "单据类型不能为空") + private String billType; + + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "仓库标识不能为空") + private String storId; + + @Schema(description = "业务日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "业务日期不能为空") + private LocalDateTime bizDate; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "出库单明细", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "出库单明细不能为空") + @Valid + private List details; + + @Schema(description = "出库单明细") + @Data + public static class Detail { + + @Schema(description = "组盘记录标识(仅库存选取方式提交)") + private Long groupId; + + @Schema(description = "箱号(仅库存选取方式提交)") + private String vehicleCode; + + @Schema(description = "物料编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "物料编码不能为空") + private String materialCode; + + @Schema(description = "物料标识") + private String materialId; + + @Schema(description = "批次序列号") + private String pcsn; + + @Schema(description = "出库重量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出库重量不能为空") + @DecimalMin(value = "0.001", message = "出库重量必须大于0") + private BigDecimal planQty; + + @Schema(description = "数量单位标识") + private String qtyUnitId; + + @Schema(description = "数量单位名称") + private String qtyUnitName; + + @Schema(description = "来源单据编号") + private String sourceBillCode; + + @Schema(description = "来源单据类型") + private String sourceBillType; + + @Schema(description = "来源单据明细标识") + private String sourceBilldtlId; + + @Schema(description = "备注") + private String remark; + } +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvPageReqVO.java new file mode 100644 index 00000000..ea47a533 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvPageReqVO.java @@ -0,0 +1,89 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 出入库单主表分页 Request VO") +@Data +public class IostorInvPageReqVO extends PageParam { + + @Schema(description = "单据编号") + private String billCode; + + @Schema(description = "单据类型", example = "2") + private String billType; + + @Schema(description = "业务日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDateTime[] bizDate; + + @Schema(description = "仓库标识", example = "12635") + private String storId; + + @Schema(description = "来源方名称", example = "李四") + private String sourceName; + + @Schema(description = "来源方类型", example = "2") + private String sourceType; + + @Schema(description = "总数量") + private BigDecimal totalQty; + + @Schema(description = "总重量") + private BigDecimal totalWeight; + + @Schema(description = "明细数", example = "5494") + private Integer detailCount; + + @Schema(description = "单据状态", example = "1") + private String billStatus; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "生成方式") + private String createMode; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "分配人", example = "27530") + private String disOptid; + + @Schema(description = "分配时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] disTime; + + @Schema(description = "确认人", example = "30295") + private String confirmOptid; + + @Schema(description = "确认时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] confirmTime; + + @Schema(description = "部门ID", example = "8530") + private String sysdeptid; + + @Schema(description = "公司ID", example = "11731") + private String syscompanyid; + + @Schema(description = "是否已上传") + private Boolean isUpload; + + @Schema(description = "回传人", example = "25284") + private String uploadOptid; + + @Schema(description = "回传时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private String[] uploadTime; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvRespVO.java new file mode 100644 index 00000000..737c5d38 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvRespVO.java @@ -0,0 +1,116 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Schema(description = "管理后台 - 出入库单主表 Response VO") +@Data +@ExcelIgnoreUnannotated +public class IostorInvRespVO { + + @Schema(description = "单据编号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("单据编号") + private String billCode; + + @Schema(description = "单据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("单据类型") + private String billType; + + @Schema(description = "业务日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("业务日期") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDateTime bizDate; + + @Schema(description = "仓库标识", example = "12635") + @ExcelProperty("仓库标识") + private String storId; + + @Schema(description = "仓库", example = "1号仓") + @ExcelProperty("仓库") + private String storName; + + @Schema(description = "来源方标识", example = "21190") + @ExcelProperty("来源方标识") + private String sourceId; + + @Schema(description = "来源方名称", example = "李四") + @ExcelProperty("来源方名称") + private String sourceName; + + @Schema(description = "来源方类型", example = "2") + @ExcelProperty("来源方类型") + private String sourceType; + + @Schema(description = "总数量", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("总数量") + private BigDecimal totalQty; + + @Schema(description = "总重量") + @ExcelProperty("总重量") + private BigDecimal totalWeight; + + @Schema(description = "明细数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5494") + @ExcelProperty("明细数") + private Integer detailCount; + + @Schema(description = "单据状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("单据状态") + private String billStatus; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "生成方式", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("生成方式") + private String createMode; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "分配人", example = "27530") + @ExcelProperty("分配人") + private String disOptid; + + @Schema(description = "分配时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("分配时间") + private LocalDateTime disTime; + + @Schema(description = "确认人", example = "30295") + @ExcelProperty("确认人") + private String confirmOptid; + + @Schema(description = "确认时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("确认时间") + private LocalDateTime confirmTime; + + @Schema(description = "部门ID", example = "8530") + @ExcelProperty("部门ID") + private String sysdeptid; + + @Schema(description = "公司ID", example = "11731") + @ExcelProperty("公司ID") + private String syscompanyid; + + @Schema(description = "是否已上传", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("是否已上传") + private String isUpload; + + @Schema(description = "回传人", example = "25284") + @ExcelProperty("回传人") + private String uploadOptid; + + @Schema(description = "回传时间") + @ExcelProperty("回传时间") + private String uploadTime; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvSaveReqVO.java new file mode 100644 index 00000000..521c2676 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvSaveReqVO.java @@ -0,0 +1,104 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 出入库单主表新增/修改 Request VO") +@Data +public class IostorInvSaveReqVO { + + @Schema(description = "出入单标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1273") + private String iostorinvId; + + @Schema(description = "单据编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "单据编号不能为空") + private String billCode; + + @Schema(description = "出入类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "出入类型不能为空") + private String ioType; + + @Schema(description = "单据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotEmpty(message = "单据类型不能为空") + private String billType; + + @Schema(description = "业务日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "业务日期不能为空") + private LocalDateTime bizDate; + + @Schema(description = "仓库标识", example = "12635") + private String storId; + + @Schema(description = "仓库编码") + private String storCode; + + @Schema(description = "仓库名称", example = "赵六") + private String storName; + + @Schema(description = "来源方标识", example = "21190") + private String sourceId; + + @Schema(description = "来源方名称", example = "李四") + private String sourceName; + + @Schema(description = "来源方类型", example = "2") + private String sourceType; + + @Schema(description = "总数量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "总数量不能为空") + private BigDecimal totalQty; + + @Schema(description = "总重量") + private BigDecimal totalWeight; + + @Schema(description = "明细数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5494") + @NotNull(message = "明细数不能为空") + private Integer detailCount; + + @Schema(description = "单据状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "单据状态不能为空") + private String billStatus; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "生成方式", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "生成方式不能为空") + private String createMode; + + @Schema(description = "分配人", example = "27530") + private String disOptid; + + @Schema(description = "分配时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "分配时间不能为空") + private LocalDateTime disTime; + + @Schema(description = "确认人", example = "30295") + private String confirmOptid; + + @Schema(description = "确认时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "确认时间不能为空") + private LocalDateTime confirmTime; + + @Schema(description = "部门ID", example = "8530") + private String sysdeptid; + + @Schema(description = "公司ID", example = "11731") + private String syscompanyid; + + @Schema(description = "是否已上传", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "是否已上传不能为空") + private String isUpload; + + @Schema(description = "回传人", example = "25284") + private String uploadOptid; + + @Schema(description = "回传时间") + private String uploadTime; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/IostorinvDisController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/IostorinvDisController.java new file mode 100644 index 00000000..8fef08bd --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/IostorinvDisController.java @@ -0,0 +1,104 @@ +package cn.code.nl.module.wms.controller.admin.iostorinvdis; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.iostorinvdis.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdis.IostorinvDisDO; +import cn.code.nl.module.wms.service.iostorinvdis.IostorinvDisService; + +@Tag(name = "管理后台 - 出入库单分配") +@RestController +@RequestMapping("/wms/iostorinv-dis") +@Validated +public class IostorinvDisController { + + @Resource + private IostorinvDisService iostorinvDisService; + + @PostMapping("/create") + @Operation(summary = "创建出入库单分配") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dis:create')") + public CommonResult createIostorinvDis(@Valid @RequestBody IostorinvDisSaveReqVO createReqVO) { + return success(iostorinvDisService.createIostorinvDis(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新出入库单分配") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dis:update')") + public CommonResult updateIostorinvDis(@Valid @RequestBody IostorinvDisSaveReqVO updateReqVO) { + iostorinvDisService.updateIostorinvDis(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除出入库单分配") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dis:delete')") + public CommonResult deleteIostorinvDis(@RequestParam("id") String id) { + iostorinvDisService.deleteIostorinvDis(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除出入库单分配") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dis:delete')") + public CommonResult deleteIostorinvDisList(@RequestParam("ids") List ids) { + iostorinvDisService.deleteIostorinvDisListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得出入库单分配") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dis:query')") + public CommonResult getIostorinvDis(@RequestParam("id") String id) { + IostorinvDisDO iostorinvDis = iostorinvDisService.getIostorinvDis(id); + return success(BeanUtils.toBean(iostorinvDis, IostorinvDisRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得出入库单分配分页") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dis:query')") + public CommonResult> getIostorinvDisPage(@Valid IostorinvDisPageReqVO pageReqVO) { + PageResult pageResult = iostorinvDisService.getIostorinvDisPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IostorinvDisRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出出入库单分配 Excel") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dis:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportIostorinvDisExcel(@Valid IostorinvDisPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = iostorinvDisService.getIostorinvDisPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "出入库单分配.xls", "数据", IostorinvDisRespVO.class, + BeanUtils.toBean(list, IostorinvDisRespVO.class)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisPageReqVO.java new file mode 100644 index 00000000..a8f1fac0 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisPageReqVO.java @@ -0,0 +1,79 @@ +package cn.code.nl.module.wms.controller.admin.iostorinvdis.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 出入库单分配分页 Request VO") +@Data +public class IostorinvDisPageReqVO extends PageParam { + + @Schema(description = "出入单标识", example = "2717") + private String iostorinvId; + + @Schema(description = "出入单明细标识", example = "22004") + private String iostorinvdtlId; + + @Schema(description = "明细序号") + private String seqNo; + + @Schema(description = "库区标识", example = "529") + private String sectId; + + @Schema(description = "库区编码") + private String sectCode; + + @Schema(description = "库区名称", example = "赵六") + private String sectName; + + @Schema(description = "仓位标识", example = "9779") + private String structId; + + @Schema(description = "仓位编码") + private String structCode; + + @Schema(description = "仓位名称", example = "李四") + private String structName; + + @Schema(description = "物料标识", example = "28220") + private String materialId; + + @Schema(description = "物料编码") + private String materialCode; + + @Schema(description = "批次") + private String pcsn; + + @Schema(description = "执行状态", example = "1") + private String workStatus; + + @Schema(description = "任务标识", example = "29117") + private String taskId; + + @Schema(description = "存储载具编码") + private String storagevehicleCode; + + @Schema(description = "是否已下发") + private String isIssued; + + @Schema(description = "数量计量单位标识", example = "26595") + private String qtyUnitId; + + @Schema(description = "数量计量单位名称", example = "张三") + private String qtyUnitName; + + @Schema(description = "计划数量") + private BigDecimal planQty; + + @Schema(description = "实际数量") + private BigDecimal realQty; + + @Schema(description = "出入点位标识") + private String pointCode; + + @Schema(description = "出库类型:0自动搬运1手动搬运", example = "2") + private Boolean handType; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisRespVO.java new file mode 100644 index 00000000..9882c825 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisRespVO.java @@ -0,0 +1,106 @@ +package cn.code.nl.module.wms.controller.admin.iostorinvdis.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 出入库单分配 Response VO") +@Data +@ExcelIgnoreUnannotated +public class IostorinvDisRespVO { + + @Schema(description = "出入单分配标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "14409") + @ExcelProperty("出入单分配标识") + private String iostorinvdisId; + + @Schema(description = "出入单标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "2717") + @ExcelProperty("出入单标识") + private String iostorinvId; + + @Schema(description = "出入单明细标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "22004") + @ExcelProperty("出入单明细标识") + private String iostorinvdtlId; + + @Schema(description = "明细序号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("明细序号") + private String seqNo; + + @Schema(description = "库区标识", example = "529") + @ExcelProperty("库区标识") + private String sectId; + + @Schema(description = "库区编码") + @ExcelProperty("库区编码") + private String sectCode; + + @Schema(description = "库区名称", example = "赵六") + @ExcelProperty("库区名称") + private String sectName; + + @Schema(description = "仓位标识", example = "9779") + @ExcelProperty("仓位标识") + private String structId; + + @Schema(description = "仓位编码") + @ExcelProperty("仓位编码") + private String structCode; + + @Schema(description = "仓位名称", example = "李四") + @ExcelProperty("仓位名称") + private String structName; + + @Schema(description = "物料标识", example = "28220") + @ExcelProperty("物料标识") + private String materialId; + + @Schema(description = "物料编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("物料编码") + private String materialCode; + + @Schema(description = "批次", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("批次") + private String pcsn; + + @Schema(description = "执行状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("执行状态") + private String workStatus; + + @Schema(description = "任务标识", example = "29117") + @ExcelProperty("任务标识") + private String taskId; + + @Schema(description = "存储载具编码") + @ExcelProperty("存储载具编码") + private String storagevehicleCode; + + @Schema(description = "是否已下发", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("是否已下发") + private String isIssued; + + @Schema(description = "数量计量单位标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "26595") + @ExcelProperty("数量计量单位标识") + private String qtyUnitId; + + @Schema(description = "数量计量单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @ExcelProperty("数量计量单位名称") + private String qtyUnitName; + + @Schema(description = "计划数量", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("计划数量") + private BigDecimal planQty; + + @Schema(description = "实际数量") + @ExcelProperty("实际数量") + private BigDecimal realQty; + + @Schema(description = "出入点位标识") + @ExcelProperty("出入点位标识") + private String pointCode; + + @Schema(description = "出库类型:0自动搬运1手动搬运", example = "2") + @ExcelProperty("出库类型:0自动搬运1手动搬运") + private Boolean handType; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisSaveReqVO.java new file mode 100644 index 00000000..337eb6e9 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdis/vo/IostorinvDisSaveReqVO.java @@ -0,0 +1,92 @@ +package cn.code.nl.module.wms.controller.admin.iostorinvdis.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 出入库单分配新增/修改 Request VO") +@Data +public class IostorinvDisSaveReqVO { + + @Schema(description = "出入单分配标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "14409") + private String iostorinvdisId; + + @Schema(description = "出入单标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "2717") + @NotEmpty(message = "出入单标识不能为空") + private String iostorinvId; + + @Schema(description = "出入单明细标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "22004") + @NotEmpty(message = "出入单明细标识不能为空") + private String iostorinvdtlId; + + @Schema(description = "明细序号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "明细序号不能为空") + private String seqNo; + + @Schema(description = "库区标识", example = "529") + private String sectId; + + @Schema(description = "库区编码") + private String sectCode; + + @Schema(description = "库区名称", example = "赵六") + private String sectName; + + @Schema(description = "仓位标识", example = "9779") + private String structId; + + @Schema(description = "仓位编码") + private String structCode; + + @Schema(description = "仓位名称", example = "李四") + private String structName; + + @Schema(description = "物料标识", example = "28220") + private String materialId; + + @Schema(description = "物料编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "物料编码不能为空") + private String materialCode; + + @Schema(description = "批次", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "批次不能为空") + private String pcsn; + + @Schema(description = "执行状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "执行状态不能为空") + private String workStatus; + + @Schema(description = "任务标识", example = "29117") + private String taskId; + + @Schema(description = "存储载具编码") + private String storagevehicleCode; + + @Schema(description = "是否已下发", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "是否已下发不能为空") + private String isIssued; + + @Schema(description = "数量计量单位标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "26595") + @NotEmpty(message = "数量计量单位标识不能为空") + private String qtyUnitId; + + @Schema(description = "数量计量单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @NotEmpty(message = "数量计量单位名称不能为空") + private String qtyUnitName; + + @Schema(description = "计划数量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "计划数量不能为空") + private BigDecimal planQty; + + @Schema(description = "实际数量") + private BigDecimal realQty; + + @Schema(description = "出入点位标识") + private String pointCode; + + @Schema(description = "出库类型:0自动搬运1手动搬运", example = "2") + private Boolean handType; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/IostorinvDtlController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/IostorinvDtlController.java new file mode 100644 index 00000000..dd2f69e2 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/IostorinvDtlController.java @@ -0,0 +1,104 @@ +package cn.code.nl.module.wms.controller.admin.iostorinvdtl; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdtl.IostorinvDtlDO; +import cn.code.nl.module.wms.service.iostorinvdtl.IostorinvDtlService; + +@Tag(name = "管理后台 - 出入库单明细") +@RestController +@RequestMapping("/wms/iostorinv-dtl") +@Validated +public class IostorinvDtlController { + + @Resource + private IostorinvDtlService iostorinvDtlService; + + @PostMapping("/create") + @Operation(summary = "创建出入库单明细") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dtl:create')") + public CommonResult createIostorinvDtl(@Valid @RequestBody IostorinvDtlSaveReqVO createReqVO) { + return success(iostorinvDtlService.createIostorinvDtl(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新出入库单明细") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dtl:update')") + public CommonResult updateIostorinvDtl(@Valid @RequestBody IostorinvDtlSaveReqVO updateReqVO) { + iostorinvDtlService.updateIostorinvDtl(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除出入库单明细") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dtl:delete')") + public CommonResult deleteIostorinvDtl(@RequestParam("id") String id) { + iostorinvDtlService.deleteIostorinvDtl(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除出入库单明细") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dtl:delete')") + public CommonResult deleteIostorinvDtlList(@RequestParam("ids") List ids) { + iostorinvDtlService.deleteIostorinvDtlListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得出入库单明细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dtl:query')") + public CommonResult getIostorinvDtl(@RequestParam("id") String id) { + IostorinvDtlDO iostorinvDtl = iostorinvDtlService.getIostorinvDtl(id); + return success(BeanUtils.toBean(iostorinvDtl, IostorinvDtlRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得出入库单明细分页") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dtl:query')") + public CommonResult> getIostorinvDtlPage(@Valid IostorinvDtlPageReqVO pageReqVO) { + PageResult pageResult = iostorinvDtlService.getIostorinvDtlPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IostorinvDtlRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出出入库单明细 Excel") + @PreAuthorize("@ss.hasPermission('wms:iostorinv-dtl:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportIostorinvDtlExcel(@Valid IostorinvDtlPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = iostorinvDtlService.getIostorinvDtlPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "出入库单明细.xls", "数据", IostorinvDtlRespVO.class, + BeanUtils.toBean(list, IostorinvDtlRespVO.class)); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlPageReqVO.java new file mode 100644 index 00000000..eba93573 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlPageReqVO.java @@ -0,0 +1,70 @@ +package cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 出入库单明细分页 Request VO") +@Data +public class IostorinvDtlPageReqVO extends PageParam { + + @Schema(description = "出入单标识", example = "29865") + private String iostorinvId; + + @Schema(description = "明细序号") + private Integer seqNo; + + @Schema(description = "批次") + private String pcsn; + + @Schema(description = "单据明细状态", example = "1") + private String billStatus; + + @Schema(description = "数量计量单位标识", example = "3271") + private String qtyUnitId; + + @Schema(description = "数量计量单位名称", example = "李四") + private String qtyUnitName; + + @Schema(description = "计划数量") + private BigDecimal planQty; + + @Schema(description = "实际数量") + private BigDecimal realQty; + + @Schema(description = "来源单据明细标识", example = "32560") + private String sourceBilldtlId; + + @Schema(description = "来源单据类型", example = "1") + private String sourceBillType; + + @Schema(description = "来源单编号") + private String sourceBillCode; + + @Schema(description = "来源单表名") + private String sourceBillTable; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "已分配数量") + private BigDecimal assignQty; + + @Schema(description = "未分配数量") + private BigDecimal unassignQty; + + @Schema(description = "物料编号") + private String materialCode; + + @Schema(description = "来源单指定上料口") + private String sourceLoadPort; + + @Schema(description = "单据回传策略配置类名") + private String callbackStrategy; + + @Schema(description = "物料标识", example = "2525") + private String materialId; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlRespVO.java new file mode 100644 index 00000000..aaf02c72 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlRespVO.java @@ -0,0 +1,94 @@ +package cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 出入库单明细 Response VO") +@Data +@ExcelIgnoreUnannotated +public class IostorinvDtlRespVO { + + @Schema(description = "出入单明细标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "3443") + @ExcelProperty("出入单明细标识") + private String iostorinvdtlId; + + @Schema(description = "出入单标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "29865") + @ExcelProperty("出入单标识") + private String iostorinvId; + + @Schema(description = "明细序号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("明细序号") + private Integer seqNo; + + @Schema(description = "批次") + @ExcelProperty("批次") + private String pcsn; + + @Schema(description = "单据明细状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("单据明细状态") + private String billStatus; + + @Schema(description = "数量计量单位标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "3271") + @ExcelProperty("数量计量单位标识") + private String qtyUnitId; + + @Schema(description = "数量计量单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("数量计量单位名称") + private String qtyUnitName; + + @Schema(description = "计划数量", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("计划数量") + private BigDecimal planQty; + + @Schema(description = "实际数量") + @ExcelProperty("实际数量") + private BigDecimal realQty; + + @Schema(description = "来源单据明细标识", example = "32560") + @ExcelProperty("来源单据明细标识") + private String sourceBilldtlId; + + @Schema(description = "来源单据类型", example = "1") + @ExcelProperty("来源单据类型") + private String sourceBillType; + + @Schema(description = "来源单编号") + @ExcelProperty("来源单编号") + private String sourceBillCode; + + @Schema(description = "来源单表名") + @ExcelProperty("来源单表名") + private String sourceBillTable; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "已分配数量") + @ExcelProperty("已分配数量") + private BigDecimal assignQty; + + @Schema(description = "未分配数量") + @ExcelProperty("未分配数量") + private BigDecimal unassignQty; + + @Schema(description = "物料编号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("物料编号") + private String materialCode; + + @Schema(description = "来源单指定上料口") + @ExcelProperty("来源单指定上料口") + private String sourceLoadPort; + + @Schema(description = "单据回传策略配置类名") + @ExcelProperty("单据回传策略配置类名") + private String callbackStrategy; + + @Schema(description = "物料标识", example = "2525") + @ExcelProperty("物料标识") + private String materialId; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlSaveReqVO.java new file mode 100644 index 00000000..73a7dc8e --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinvdtl/vo/IostorinvDtlSaveReqVO.java @@ -0,0 +1,80 @@ +package cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 出入库单明细新增/修改 Request VO") +@Data +public class IostorinvDtlSaveReqVO { + + @Schema(description = "出入单明细标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "3443") + private String iostorinvdtlId; + + @Schema(description = "出入单标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "29865") + @NotEmpty(message = "出入单标识不能为空") + private String iostorinvId; + + @Schema(description = "明细序号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "明细序号不能为空") + private Integer seqNo; + + @Schema(description = "批次") + private String pcsn; + + @Schema(description = "单据明细状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "单据明细状态不能为空") + private String billStatus; + + @Schema(description = "数量计量单位标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "3271") + @NotEmpty(message = "数量计量单位标识不能为空") + private String qtyUnitId; + + @Schema(description = "数量计量单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "数量计量单位名称不能为空") + private String qtyUnitName; + + @Schema(description = "计划数量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "计划数量不能为空") + private BigDecimal planQty; + + @Schema(description = "实际数量") + private BigDecimal realQty; + + @Schema(description = "来源单据明细标识", example = "32560") + private String sourceBilldtlId; + + @Schema(description = "来源单据类型", example = "1") + private String sourceBillType; + + @Schema(description = "来源单编号") + private String sourceBillCode; + + @Schema(description = "来源单表名") + private String sourceBillTable; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "已分配数量") + private BigDecimal assignQty; + + @Schema(description = "未分配数量") + private BigDecimal unassignQty; + + @Schema(description = "物料编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "物料编号不能为空") + private String materialCode; + + @Schema(description = "来源单指定上料口") + private String sourceLoadPort; + + @Schema(description = "单据回传策略配置类名") + private String callbackStrategy; + + @Schema(description = "物料标识", example = "2525") + private String materialId; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/SectAttrController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/SectAttrController.java new file mode 100644 index 00000000..90cc954b --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/SectAttrController.java @@ -0,0 +1,113 @@ +package cn.code.nl.module.wms.controller.admin.sectattr; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.sectattr.vo.*; +import cn.code.nl.module.wms.dal.dataobject.sectattr.SectAttrDO; +import cn.code.nl.module.wms.service.sectattr.SectAttrService; + +@Tag(name = "管理后台 - 库区属性") +@RestController +@RequestMapping("/wms/sect-attr") +@Validated +public class SectAttrController { + + @Resource + private SectAttrService sectAttrService; + + @PostMapping("/create") + @Operation(summary = "创建库区属性") + @PreAuthorize("@ss.hasPermission('wms:sect-attr:create')") + public CommonResult createSectAttr(@Valid @RequestBody SectAttrSaveReqVO createReqVO) { + return success(sectAttrService.createSectAttr(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新库区属性") + @PreAuthorize("@ss.hasPermission('wms:sect-attr:update')") + public CommonResult updateSectAttr(@Valid @RequestBody SectAttrSaveReqVO updateReqVO) { + sectAttrService.updateSectAttr(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除库区属性") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:sect-attr:delete')") + public CommonResult deleteSectAttr(@RequestParam("id") String id) { + sectAttrService.deleteSectAttr(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除库区属性") + @PreAuthorize("@ss.hasPermission('wms:sect-attr:delete')") + public CommonResult deleteSectAttrList(@RequestParam("ids") List ids) { + sectAttrService.deleteSectAttrListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得库区属性") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:sect-attr:query')") + public CommonResult getSectAttr(@RequestParam("id") String id) { + SectAttrDO sectAttr = sectAttrService.getSectAttr(id); + return success(BeanUtils.toBean(sectAttr, SectAttrRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得库区属性分页") + @PreAuthorize("@ss.hasPermission('wms:sect-attr:query')") + public CommonResult> getSectAttrPage(@Valid SectAttrPageReqVO pageReqVO) { + PageResult pageResult = sectAttrService.getSectAttrPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, SectAttrRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出库区属性 Excel") + @PreAuthorize("@ss.hasPermission('wms:sect-attr:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSectAttrExcel(@Valid SectAttrPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = sectAttrService.getSectAttrPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "库区属性.xls", "数据", SectAttrRespVO.class, + BeanUtils.toBean(list, SectAttrRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得启用的库区属性精简列表") + @Parameter(name = "storId", description = "仓库标识,可选") + public CommonResult> getSectAttrSimpleList( + @RequestParam(value = "storId", required = false) String storId) { + List list = sectAttrService.getSectAttrSimpleList(storId); + return success(BeanUtils.toBean(list, SectAttrSimpleRespVO.class)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrPageReqVO.java new file mode 100644 index 00000000..3f79faad --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrPageReqVO.java @@ -0,0 +1,35 @@ +package cn.code.nl.module.wms.controller.admin.sectattr.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 库区属性分页 Request VO") +@Data +public class SectAttrPageReqVO extends PageParam { + + @Schema(description = "库区编码") + private String sectCode; + + @Schema(description = "库区名称", example = "芋艿") + private String sectName; + + @Schema(description = "库区类型") + private String sectTypeAttr; + + @Schema(description = "仓库标识", example = "24614") + private String storId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "是否启用") + private String isUsed; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrRespVO.java new file mode 100644 index 00000000..b63bab72 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrRespVO.java @@ -0,0 +1,79 @@ +package cn.code.nl.module.wms.controller.admin.sectattr.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 库区属性 Response VO") +@Data +@ExcelIgnoreUnannotated +public class SectAttrRespVO { + + @Schema(description = "库区标识", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("库区标识") + private String sectId; + + @Schema(description = "库区编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("库区编码") + private String sectCode; + + @Schema(description = "库区名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("库区名称") + private String sectName; + + @Schema(description = "库区简称", example = "张三") + @ExcelProperty("库区简称") + private String simpleName; + + @Schema(description = "库区类型", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("库区类型") + private String sectTypeAttr; + + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "24614") + @ExcelProperty("仓库标识") + private String storId; + + @Schema(description = "仓库类型", example = "1") + @ExcelProperty("仓库类型") + private String storType; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "背景色") + @ExcelProperty("背景色") + private String backGroundColor; + + @Schema(description = "前景色") + @ExcelProperty("前景色") + private String frontGroundColor; + + @Schema(description = "背景图片") + @ExcelProperty("背景图片") + private String backGroundPic; + + @Schema(description = "字体显示方向") + @ExcelProperty("字体显示方向") + private String fontDirectionScode; + + @Schema(description = "所在楼层") + @ExcelProperty("所在楼层") + private Integer floorNo; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("是否启用") + private String isUsed; + + @Schema(description = "外部标识", example = "16459") + @ExcelProperty("外部标识") + private String extId; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrSaveReqVO.java new file mode 100644 index 00000000..c2d21746 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrSaveReqVO.java @@ -0,0 +1,89 @@ +package cn.code.nl.module.wms.controller.admin.sectattr.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - 库区属性新增/修改 Request VO") +@Data +public class SectAttrSaveReqVO { + + @Schema(description = "库区标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "23215") + private String sectId; + + @Schema(description = "库区编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "库区编码不能为空") + private String sectCode; + + @Schema(description = "库区名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "库区名称不能为空") + private String sectName; + + @Schema(description = "库区简称", example = "张三") + private String simpleName; + + @Schema(description = "库区类型", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "库区类型不能为空") + private String sectTypeAttr; + + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "24614") + @NotEmpty(message = "仓库标识不能为空") + private String storId; + + @Schema(description = "仓库类型", example = "1") + private String storType; + + @Schema(description = "容量") + private Integer capacity; + + @Schema(description = "宽度") + private Integer width; + + @Schema(description = "高度") + private Integer height; + + @Schema(description = "深度") + private Integer zdepth; + + @Schema(description = "起始X坐标") + private Integer xqty; + + @Schema(description = "起始Y坐标") + private Integer yqty; + + @Schema(description = "起始Z坐标") + private Integer zqty; + + @Schema(description = "负责人", example = "张三") + private String sectManagerName; + + @Schema(description = "负责人电话") + private String mobileNo; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "背景色") + private String backGroundColor; + + @Schema(description = "前景色") + private String frontGroundColor; + + @Schema(description = "背景图片") + private String backGroundPic; + + @Schema(description = "字体显示方向") + private String fontDirectionScode; + + @Schema(description = "所在楼层") + private Integer floorNo; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "是否启用不能为空") + private String isUsed; + + @Schema(description = "外部标识", example = "16459") + private String extId; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrSimpleRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrSimpleRespVO.java new file mode 100644 index 00000000..797b3b3b --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/sectattr/vo/SectAttrSimpleRespVO.java @@ -0,0 +1,22 @@ +package cn.code.nl.module.wms.controller.admin.sectattr.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 库区属性精简 Response VO") +@Data +public class SectAttrSimpleRespVO { + + @Schema(description = "库区标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String sectId; + + @Schema(description = "库区编码", example = "KQ001") + private String sectCode; + + @Schema(description = "库区名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "A区") + private String sectName; + + @Schema(description = "仓库标识", example = "2048") + private String storId; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/StorageVehicleExtController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/StorageVehicleExtController.java new file mode 100644 index 00000000..42dcb612 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/StorageVehicleExtController.java @@ -0,0 +1,104 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleext; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.storagevehicleext.vo.*; +import cn.code.nl.module.wms.dal.dataobject.storagevehicleext.StorageVehicleExtDO; +import cn.code.nl.module.wms.service.storagevehicleext.StorageVehicleExtService; + +@Tag(name = "管理后台 - 载具扩展属性信息") +@RestController +@RequestMapping("/wms/storage-vehicle-ext") +@Validated +public class StorageVehicleExtController { + + @Resource + private StorageVehicleExtService storageVehicleExtService; + + @PostMapping("/create") + @Operation(summary = "创建载具扩展属性信息") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-ext:create')") + public CommonResult createStorageVehicleExt(@Valid @RequestBody StorageVehicleExtSaveReqVO createReqVO) { + return success(storageVehicleExtService.createStorageVehicleExt(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新载具扩展属性信息") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-ext:update')") + public CommonResult updateStorageVehicleExt(@Valid @RequestBody StorageVehicleExtSaveReqVO updateReqVO) { + storageVehicleExtService.updateStorageVehicleExt(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除载具扩展属性信息") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-ext:delete')") + public CommonResult deleteStorageVehicleExt(@RequestParam("id") Long id) { + storageVehicleExtService.deleteStorageVehicleExt(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除载具扩展属性信息") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-ext:delete')") + public CommonResult deleteStorageVehicleExtList(@RequestParam("ids") List ids) { + storageVehicleExtService.deleteStorageVehicleExtListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得载具扩展属性信息") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-ext:query')") + public CommonResult getStorageVehicleExt(@RequestParam("id") Long id) { + StorageVehicleExtDO storageVehicleExt = storageVehicleExtService.getStorageVehicleExt(id); + return success(BeanUtils.toBean(storageVehicleExt, StorageVehicleExtRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得载具扩展属性信息分页") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-ext:query')") + public CommonResult> getStorageVehicleExtPage(@Valid StorageVehicleExtPageReqVO pageReqVO) { + PageResult pageResult = storageVehicleExtService.getStorageVehicleExtPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, StorageVehicleExtRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出载具扩展属性信息 Excel") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-ext:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStorageVehicleExtExcel(@Valid StorageVehicleExtPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = storageVehicleExtService.getStorageVehicleExtPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "载具扩展属性信息.xls", "数据", StorageVehicleExtRespVO.class, + BeanUtils.toBean(list, StorageVehicleExtRespVO.class)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtPageReqVO.java new file mode 100644 index 00000000..17811021 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtPageReqVO.java @@ -0,0 +1,36 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleext.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 载具扩展属性信息分页 Request VO") +@Data +public class StorageVehicleExtPageReqVO extends PageParam { + + @Schema(description = "载具编码") + private String storageVehicleCode; + + @Schema(description = "载具类型", example = "1") + private String storageVehicleType; + + @Schema(description = "物料标识", example = "9871") + private Long materialId; + + @Schema(description = "批次") + private String pcsn; + + @Schema(description = "木箱号") + private String boxNo; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtRespVO.java new file mode 100644 index 00000000..2ecb2e01 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtRespVO.java @@ -0,0 +1,72 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleext.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 载具扩展属性信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class StorageVehicleExtRespVO { + + @Schema(description = "载具编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("载具编码") + private String storageVehicleCode; + + @Schema(description = "载具类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("载具类型") + private String storageVehicleType; + + @Schema(description = "物料标识", example = "9871") + @ExcelProperty("物料标识") + private Long materialId; + + @Schema(description = "批次") + @ExcelProperty("批次") + private String pcsn; + + @Schema(description = "木箱号") + @ExcelProperty("木箱号") + private String boxNo; + + @Schema(description = "数量计量单位标识", example = "5443") + @ExcelProperty("数量计量单位标识") + private Long qtyUnitId; + + @Schema(description = "数量计量单位名称", example = "赵六") + @ExcelProperty("数量计量单位名称") + private String qtyUnitName; + + @Schema(description = "物料数量") + @ExcelProperty("物料数量") + private BigDecimal qty; + + @Schema(description = "托盘重量", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("托盘重量") + private BigDecimal vehicleWeight; + + @Schema(description = "重量计量单位标识", example = "4653") + @ExcelProperty("重量计量单位标识") + private Long weightUnitId; + + @Schema(description = "重量计量单位名称", example = "王五") + @ExcelProperty("重量计量单位名称") + private String weightUnitName; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtSaveReqVO.java new file mode 100644 index 00000000..98662113 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleext/vo/StorageVehicleExtSaveReqVO.java @@ -0,0 +1,58 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleext.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 载具扩展属性信息新增/修改 Request VO") +@Data +public class StorageVehicleExtSaveReqVO { + + private Long storageVehicleExtId; + + @Schema(description = "载具标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "7198") + @NotNull(message = "载具标识不能为空") + private Long storageVehicleId; + + @Schema(description = "载具编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "载具编码不能为空") + private String storageVehicleCode; + + @Schema(description = "载具类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "载具类型不能为空") + private String storageVehicleType; + + @Schema(description = "物料标识", example = "9871") + private Long materialId; + + @Schema(description = "批次") + private String pcsn; + + @Schema(description = "木箱号") + private String boxNo; + + @Schema(description = "数量计量单位标识", example = "5443") + private Long qtyUnitId; + + @Schema(description = "数量计量单位名称", example = "赵六") + private String qtyUnitName; + + @Schema(description = "物料数量") + private BigDecimal qty; + + @Schema(description = "托盘重量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "托盘重量不能为空") + private BigDecimal vehicleWeight; + + @Schema(description = "重量计量单位标识", example = "4653") + private Long weightUnitId; + + @Schema(description = "重量计量单位名称", example = "王五") + private String weightUnitName; + + @Schema(description = "备注", example = "随便") + private String remark; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/StorageVehicleInfoController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/StorageVehicleInfoController.java new file mode 100644 index 00000000..cd8536dd --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/StorageVehicleInfoController.java @@ -0,0 +1,111 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleinfo; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.storagevehicleinfo.vo.*; +import cn.code.nl.module.wms.dal.dataobject.storagevehicleinfo.StorageVehicleInfoDO; +import cn.code.nl.module.wms.service.storagevehicleinfo.StorageVehicleInfoService; + +@Tag(name = "管理后台 - 载具信息") +@RestController +@RequestMapping("/wms/storage-vehicle-info") +@Validated +public class StorageVehicleInfoController { + + @Resource + private StorageVehicleInfoService storageVehicleInfoService; + + @PostMapping("/create") + @Operation(summary = "创建载具信息") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-info:create')") + public CommonResult createStorageVehicleInfo(@Valid @RequestBody StorageVehicleInfoSaveReqVO createReqVO) { + return success(storageVehicleInfoService.createStorageVehicleInfo(createReqVO)); + } + + @PostMapping("/batch-create") + @Operation(summary = "批量生成载具信息") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-info:create')") + public CommonResult> batchCreateStorageVehicleInfo(@Valid @RequestBody StorageVehicleInfoBatchCreateReqVO reqVO) { + return success(storageVehicleInfoService.batchCreateStorageVehicleInfo(reqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新载具信息") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-info:update')") + public CommonResult updateStorageVehicleInfo(@Valid @RequestBody StorageVehicleInfoSaveReqVO updateReqVO) { + storageVehicleInfoService.updateStorageVehicleInfo(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除载具信息") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-info:delete')") + public CommonResult deleteStorageVehicleInfo(@RequestParam("id") Long id) { + storageVehicleInfoService.deleteStorageVehicleInfo(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除载具信息") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-info:delete')") + public CommonResult deleteStorageVehicleInfoList(@RequestParam("ids") List ids) { + storageVehicleInfoService.deleteStorageVehicleInfoListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得载具信息") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-info:query')") + public CommonResult getStorageVehicleInfo(@RequestParam("id") Long id) { + StorageVehicleInfoDO storageVehicleInfo = storageVehicleInfoService.getStorageVehicleInfo(id); + return success(BeanUtils.toBean(storageVehicleInfo, StorageVehicleInfoRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得载具信息分页") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-info:query')") + public CommonResult> getStorageVehicleInfoPage(@Valid StorageVehicleInfoPageReqVO pageReqVO) { + PageResult pageResult = storageVehicleInfoService.getStorageVehicleInfoPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, StorageVehicleInfoRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出载具信息 Excel") + @PreAuthorize("@ss.hasPermission('wms:storage-vehicle-info:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStorageVehicleInfoExcel(@Valid StorageVehicleInfoPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = storageVehicleInfoService.getStorageVehicleInfoPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "载具信息.xls", "数据", StorageVehicleInfoRespVO.class, + BeanUtils.toBean(list, StorageVehicleInfoRespVO.class)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoBatchCreateReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoBatchCreateReqVO.java new file mode 100644 index 00000000..58bcf6b3 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoBatchCreateReqVO.java @@ -0,0 +1,26 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleinfo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Min; +import lombok.Data; + +@Schema(description = "管理后台 - 载具信息批量生成 Request VO") +@Data +public class StorageVehicleInfoBatchCreateReqVO { + + @Schema(description = "载具类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "MTP") + @NotEmpty(message = "载具类型不能为空") + private String storageVehicleType; + + @Schema(description = "载具类型中文名", requiredMode = Schema.RequiredMode.REQUIRED, example = "木托盘") + @NotEmpty(message = "载具类型中文名不能为空") + private String storageVehicleTypeLabel; + + @Schema(description = "生成数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "生成数量不能为空") + @Min(value = 1, message = "生成数量至少为1") + private Integer count; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoPageReqVO.java new file mode 100644 index 00000000..6e2dfa21 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoPageReqVO.java @@ -0,0 +1,60 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleinfo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 载具信息分页 Request VO") +@Data +public class StorageVehicleInfoPageReqVO extends PageParam { + + @Schema(description = "载具编码") + private String storageVehicleCode; + + @Schema(description = "载具名称") + private String storageVehicleName; + + @Schema(description = "一维码") + private String oneCode; + + @Schema(description = "二维码") + private String twoCode; + + @Schema(description = "是否启用") + private Boolean isUsed; + + @Schema(description = "载具类型") + private String storageVehicleType; + + @Schema(description = "载具宽度") + private Integer vehicleWidth; + + @Schema(description = "载具长度") + private Integer vehicleLong; + + @Schema(description = "载具高度") + private Integer vehicleHeight; + + @Schema(description = "托盘重量") + private BigDecimal weigth; + + @Schema(description = "载具是否超仓位") + private String overStructType; + + @Schema(description = "占仓位数") + private Integer occupyStructQty; + + @Schema(description = "木箱号") + private String boxNo; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoRespVO.java new file mode 100644 index 00000000..e2bbf772 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoRespVO.java @@ -0,0 +1,90 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleinfo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 载具信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class StorageVehicleInfoRespVO { + + private Long storageVehicleId; + + @Schema(description = "载具编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("载具编码") + private String storageVehicleCode; + + @Schema(description = "载具名称") + @ExcelProperty("载具名称") + private String storageVehicleName; + + @Schema(description = "一维码") + @ExcelProperty("一维码") + private String oneCode; + + @Schema(description = "二维码") + @ExcelProperty("二维码") + private String twoCode; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("是否启用") + private Boolean isUsed; + + @Schema(description = "载具类型", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("载具类型") + private String storageVehicleType; + + @Schema(description = "载具宽度") + @ExcelProperty("载具宽度") + private Integer vehicleWidth; + + @Schema(description = "载具长度") + @ExcelProperty("载具长度") + private Integer vehicleLong; + + @Schema(description = "载具高度") + @ExcelProperty("载具高度") + private Integer vehicleHeight; + + @Schema(description = "托盘重量") + @ExcelProperty("托盘重量") + private BigDecimal weigth; + + @Schema(description = "载具是否超仓位", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("载具是否超仓位") + private String overStructType; + + @Schema(description = "占仓位数", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("占仓位数") + private Integer occupyStructQty; + + @Schema(description = "木箱号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("木箱号") + private String boxNo; + + @Schema(description = "外部标识") + @ExcelProperty("外部标识") + private String extId; + + @Schema(description = "创建者") + @ExcelProperty("创建者") + private String creator; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新者") + @ExcelProperty("更新者") + private String updater; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoSaveReqVO.java new file mode 100644 index 00000000..bcdc1f0b --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/storagevehicleinfo/vo/StorageVehicleInfoSaveReqVO.java @@ -0,0 +1,55 @@ +package cn.code.nl.module.wms.controller.admin.storagevehicleinfo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 载具信息新增/修改 Request VO") +@Data +public class StorageVehicleInfoSaveReqVO { + + private Long storageVehicleId; + + @Schema(description = "载具编码", requiredMode = Schema.RequiredMode.REQUIRED) + private String storageVehicleCode; + + @Schema(description = "载具名称") + private String storageVehicleName; + + @Schema(description = "一维码") + private String oneCode; + + @Schema(description = "二维码") + private String twoCode; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否启用不能为空") + private Boolean isUsed; + + @Schema(description = "载具类型", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "载具类型不能为空") + private String storageVehicleType; + + @Schema(description = "载具宽度") + private Integer vehicleWidth; + + @Schema(description = "载具长度") + private Integer vehicleLong; + + @Schema(description = "载具高度") + private Integer vehicleHeight; + + @Schema(description = "托盘重量") + private BigDecimal weigth; + + @Schema(description = "载具是否超仓位", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "载具是否超仓位不能为空") + private String overStructType; + + @Schema(description = "占仓位数", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "占仓位数不能为空") + private Integer occupyStructQty; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/StrucAttrController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/StrucAttrController.java new file mode 100644 index 00000000..02de1a05 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/StrucAttrController.java @@ -0,0 +1,104 @@ +package cn.code.nl.module.wms.controller.admin.structAttr; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.structAttr.vo.*; +import cn.code.nl.module.wms.dal.dataobject.structAttr.StrucAttrDO; +import cn.code.nl.module.wms.service.structAttr.StrucAttrService; + +@Tag(name = "管理后台 - 仓位属性") +@RestController +@RequestMapping("/wms/struc-attr") +@Validated +public class StrucAttrController { + + @Resource + private StrucAttrService strucAttrService; + + @PostMapping("/create") + @Operation(summary = "创建仓位属性") + @PreAuthorize("@ss.hasPermission('wms:struc-attr:create')") + public CommonResult createStrucAttr(@Valid @RequestBody StrucAttrSaveReqVO createReqVO) { + return success(strucAttrService.createStrucAttr(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新仓位属性") + @PreAuthorize("@ss.hasPermission('wms:struc-attr:update')") + public CommonResult updateStrucAttr(@Valid @RequestBody StrucAttrSaveReqVO updateReqVO) { + strucAttrService.updateStrucAttr(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除仓位属性") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:struc-attr:delete')") + public CommonResult deleteStrucAttr(@RequestParam("id") String id) { + strucAttrService.deleteStrucAttr(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除仓位属性") + @PreAuthorize("@ss.hasPermission('wms:struc-attr:delete')") + public CommonResult deleteStrucAttrList(@RequestParam("ids") List ids) { + strucAttrService.deleteStrucAttrListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得仓位属性") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:struc-attr:query')") + public CommonResult getStrucAttr(@RequestParam("id") String id) { + StrucAttrDO strucAttr = strucAttrService.getStrucAttr(id); + return success(BeanUtils.toBean(strucAttr, StrucAttrRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得仓位属性分页") + @PreAuthorize("@ss.hasPermission('wms:struc-attr:query')") + public CommonResult> getStrucAttrPage(@Valid StrucAttrPageReqVO pageReqVO) { + PageResult pageResult = strucAttrService.getStrucAttrPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, StrucAttrRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出仓位属性 Excel") + @PreAuthorize("@ss.hasPermission('wms:struc-attr:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStrucAttrExcel(@Valid StrucAttrPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = strucAttrService.getStrucAttrPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "仓位属性.xls", "数据", StrucAttrRespVO.class, + BeanUtils.toBean(list, StrucAttrRespVO.class)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrPageReqVO.java new file mode 100644 index 00000000..0206e9c1 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrPageReqVO.java @@ -0,0 +1,128 @@ +package cn.code.nl.module.wms.controller.admin.structAttr.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 仓位属性分页 Request VO") +@Data +public class StrucAttrPageReqVO extends PageParam { + + @Schema(description = "仓位编码") + private String structCode; + + @Schema(description = "仓位名称", example = "芋艿") + private String structName; + + @Schema(description = "仓位简称", example = "赵六") + private String simpleName; + + @Schema(description = "库区标识", example = "29259") + private String sectId; + + @Schema(description = "库区编码") + private String sectCode; + + @Schema(description = "库区名称", example = "李四") + private String sectName; + + @Schema(description = "仓库标识", example = "9143") + private String storId; + + @Schema(description = "仓库编码") + private String storCode; + + @Schema(description = "仓库名称", example = "王五") + private String storName; + + @Schema(description = "仓库类型", example = "1") + private String storType; + + @Schema(description = "容量") + private Integer capacity; + + @Schema(description = "宽度") + private Integer width; + + @Schema(description = "高度") + private Integer height; + + @Schema(description = "深度") + private Integer zdepth; + + @Schema(description = "承受重量") + private Integer weight; + + @Schema(description = "起始X坐标") + private Integer xqty; + + @Schema(description = "起始Y坐标") + private Integer yqty; + + @Schema(description = "起始Z坐标") + private Integer zqty; + + @Schema(description = "是否临时仓位") + private String isTempstruct; + + @Schema(description = "排") + private Integer rowNum; + + @Schema(description = "列") + private Integer colNum; + + @Schema(description = "层") + private Integer layerNum; + + @Schema(description = "块") + private Integer blockNum; + + @Schema(description = "放置类型", example = "1") + private String placementType; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "是否启用") + private Boolean isUsed; + + @Schema(description = "是否判断高度") + private String isZdepth; + + @Schema(description = "存储载具号") + private String storagevehicleCode; + + @Schema(description = "载具类型", example = "2") + private String storagevehicleType; + + @Schema(description = "载具数量") + private Integer storagevehicleQty; + + @Schema(description = "锁定类型", example = "2") + private String lockType; + + @Schema(description = "锁定任务编码") + private String taskCode; + + @Schema(description = "锁定单据类型", example = "2") + private String invType; + + @Schema(description = "锁定单据标识", example = "20840") + private String invId; + + @Schema(description = "锁定单据编码") + private String invCode; + + @Schema(description = "外部标识", example = "1926") + private String extId; + + @Schema(description = "备注", example = "你猜") + private String remark; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrRespVO.java new file mode 100644 index 00000000..c2247d39 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrRespVO.java @@ -0,0 +1,135 @@ +package cn.code.nl.module.wms.controller.admin.structAttr.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 仓位属性 Response VO") +@Data +@ExcelIgnoreUnannotated +public class StrucAttrRespVO { + + @Schema(description = "仓位标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "22093") + @ExcelProperty("仓位标识") + private String structId; + + @Schema(description = "仓位编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("仓位编码") + private String structCode; + + @Schema(description = "仓位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("仓位名称") + private String structName; + + @Schema(description = "仓位简称", example = "赵六") + @ExcelProperty("仓位简称") + private String simpleName; + + @Schema(description = "库区标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "29259") + @ExcelProperty("库区标识") + private String sectId; + + @Schema(description = "库区编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("库区编码") + private String sectCode; + + @Schema(description = "库区名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("库区名称") + private String sectName; + + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "9143") + @ExcelProperty("仓库标识") + private String storId; + + @Schema(description = "仓库编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("仓库编码") + private String storCode; + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @ExcelProperty("仓库名称") + private String storName; + + @Schema(description = "仓库类型", example = "1") + @ExcelProperty("仓库类型") + private String storType; + + @Schema(description = "高度") + @ExcelProperty("高度") + private Integer height; + + @Schema(description = "排") + @ExcelProperty("排") + private Integer rowNum; + + @Schema(description = "列") + @ExcelProperty("列") + private Integer colNum; + + @Schema(description = "层") + @ExcelProperty("层") + private Integer layerNum; + + @Schema(description = "块") + @ExcelProperty("块") + private Integer blockNum; + + @Schema(description = "放置类型", example = "1") + @ExcelProperty("放置类型") + private String placementType; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("是否启用") + private Boolean isUsed; + + @Schema(description = "是否判断高度") + @ExcelProperty("是否判断高度") + private String isZdepth; + + @Schema(description = "存储载具号") + @ExcelProperty("存储载具号") + private String storagevehicleCode; + + @Schema(description = "载具类型", example = "2") + @ExcelProperty("载具类型") + private String storagevehicleType; + + @Schema(description = "载具数量") + @ExcelProperty("载具数量") + private Integer storagevehicleQty; + + @Schema(description = "锁定类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("锁定类型") + private String lockType; + + @Schema(description = "锁定任务编码") + @ExcelProperty("锁定任务编码") + private String taskCode; + + @Schema(description = "锁定单据类型", example = "2") + @ExcelProperty("锁定单据类型") + private String invType; + + @Schema(description = "锁定单据标识", example = "20840") + @ExcelProperty("锁定单据标识") + private String invId; + + @Schema(description = "锁定单据编码") + @ExcelProperty("锁定单据编码") + private String invCode; + + @Schema(description = "外部标识", example = "1926") + @ExcelProperty("外部标识") + private String extId; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrSaveReqVO.java new file mode 100644 index 00000000..a4f16926 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/structAttr/vo/StrucAttrSaveReqVO.java @@ -0,0 +1,134 @@ +package cn.code.nl.module.wms.controller.admin.structAttr.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - 仓位属性新增/修改 Request VO") +@Data +public class StrucAttrSaveReqVO { + + @Schema(description = "仓位标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "22093") + private String structId; + + @Schema(description = "仓位编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "仓位编码不能为空") + private String structCode; + + @Schema(description = "仓位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "仓位名称不能为空") + private String structName; + + @Schema(description = "仓位简称", example = "赵六") + private String simpleName; + + @Schema(description = "库区标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "29259") + @NotEmpty(message = "库区标识不能为空") + private String sectId; + + @Schema(description = "库区编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "库区编码不能为空") + private String sectCode; + + @Schema(description = "库区名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "库区名称不能为空") + private String sectName; + + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "9143") + @NotEmpty(message = "仓库标识不能为空") + private String storId; + + @Schema(description = "仓库编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "仓库编码不能为空") + private String storCode; + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotEmpty(message = "仓库名称不能为空") + private String storName; + + @Schema(description = "仓库类型", example = "1") + private String storType; + + @Schema(description = "容量") + private Integer capacity; + + @Schema(description = "宽度") + private Integer width; + + @Schema(description = "高度") + private Integer height; + + @Schema(description = "深度") + private Integer zdepth; + + @Schema(description = "承受重量") + private Integer weight; + + @Schema(description = "起始X坐标") + private Integer xqty; + + @Schema(description = "起始Y坐标") + private Integer yqty; + + @Schema(description = "起始Z坐标") + private Integer zqty; + + @Schema(description = "是否临时仓位", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "是否临时仓位不能为空") + private String isTempstruct; + + @Schema(description = "排") + private Integer rowNum; + + @Schema(description = "列") + private Integer colNum; + + @Schema(description = "层") + private Integer layerNum; + + @Schema(description = "块") + private Integer blockNum; + + @Schema(description = "放置类型", example = "1") + private String placementType; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否启用不能为空") + private Boolean isUsed; + + @Schema(description = "是否判断高度") + private String isZdepth; + + @Schema(description = "存储载具号") + private String storagevehicleCode; + + @Schema(description = "载具类型", example = "2") + private String storagevehicleType; + + @Schema(description = "载具数量") + private Integer storagevehicleQty; + + @Schema(description = "锁定类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotEmpty(message = "锁定类型不能为空") + private String lockType; + + @Schema(description = "锁定任务编码") + private String taskCode; + + @Schema(description = "锁定单据类型", example = "2") + private String invType; + + @Schema(description = "锁定单据标识", example = "20840") + private String invId; + + @Schema(description = "锁定单据编码") + private String invCode; + + @Schema(description = "外部标识", example = "1926") + private String extId; + + @Schema(description = "备注", example = "你猜") + private String remark; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/WarehouseStrategyController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/WarehouseStrategyController.java new file mode 100644 index 00000000..6256d310 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/WarehouseStrategyController.java @@ -0,0 +1,106 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategy; + +import org.dromara.core.trans.anno.TransMethodResult; +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.warehousestrategy.vo.*; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategy.WarehouseStrategyDO; +import cn.code.nl.module.wms.service.warehousestrategy.WarehouseStrategyService; + +@Tag(name = "管理后台 - 出入库策略") +@RestController +@RequestMapping("/wms/warehouse-strategy") +@Validated +public class WarehouseStrategyController { + + @Resource + private WarehouseStrategyService warehouseStrategyService; + + @PostMapping("/create") + @Operation(summary = "创建出入库策略") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy:create')") + public CommonResult createWarehouseStrategy(@Valid @RequestBody WarehouseStrategySaveReqVO createReqVO) { + return success(warehouseStrategyService.createWarehouseStrategy(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新出入库策略") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy:update')") + public CommonResult updateWarehouseStrategy(@Valid @RequestBody WarehouseStrategySaveReqVO updateReqVO) { + warehouseStrategyService.updateWarehouseStrategy(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除出入库策略") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy:delete')") + public CommonResult deleteWarehouseStrategy(@RequestParam("id") Long id) { + warehouseStrategyService.deleteWarehouseStrategy(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除出入库策略") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy:delete')") + public CommonResult deleteWarehouseStrategyList(@RequestParam("ids") List ids) { + warehouseStrategyService.deleteWarehouseStrategyListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得出入库策略") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy:query')") + public CommonResult getWarehouseStrategy(@RequestParam("id") Long id) { + WarehouseStrategyDO warehouseStrategy = warehouseStrategyService.getWarehouseStrategy(id); + return success(BeanUtils.toBean(warehouseStrategy, WarehouseStrategyRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得出入库策略分页") + @TransMethodResult + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy:query')") + public CommonResult> getWarehouseStrategyPage(@Valid WarehouseStrategyPageReqVO pageReqVO) { + PageResult pageResult = warehouseStrategyService.getWarehouseStrategyPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, WarehouseStrategyRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出出入库策略 Excel") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportWarehouseStrategyExcel(@Valid WarehouseStrategyPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = warehouseStrategyService.getWarehouseStrategyPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "出入库策略.xls", "数据", WarehouseStrategyRespVO.class, + BeanUtils.toBean(list, WarehouseStrategyRespVO.class)); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategyPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategyPageReqVO.java new file mode 100644 index 00000000..516ae950 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategyPageReqVO.java @@ -0,0 +1,29 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategy.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 出入库策略分页 Request VO") +@Data +public class WarehouseStrategyPageReqVO extends PageParam { + + @Schema(description = "库区编码") + private String sectionCode; + + @Schema(description = "规则") + private String strategy; + + @Schema(description = "策略类型", example = "1入库2出库") + private String strategyType; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategyRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategyRespVO.java new file mode 100644 index 00000000..29361087 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategyRespVO.java @@ -0,0 +1,58 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategy.vo; + +import cn.code.nl.module.system.api.user.AdminUserApi; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; + +import org.dromara.core.trans.anno.Trans; +import org.dromara.core.trans.constant.TransType; +import org.dromara.core.trans.vo.VO; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 出入库策略 Response VO") +@Data +@ExcelIgnoreUnannotated +public class WarehouseStrategyRespVO implements VO { + + private Long id; + + @Schema(description = "库区编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("库区编码") + private String sectionCode; + + @Schema(description = "规则", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("规则") + private String strategy; + + @Schema(description = "策略类型", example = "1入库2出库") + @ExcelProperty("策略类型") + private String strategyType; + + @Schema(description = "描述") + @ExcelProperty("描述") + private String description; + + @Schema(description = "创建者") + @ExcelProperty("创建者") + @Trans(type = TransType.AUTO_TRANS, key = AdminUserApi.PREFIX, fields = "nickname", ref = "creatorName") + private String creator; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "创建者名称") + private String creatorName; + + @Schema(description = "更新者", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新者") + private String updater; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategySaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategySaveReqVO.java new file mode 100644 index 00000000..4fe67703 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategy/vo/WarehouseStrategySaveReqVO.java @@ -0,0 +1,28 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategy.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - 出入库策略新增/修改 Request VO") +@Data +public class WarehouseStrategySaveReqVO { + + private Long id; + + @Schema(description = "库区编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "库区编码不能为空") + private String sectionCode; + + @Schema(description = "规则", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "规则不能为空") + private String strategy; + + @Schema(description = "策略类型", example = "1入库2出库") + private String strategyType; + + @Schema(description = "描述") + private String description; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/WarehouseStrategyConfigController.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/WarehouseStrategyConfigController.java new file mode 100644 index 00000000..0a9c998e --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/WarehouseStrategyConfigController.java @@ -0,0 +1,112 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategyconfig; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import static cn.code.nl.framework.common.pojo.CommonResult.success; + +import cn.code.nl.framework.excel.core.util.ExcelUtils; + +import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog; +import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo.*; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategyconfig.WarehouseStrategyConfigDO; +import cn.code.nl.module.wms.service.warehousestrategyconfig.WarehouseStrategyConfigService; + +@Tag(name = "管理后台 - 仓储策略配置") +@RestController +@RequestMapping("/wms/warehouse-strategy-config") +@Validated +public class WarehouseStrategyConfigController { + + @Resource + private WarehouseStrategyConfigService warehouseStrategyConfigService; + + @PostMapping("/create") + @Operation(summary = "创建仓储策略配置") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy-config:create')") + public CommonResult createWarehouseStrategyConfig(@Valid @RequestBody WarehouseStrategyConfigSaveReqVO createReqVO) { + return success(warehouseStrategyConfigService.createWarehouseStrategyConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新仓储策略配置") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy-config:update')") + public CommonResult updateWarehouseStrategyConfig(@Valid @RequestBody WarehouseStrategyConfigSaveReqVO updateReqVO) { + warehouseStrategyConfigService.updateWarehouseStrategyConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除仓储策略配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy-config:delete')") + public CommonResult deleteWarehouseStrategyConfig(@RequestParam("id") Long id) { + warehouseStrategyConfigService.deleteWarehouseStrategyConfig(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除仓储策略配置") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy-config:delete')") + public CommonResult deleteWarehouseStrategyConfigList(@RequestParam("ids") List ids) { + warehouseStrategyConfigService.deleteWarehouseStrategyConfigListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得仓储策略配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy-config:query')") + public CommonResult getWarehouseStrategyConfig(@RequestParam("id") Long id) { + WarehouseStrategyConfigDO warehouseStrategyConfig = warehouseStrategyConfigService.getWarehouseStrategyConfig(id); + return success(BeanUtils.toBean(warehouseStrategyConfig, WarehouseStrategyConfigRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得仓储策略配置分页") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy-config:query')") + public CommonResult> getWarehouseStrategyConfigPage(@Valid WarehouseStrategyConfigPageReqVO pageReqVO) { + PageResult pageResult = warehouseStrategyConfigService.getWarehouseStrategyConfigPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, WarehouseStrategyConfigRespVO.class)); + } + + @GetMapping(value = {"/list-all-simple", "/simple-list"}) + @Operation(summary = "获得仓储策略配置精简列表") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy-config:query')") + public CommonResult> getSimpleWarehouseStrategyConfigList() { + List list = warehouseStrategyConfigService.getWarehouseStrategyConfigList(); + return success(BeanUtils.toBean(list, WarehouseStrategyConfigSimpleRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出仓储策略配置 Excel") + @PreAuthorize("@ss.hasPermission('wms:warehouse-strategy-config:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportWarehouseStrategyConfigExcel(@Valid WarehouseStrategyConfigPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = warehouseStrategyConfigService.getWarehouseStrategyConfigPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "仓储策略配置.xls", "数据", WarehouseStrategyConfigRespVO.class, + BeanUtils.toBean(list, WarehouseStrategyConfigRespVO.class)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigPageReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigPageReqVO.java new file mode 100644 index 00000000..18cb327f --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigPageReqVO.java @@ -0,0 +1,47 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.code.nl.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 仓储策略配置分页 Request VO") +@Data +public class WarehouseStrategyConfigPageReqVO extends PageParam { + + @Schema(description = "策略编码") + private String strategyCode; + + @Schema(description = "策略名称", example = "赵六") + private String strategyName; + + @Schema(description = "策略类型", example = "1") + private String strategyType; + + @Schema(description = "类处理类型", example = "2") + private String classType; + + @Schema(description = "处理类") + private String param; + + @Schema(description = "描述", example = "你说的对") + private String remark; + + @Schema(description = "是否启用") + private Boolean isUsed; + + @Schema(description = "禁止操作") + private Boolean ban; + + @Schema(description = "限定参数") + private String formData; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigRespVO.java new file mode 100644 index 00000000..e0aa413a --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigRespVO.java @@ -0,0 +1,69 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.*; + +@Schema(description = "管理后台 - 仓储策略配置 Response VO") +@Data +@ExcelIgnoreUnannotated +public class WarehouseStrategyConfigRespVO { + + private String id; + + @Schema(description = "策略编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("策略编码") + private String strategyCode; + + @Schema(description = "策略名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @ExcelProperty("策略名称") + private String strategyName; + + @Schema(description = "策略类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("策略类型") + private String strategyType; + + @Schema(description = "类处理类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("类处理类型") + private String classType; + + @Schema(description = "处理类", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("处理类") + private String param; + + @Schema(description = "描述", example = "你说的对") + @ExcelProperty("描述") + private String remark; + + @Schema(description = "是否启用") + @ExcelProperty("是否启用") + private Boolean isUsed; + + @Schema(description = "禁止操作") + @ExcelProperty("禁止操作") + private Boolean ban; + + @Schema(description = "限定参数") + @ExcelProperty("限定参数") + private String formData; + + @Schema(description = "创建者") + @ExcelProperty("创建者") + private String creator; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新者") + @ExcelProperty("更新者") + private String updater; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigSaveReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigSaveReqVO.java new file mode 100644 index 00000000..ee4ef087 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigSaveReqVO.java @@ -0,0 +1,46 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - 仓储策略配置新增/修改 Request VO") +@Data +public class WarehouseStrategyConfigSaveReqVO { + + private Long id; + + @Schema(description = "策略编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "策略编码不能为空") + private String strategyCode; + + @Schema(description = "策略名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "策略名称不能为空") + private String strategyName; + + @Schema(description = "策略类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "策略类型不能为空") + private String strategyType; + + @Schema(description = "类处理类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotEmpty(message = "类处理类型不能为空") + private String classType; + + @Schema(description = "处理类", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "处理类不能为空") + private String param; + + @Schema(description = "描述", example = "你说的对") + private String remark; + + @Schema(description = "是否启用") + private Boolean isUsed; + + @Schema(description = "禁止操作") + private Boolean ban; + + @Schema(description = "限定参数") + private String formData; + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigSimpleRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigSimpleRespVO.java new file mode 100644 index 00000000..e4402367 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/warehousestrategyconfig/vo/WarehouseStrategyConfigSimpleRespVO.java @@ -0,0 +1,19 @@ +package cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 仓储策略配置精简 Response VO") +@Data +public class WarehouseStrategyConfigSimpleRespVO { + + @Schema(description = "策略编码", requiredMode = Schema.RequiredMode.REQUIRED) + private String strategyCode; + + @Schema(description = "策略名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String strategyName; + + @Schema(description = "类处理类型", requiredMode = Schema.RequiredMode.REQUIRED) + private String classType; + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/groupplate/GroupPlateDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/groupplate/GroupPlateDO.java new file mode 100644 index 00000000..0a510abe --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/groupplate/GroupPlateDO.java @@ -0,0 +1,90 @@ +package cn.code.nl.module.wms.dal.dataobject.groupplate; + +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 组盘记录 DO + * + * @author 诺力管理员 + */ +@TableName("wms_group_plate") +@KeySequence("wms_group_plate_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GroupPlateDO extends BaseDO { + + /** + * 组盘标识 + */ + @TableId + private Long groupId; + /** + * 载具编码 + */ + private String vehicleCode; + /** + * 状态 + */ + private String status; + /** + * 物料id + */ + private String materialId; + /** + * 批次 + */ + private String pcsn; + /** + * 数量 + */ + private BigDecimal qty; + /** + * 冻结数量 + */ + private BigDecimal frozenQty; + /** + * 计量单位标识 + */ + private String qtyUnitId; + /** + * 计量单位名称 + */ + private String qtyUnitName; + /** + * 备注 + */ + private String remark; + /** + * 来源单据号 + */ + private String extCode; + /** + * 来源单据类型 + */ + private String extType; + /** + * 来源单据明细号 + */ + private String extDtlCode; + /** + * md5 + */ + private String md5; + /** + * 物料编码 + */ + private String materialCode; + + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinv/IostorInvDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinv/IostorInvDO.java new file mode 100644 index 00000000..939927ef --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinv/IostorInvDO.java @@ -0,0 +1,137 @@ +package cn.code.nl.module.wms.dal.dataobject.iostorinv; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.math.BigDecimal; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 出入库单主表 DO + * + * @author 诺力管理员 + */ +@TableName("wms_iostorinv") +@KeySequence("wms_iostorinv_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IostorInvDO extends BaseDO { + + /** + * 出入单标识 + */ + @TableId + private Long iostorinvId; + /** + * 单据编号 + */ + private String billCode; + /** + * 出入类型 + */ + private String ioType; + /** + * 单据类型 + */ + private String billType; + /** + * 业务日期 + */ + private LocalDateTime bizDate; + /** + * 仓库标识 + */ + private String storId; + /** + * 仓库编码 + */ + private String storCode; + /** + * 仓库名称 + */ + private String storName; + /** + * 来源方标识 + */ + private String sourceId; + /** + * 来源方名称 + */ + private String sourceName; + /** + * 来源方类型 + */ + private String sourceType; + /** + * 总数量 + */ + private BigDecimal totalQty; + /** + * 总重量 + */ + private BigDecimal totalWeight; + /** + * 明细数 + */ + private Integer detailCount; + /** + * 单据状态 + */ + private String billStatus; + /** + * 备注 + */ + private String remark; + /** + * 生成方式 + */ + private String createMode; + /** + * 分配人 + */ + private String disOptid; + /** + * 分配时间 + */ + private LocalDateTime disTime; + /** + * 确认人 + */ + private String confirmOptid; + /** + * 确认时间 + */ + private LocalDateTime confirmTime; + /** + * 部门ID + */ + private String sysdeptid; + /** + * 公司ID + */ + private String syscompanyid; + /** + * 是否已上传 + */ + private String isUpload; + /** + * 回传人 + */ + private String uploadOptid; + /** + * 回传时间 + */ + private String uploadTime; + + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinvdis/IostorinvDisDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinvdis/IostorinvDisDO.java new file mode 100644 index 00000000..d6ba1660 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinvdis/IostorinvDisDO.java @@ -0,0 +1,120 @@ +package cn.code.nl.module.wms.dal.dataobject.iostorinvdis; + +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 出入库单分配 DO + * + * @author 诺力管理员 + */ +@TableName("wms_iostorinvdis") +@KeySequence("wms_iostorinvdis_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IostorinvDisDO extends BaseDO { + + /** + * 出入单分配标识 + */ + @TableId(type = IdType.INPUT) + private String iostorinvdisId; + /** + * 出入单标识 + */ + private String iostorinvId; + /** + * 出入单明细标识 + */ + private String iostorinvdtlId; + /** + * 明细序号 + */ + private String seqNo; + /** + * 库区标识 + */ + private String sectId; + /** + * 库区编码 + */ + private String sectCode; + /** + * 库区名称 + */ + private String sectName; + /** + * 仓位标识 + */ + private String structId; + /** + * 仓位编码 + */ + private String structCode; + /** + * 仓位名称 + */ + private String structName; + /** + * 物料标识 + */ + private String materialId; + /** + * 物料编码 + */ + private String materialCode; + /** + * 批次 + */ + private String pcsn; + /** + * 执行状态 + */ + private String workStatus; + /** + * 任务标识 + */ + private String taskId; + /** + * 存储载具编码 + */ + private String storagevehicleCode; + /** + * 是否已下发 + */ + private String isIssued; + /** + * 数量计量单位标识 + */ + private String qtyUnitId; + /** + * 数量计量单位名称 + */ + private String qtyUnitName; + /** + * 计划数量 + */ + private BigDecimal planQty; + /** + * 实际数量 + */ + private BigDecimal realQty; + /** + * 出入点位标识 + */ + private String pointCode; + /** + * 出库类型:0自动搬运1手动搬运 + */ + private Boolean handType; + + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinvdtl/IostorinvDtlDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinvdtl/IostorinvDtlDO.java new file mode 100644 index 00000000..5f65d7ab --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/iostorinvdtl/IostorinvDtlDO.java @@ -0,0 +1,106 @@ +package cn.code.nl.module.wms.dal.dataobject.iostorinvdtl; + +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import java.math.BigDecimal; +import java.math.BigDecimal; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 出入库单明细 DO + * + * @author 诺力管理员 + */ +@TableName("wms_iostorinvdtl") +@KeySequence("wms_iostorinvdtl_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IostorinvDtlDO { + + /** + * 出入单明细标识 + */ + @TableId + private Long iostorinvdtlId; + /** + * 出入单标识 + */ + private Long iostorinvId; + /** + * 明细序号 + */ + private Integer seqNo; + /** + * 批次 + */ + private String pcsn; + /** + * 单据明细状态 + */ + private String billStatus; + /** + * 数量计量单位标识 + */ + private String qtyUnitId; + + /** + * 计划数量 + */ + private BigDecimal planQty; + /** + * 实际数量 + */ + private BigDecimal realQty; + /** + * 来源单据明细标识 + */ + private String sourceBilldtlId; + /** + * 来源单据类型 + */ + private String sourceBillType; + /** + * 来源单编号 + */ + private String sourceBillCode; + /** + * 来源单表名 + */ + private String sourceBillTable; + /** + * 备注 + */ + private String remark; + /** + * 已分配数量 + */ + private BigDecimal assignQty; + /** + * 未分配数量 + */ + private BigDecimal unassignQty; + /** + * 物料编号 + */ + private String materialCode; + /** + * 来源单指定上料口 + */ + private String sourceLoadPort; + /** + * 单据回传策略配置类名 + */ + private String callbackStrategy; + /** + * 物料标识 + */ + private String materialId; + + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/sectattr/SectAttrDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/sectattr/SectAttrDO.java new file mode 100644 index 00000000..42f338d8 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/sectattr/SectAttrDO.java @@ -0,0 +1,124 @@ +package cn.code.nl.module.wms.dal.dataobject.sectattr; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 库区属性 DO + * + * @author 诺力管理员 + */ +@TableName("wms_sectattr") +@KeySequence("wms_sectattr_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SectAttrDO extends BaseDO { + + /** + * 库区标识 + */ + @TableId + private String sectId; + /** + * 库区编码 + */ + private String sectCode; + /** + * 库区名称 + */ + private String sectName; + /** + * 库区简称 + */ + private String simpleName; + /** + * 库区类型 + */ + private String sectTypeAttr; + /** + * 仓库标识 + */ + private String storId; + /** + * 仓库类型 + */ + private String storType; + /** + * 容量 + */ + private Integer capacity; + /** + * 宽度 + */ + private Integer width; + /** + * 高度 + */ + private Integer height; + /** + * 深度 + */ + private Integer zdepth; + /** + * 起始X坐标 + */ + private Integer xqty; + /** + * 起始Y坐标 + */ + private Integer yqty; + /** + * 起始Z坐标 + */ + private Integer zqty; + /** + * 负责人 + */ + private String sectManagerName; + /** + * 负责人电话 + */ + private String mobileNo; + /** + * 备注 + */ + private String remark; + /** + * 背景色 + */ + private String backGroundColor; + /** + * 前景色 + */ + private String frontGroundColor; + /** + * 背景图片 + */ + private String backGroundPic; + /** + * 字体显示方向 + */ + private String fontDirectionScode; + /** + * 所在楼层 + */ + private Integer floorNo; + /** + * 是否启用 + */ + private String isUsed; + /** + * 外部标识 + */ + private String extId; + + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/storagevehicleext/StorageVehicleExtDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/storagevehicleext/StorageVehicleExtDO.java new file mode 100644 index 00000000..62f1421b --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/storagevehicleext/StorageVehicleExtDO.java @@ -0,0 +1,90 @@ +package cn.code.nl.module.wms.dal.dataobject.storagevehicleext; + +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 载具扩展属性信息 DO + * + * @author 诺力管理员 + */ +@TableName("wms_storage_vehicle_ext") +@KeySequence("wms_storage_vehicle_ext_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class StorageVehicleExtDO extends BaseDO { + + /** + * 载具扩展标识 + */ + @TableId + private Long storageVehicleExtId; + /** + * 载具标识 + */ + private Long storageVehicleId; + /** + * 载具编码 + */ + private String storageVehicleCode; + /** + * 载具类型 + */ + private String storageVehicleType; + /** + * 物料标识 + */ + private Long materialId; + /** + * 批次 + */ + private String pcsn; + /** + * 木箱号 + */ + private String boxNo; + /** + * 数量计量单位标识 + */ + private Long qtyUnitId; + /** + * 数量计量单位名称 + */ + private String qtyUnitName; + /** + * 物料数量 + */ + private BigDecimal qty; + /** + * 设备标识 + */ + private Long deviceUuid; + /** + * 托盘重量 + */ + private BigDecimal vehicleWeight; + /** + * 重量计量单位标识 + */ + private Long weightUnitId; + /** + * 重量计量单位名称 + */ + private String weightUnitName; + /** + * 备注 + */ + private String remark; + + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/storagevehicleinfo/StorageVehicleInfoDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/storagevehicleinfo/StorageVehicleInfoDO.java new file mode 100644 index 00000000..267d7d63 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/storagevehicleinfo/StorageVehicleInfoDO.java @@ -0,0 +1,85 @@ +package cn.code.nl.module.wms.dal.dataobject.storagevehicleinfo; + +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 载具信息 DO + * + * @author 诺力管理员 + */ +@TableName("wms_storage_vehicle_info") +@KeySequence("wms_storage_vehicle_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class StorageVehicleInfoDO extends BaseDO { + + /** + * 载具标识 + */ + @TableId + private Long storageVehicleId; + /** + * 载具编码 + */ + private String storageVehicleCode; + /** + * 载具名称 + */ + private String storageVehicleName; + /** + * 一维码 + */ + private String oneCode; + /** + * 二维码 + */ + private String twoCode; + /** + * 是否启用 + */ + private Boolean isUsed; + /** + * 载具类型 + */ + private String storageVehicleType; + /** + * 载具宽度 + */ + private Integer vehicleWidth; + /** + * 载具长度 + */ + private Integer vehicleLong; + /** + * 载具高度 + */ + private Integer vehicleHeight; + /** + * 托盘重量 + */ + private BigDecimal weigth; + /** + * 载具是否超仓位 + */ + private String overStructType; + /** + * 占仓位数 + */ + private Integer occupyStructQty; + /** + * 外部标识 + */ + private String extId; + + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/structAttr/StrucAttrDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/structAttr/StrucAttrDO.java new file mode 100644 index 00000000..6d21b914 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/structAttr/StrucAttrDO.java @@ -0,0 +1,176 @@ +package cn.code.nl.module.wms.dal.dataobject.structAttr; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 仓位属性 DO + * + * @author 诺力管理员 + */ +@TableName("wms_structattr") +@KeySequence("wms_structattr_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class StrucAttrDO extends BaseDO { + + /** + * 仓位标识 + */ + @TableId + private String structId; + /** + * 仓位编码 + */ + private String structCode; + /** + * 仓位名称 + */ + private String structName; + /** + * 仓位简称 + */ + private String simpleName; + /** + * 库区标识 + */ + private String sectId; + /** + * 库区编码 + */ + private String sectCode; + /** + * 库区名称 + */ + private String sectName; + /** + * 仓库标识 + */ + private String storId; + /** + * 仓库编码 + */ + private String storCode; + /** + * 仓库名称 + */ + private String storName; + /** + * 仓库类型 + */ + private String storType; + /** + * 容量 + */ + private Integer capacity; + /** + * 宽度 + */ + private Integer width; + /** + * 高度 + */ + private Integer height; + /** + * 深度 + */ + private Integer zdepth; + /** + * 承受重量 + */ + private Integer weight; + /** + * 起始X坐标 + */ + private Integer xqty; + /** + * 起始Y坐标 + */ + private Integer yqty; + /** + * 起始Z坐标 + */ + private Integer zqty; + /** + * 是否临时仓位 + */ + private String isTempstruct; + /** + * 排 + */ + private Integer rowNum; + /** + * 列 + */ + private Integer colNum; + /** + * 层 + */ + private Integer layerNum; + /** + * 块 + */ + private Integer blockNum; + /** + * 放置类型 + */ + private String placementType; + /** + * 是否启用 + */ + private Boolean isUsed; + /** + * 是否判断高度 + */ + private String isZdepth; + /** + * 存储载具号 + */ + private String storagevehicleCode; + /** + * 载具类型 + */ + private String storagevehicleType; + /** + * 载具数量 + */ + private Integer storagevehicleQty; + /** + * 锁定类型 + */ + private String lockType; + /** + * 锁定任务编码 + */ + private String taskCode; + /** + * 锁定单据类型 + */ + private String invType; + /** + * 锁定单据标识 + */ + private String invId; + /** + * 锁定单据编码 + */ + private String invCode; + /** + * 外部标识 + */ + private String extId; + /** + * 备注 + */ + private String remark; + + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/warehousestrategy/WarehouseStrategyDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/warehousestrategy/WarehouseStrategyDO.java new file mode 100644 index 00000000..4aeebf02 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/warehousestrategy/WarehouseStrategyDO.java @@ -0,0 +1,48 @@ +package cn.code.nl.module.wms.dal.dataobject.warehousestrategy; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 出入库策略 DO + * + * @author 诺力管理员 + */ +@TableName("wms_warehouse_strategy") +@KeySequence("wms_warehouse_strategy_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WarehouseStrategyDO extends BaseDO { + + /** + * id + */ + @TableId + private Long id; + /** + * 库区编码 + */ + private String sectionCode; + /** + * 规则 + */ + private String strategy; + /** + * 策略类型 + */ + private String strategyType; + /** + * 描述 + */ + private String description; + + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/warehousestrategyconfig/WarehouseStrategyConfigDO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/warehousestrategyconfig/WarehouseStrategyConfigDO.java new file mode 100644 index 00000000..a360572c --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/dataobject/warehousestrategyconfig/WarehouseStrategyConfigDO.java @@ -0,0 +1,67 @@ +package cn.code.nl.module.wms.dal.dataobject.warehousestrategyconfig; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 仓储策略配置 DO + * + * @author 诺力管理员 + */ +@TableName("wms_warehouse_strategy_config") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WarehouseStrategyConfigDO extends BaseDO { + + /** + * 策略标识 + */ + @TableId + private Long id; + /** + * 策略编码 + */ + private String strategyCode; + /** + * 策略名称 + */ + private String strategyName; + /** + * 策略类型 + */ + private String strategyType; + /** + * 类处理类型 + */ + private String classType; + /** + * 参数 + */ + private String param; + /** + * 描述 + */ + private String remark; + /** + * 是否启用 + */ + private Boolean isUsed; + /** + * 禁止操作 + */ + private Boolean ban; + /** + * 限定参数 + */ + private String formData; + + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/groupplate/GroupPlateMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/groupplate/GroupPlateMapper.java new file mode 100644 index 00000000..d2501627 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/groupplate/GroupPlateMapper.java @@ -0,0 +1,40 @@ +package cn.code.nl.module.wms.dal.mysql.groupplate; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.groupplate.GroupPlateDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.groupplate.vo.*; + +/** + * 组盘记录 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface GroupPlateMapper extends BaseMapperX { + + default PageResult selectPage(GroupPlatePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(GroupPlateDO::getVehicleCode, reqVO.getVehicleCode()) + .eqIfPresent(GroupPlateDO::getStatus, reqVO.getStatus()) + .eqIfPresent(GroupPlateDO::getMaterialId, reqVO.getMaterialId()) + .eqIfPresent(GroupPlateDO::getPcsn, reqVO.getPcsn()) + .eqIfPresent(GroupPlateDO::getQty, reqVO.getQty()) + .eqIfPresent(GroupPlateDO::getFrozenQty, reqVO.getFrozenQty()) + .eqIfPresent(GroupPlateDO::getQtyUnitId, reqVO.getQtyUnitId()) + .likeIfPresent(GroupPlateDO::getQtyUnitName, reqVO.getQtyUnitName()) + .eqIfPresent(GroupPlateDO::getRemark, reqVO.getRemark()) + .eqIfPresent(GroupPlateDO::getExtCode, reqVO.getExtCode()) + .eqIfPresent(GroupPlateDO::getExtType, reqVO.getExtType()) + .eqIfPresent(GroupPlateDO::getExtDtlCode, reqVO.getExtDtlCode()) + .eqIfPresent(GroupPlateDO::getMd5, reqVO.getMd5()) + .eqIfPresent(GroupPlateDO::getMaterialCode, reqVO.getMaterialCode()) + .betweenIfPresent(GroupPlateDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(GroupPlateDO::getGroupId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinv/IostorInvMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinv/IostorInvMapper.java new file mode 100644 index 00000000..cc9d17ac --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinv/IostorInvMapper.java @@ -0,0 +1,47 @@ +package cn.code.nl.module.wms.dal.mysql.iostorinv; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.iostorinv.IostorInvDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.*; + +/** + * 出入库单主表 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface IostorInvMapper extends BaseMapperX { + + default PageResult selectPage(IostorInvPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IostorInvDO::getBillCode, reqVO.getBillCode()) + .eqIfPresent(IostorInvDO::getBillType, reqVO.getBillType()) + .betweenIfPresent(IostorInvDO::getBizDate, reqVO.getBizDate()) + .eqIfPresent(IostorInvDO::getStorId, reqVO.getStorId()) + .likeIfPresent(IostorInvDO::getSourceName, reqVO.getSourceName()) + .eqIfPresent(IostorInvDO::getSourceType, reqVO.getSourceType()) + .eqIfPresent(IostorInvDO::getTotalQty, reqVO.getTotalQty()) + .eqIfPresent(IostorInvDO::getTotalWeight, reqVO.getTotalWeight()) + .eqIfPresent(IostorInvDO::getDetailCount, reqVO.getDetailCount()) + .eqIfPresent(IostorInvDO::getBillStatus, reqVO.getBillStatus()) + .eqIfPresent(IostorInvDO::getRemark, reqVO.getRemark()) + .eqIfPresent(IostorInvDO::getCreateMode, reqVO.getCreateMode()) + .betweenIfPresent(IostorInvDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(IostorInvDO::getDisOptid, reqVO.getDisOptid()) + .betweenIfPresent(IostorInvDO::getDisTime, reqVO.getDisTime()) + .eqIfPresent(IostorInvDO::getConfirmOptid, reqVO.getConfirmOptid()) + .betweenIfPresent(IostorInvDO::getConfirmTime, reqVO.getConfirmTime()) + .eqIfPresent(IostorInvDO::getSysdeptid, reqVO.getSysdeptid()) + .eqIfPresent(IostorInvDO::getSyscompanyid, reqVO.getSyscompanyid()) + .eqIfPresent(IostorInvDO::getIsUpload, reqVO.getIsUpload()) + .eqIfPresent(IostorInvDO::getUploadOptid, reqVO.getUploadOptid()) + .betweenIfPresent(IostorInvDO::getUploadTime, reqVO.getUploadTime()) + .orderByDesc(IostorInvDO::getIostorinvId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinvdis/IostorinvDisMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinvdis/IostorinvDisMapper.java new file mode 100644 index 00000000..c33e6c85 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinvdis/IostorinvDisMapper.java @@ -0,0 +1,47 @@ +package cn.code.nl.module.wms.dal.mysql.iostorinvdis; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdis.IostorinvDisDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.iostorinvdis.vo.*; + +/** + * 出入库单分配 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface IostorinvDisMapper extends BaseMapperX { + + default PageResult selectPage(IostorinvDisPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IostorinvDisDO::getIostorinvId, reqVO.getIostorinvId()) + .eqIfPresent(IostorinvDisDO::getIostorinvdtlId, reqVO.getIostorinvdtlId()) + .eqIfPresent(IostorinvDisDO::getSeqNo, reqVO.getSeqNo()) + .eqIfPresent(IostorinvDisDO::getSectId, reqVO.getSectId()) + .eqIfPresent(IostorinvDisDO::getSectCode, reqVO.getSectCode()) + .likeIfPresent(IostorinvDisDO::getSectName, reqVO.getSectName()) + .eqIfPresent(IostorinvDisDO::getStructId, reqVO.getStructId()) + .eqIfPresent(IostorinvDisDO::getStructCode, reqVO.getStructCode()) + .likeIfPresent(IostorinvDisDO::getStructName, reqVO.getStructName()) + .eqIfPresent(IostorinvDisDO::getMaterialId, reqVO.getMaterialId()) + .eqIfPresent(IostorinvDisDO::getMaterialCode, reqVO.getMaterialCode()) + .eqIfPresent(IostorinvDisDO::getPcsn, reqVO.getPcsn()) + .eqIfPresent(IostorinvDisDO::getWorkStatus, reqVO.getWorkStatus()) + .eqIfPresent(IostorinvDisDO::getTaskId, reqVO.getTaskId()) + .eqIfPresent(IostorinvDisDO::getStoragevehicleCode, reqVO.getStoragevehicleCode()) + .eqIfPresent(IostorinvDisDO::getIsIssued, reqVO.getIsIssued()) + .eqIfPresent(IostorinvDisDO::getQtyUnitId, reqVO.getQtyUnitId()) + .likeIfPresent(IostorinvDisDO::getQtyUnitName, reqVO.getQtyUnitName()) + .eqIfPresent(IostorinvDisDO::getPlanQty, reqVO.getPlanQty()) + .eqIfPresent(IostorinvDisDO::getRealQty, reqVO.getRealQty()) + .eqIfPresent(IostorinvDisDO::getPointCode, reqVO.getPointCode()) + .eqIfPresent(IostorinvDisDO::getHandType, reqVO.getHandType()) + .orderByDesc(IostorinvDisDO::getIostorinvdisId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinvdtl/IostorinvDtlMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinvdtl/IostorinvDtlMapper.java new file mode 100644 index 00000000..61324e0e --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/iostorinvdtl/IostorinvDtlMapper.java @@ -0,0 +1,73 @@ +package cn.code.nl.module.wms.dal.mysql.iostorinvdtl; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.util.MyBatisUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdtl.IostorinvDtlDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryPageReqVO; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryRespVO; +import cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo.*; + +/** + * 出入库单明细 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface IostorinvDtlMapper extends BaseMapperX { + + /** + * 分页查询指定仓库的可用库存。 + */ + default PageResult selectAvailableInventoryPage(AvailableInventoryPageReqVO reqVO) { + Page page = selectAvailableInventoryPage( + MyBatisUtils.buildPage(reqVO), reqVO); + return new PageResult<>(page.getRecords(), page.getTotal()); + } + + /** + * 执行可用库存分页 SQL。 + */ + Page selectAvailableInventoryPage( + Page page, @Param("reqVO") AvailableInventoryPageReqVO reqVO); + + /** + * 查询指定仓库、指定箱号下的全部可用子卷。 + */ + List selectAvailableInventoryByVehicleCodes( + @Param("storId") String storId, @Param("vehicleCodes") Collection vehicleCodes); + + /** 保存前重查并锁定指定仓库、箱号下的全部可用组盘行。 */ + List selectAvailableInventoryByVehicleCodesForUpdate( + @Param("storId") String storId, @Param("vehicleCodes") Collection vehicleCodes); + + default PageResult selectPage(IostorinvDtlPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IostorinvDtlDO::getIostorinvId, reqVO.getIostorinvId()) + .eqIfPresent(IostorinvDtlDO::getSeqNo, reqVO.getSeqNo()) + .eqIfPresent(IostorinvDtlDO::getPcsn, reqVO.getPcsn()) + .eqIfPresent(IostorinvDtlDO::getBillStatus, reqVO.getBillStatus()) + .eqIfPresent(IostorinvDtlDO::getQtyUnitId, reqVO.getQtyUnitId()) + .eqIfPresent(IostorinvDtlDO::getPlanQty, reqVO.getPlanQty()) + .eqIfPresent(IostorinvDtlDO::getRealQty, reqVO.getRealQty()) + .eqIfPresent(IostorinvDtlDO::getSourceBilldtlId, reqVO.getSourceBilldtlId()) + .eqIfPresent(IostorinvDtlDO::getSourceBillType, reqVO.getSourceBillType()) + .eqIfPresent(IostorinvDtlDO::getSourceBillCode, reqVO.getSourceBillCode()) + .eqIfPresent(IostorinvDtlDO::getSourceBillTable, reqVO.getSourceBillTable()) + .eqIfPresent(IostorinvDtlDO::getRemark, reqVO.getRemark()) + .eqIfPresent(IostorinvDtlDO::getAssignQty, reqVO.getAssignQty()) + .eqIfPresent(IostorinvDtlDO::getUnassignQty, reqVO.getUnassignQty()) + .eqIfPresent(IostorinvDtlDO::getMaterialCode, reqVO.getMaterialCode()) + .eqIfPresent(IostorinvDtlDO::getSourceLoadPort, reqVO.getSourceLoadPort()) + .eqIfPresent(IostorinvDtlDO::getCallbackStrategy, reqVO.getCallbackStrategy()) + .eqIfPresent(IostorinvDtlDO::getMaterialId, reqVO.getMaterialId()) + .orderByDesc(IostorinvDtlDO::getIostorinvdtlId)); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/sectattr/SectAttrMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/sectattr/SectAttrMapper.java new file mode 100644 index 00000000..5e4487a1 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/sectattr/SectAttrMapper.java @@ -0,0 +1,31 @@ +package cn.code.nl.module.wms.dal.mysql.sectattr; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.sectattr.SectAttrDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.sectattr.vo.*; + +/** + * 库区属性 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface SectAttrMapper extends BaseMapperX { + + default PageResult selectPage(SectAttrPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(SectAttrDO::getSectCode, reqVO.getSectCode()) + .likeIfPresent(SectAttrDO::getSectName, reqVO.getSectName()) + .eqIfPresent(SectAttrDO::getSectTypeAttr, reqVO.getSectTypeAttr()) + .eqIfPresent(SectAttrDO::getStorId, reqVO.getStorId()) + .betweenIfPresent(SectAttrDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(SectAttrDO::getIsUsed, reqVO.getIsUsed()) + .orderByDesc(SectAttrDO::getSectId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/storagevehicleext/StorageVehicleExtMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/storagevehicleext/StorageVehicleExtMapper.java new file mode 100644 index 00000000..7824a198 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/storagevehicleext/StorageVehicleExtMapper.java @@ -0,0 +1,31 @@ +package cn.code.nl.module.wms.dal.mysql.storagevehicleext; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.storagevehicleext.StorageVehicleExtDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.storagevehicleext.vo.*; + +/** + * 载具扩展属性信息 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface StorageVehicleExtMapper extends BaseMapperX { + + default PageResult selectPage(StorageVehicleExtPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(StorageVehicleExtDO::getStorageVehicleCode, reqVO.getStorageVehicleCode()) + .eqIfPresent(StorageVehicleExtDO::getStorageVehicleType, reqVO.getStorageVehicleType()) + .eqIfPresent(StorageVehicleExtDO::getMaterialId, reqVO.getMaterialId()) + .eqIfPresent(StorageVehicleExtDO::getPcsn, reqVO.getPcsn()) + .eqIfPresent(StorageVehicleExtDO::getBoxNo, reqVO.getBoxNo()) + .betweenIfPresent(StorageVehicleExtDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(StorageVehicleExtDO::getStorageVehicleExtId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/storagevehicleinfo/StorageVehicleInfoMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/storagevehicleinfo/StorageVehicleInfoMapper.java new file mode 100644 index 00000000..c9621c15 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/storagevehicleinfo/StorageVehicleInfoMapper.java @@ -0,0 +1,38 @@ +package cn.code.nl.module.wms.dal.mysql.storagevehicleinfo; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.storagevehicleinfo.StorageVehicleInfoDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.storagevehicleinfo.vo.*; + +/** + * 载具信息 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface StorageVehicleInfoMapper extends BaseMapperX { + + default PageResult selectPage(StorageVehicleInfoPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(StorageVehicleInfoDO::getStorageVehicleCode, reqVO.getStorageVehicleCode()) + .likeIfPresent(StorageVehicleInfoDO::getStorageVehicleName, reqVO.getStorageVehicleName()) + .eqIfPresent(StorageVehicleInfoDO::getOneCode, reqVO.getOneCode()) + .eqIfPresent(StorageVehicleInfoDO::getTwoCode, reqVO.getTwoCode()) + .eqIfPresent(StorageVehicleInfoDO::getIsUsed, reqVO.getIsUsed()) + .eqIfPresent(StorageVehicleInfoDO::getStorageVehicleType, reqVO.getStorageVehicleType()) + .eqIfPresent(StorageVehicleInfoDO::getVehicleWidth, reqVO.getVehicleWidth()) + .eqIfPresent(StorageVehicleInfoDO::getVehicleLong, reqVO.getVehicleLong()) + .eqIfPresent(StorageVehicleInfoDO::getVehicleHeight, reqVO.getVehicleHeight()) + .eqIfPresent(StorageVehicleInfoDO::getWeigth, reqVO.getWeigth()) + .eqIfPresent(StorageVehicleInfoDO::getOverStructType, reqVO.getOverStructType()) + .eqIfPresent(StorageVehicleInfoDO::getOccupyStructQty, reqVO.getOccupyStructQty()) + .betweenIfPresent(StorageVehicleInfoDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(StorageVehicleInfoDO::getStorageVehicleId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/structAttr/StrucAttrMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/structAttr/StrucAttrMapper.java new file mode 100644 index 00000000..f6078029 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/structAttr/StrucAttrMapper.java @@ -0,0 +1,62 @@ +package cn.code.nl.module.wms.dal.mysql.structAttr; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.structAttr.StrucAttrDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.structAttr.vo.*; + +/** + * 仓位属性 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface StrucAttrMapper extends BaseMapperX { + + default PageResult selectPage(StrucAttrPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(StrucAttrDO::getStructCode, reqVO.getStructCode()) + .likeIfPresent(StrucAttrDO::getStructName, reqVO.getStructName()) + .likeIfPresent(StrucAttrDO::getSimpleName, reqVO.getSimpleName()) + .eqIfPresent(StrucAttrDO::getSectId, reqVO.getSectId()) + .eqIfPresent(StrucAttrDO::getSectCode, reqVO.getSectCode()) + .likeIfPresent(StrucAttrDO::getSectName, reqVO.getSectName()) + .eqIfPresent(StrucAttrDO::getStorId, reqVO.getStorId()) + .eqIfPresent(StrucAttrDO::getStorCode, reqVO.getStorCode()) + .likeIfPresent(StrucAttrDO::getStorName, reqVO.getStorName()) + .eqIfPresent(StrucAttrDO::getStorType, reqVO.getStorType()) + .eqIfPresent(StrucAttrDO::getCapacity, reqVO.getCapacity()) + .eqIfPresent(StrucAttrDO::getWidth, reqVO.getWidth()) + .eqIfPresent(StrucAttrDO::getHeight, reqVO.getHeight()) + .eqIfPresent(StrucAttrDO::getZdepth, reqVO.getZdepth()) + .eqIfPresent(StrucAttrDO::getWeight, reqVO.getWeight()) + .eqIfPresent(StrucAttrDO::getXqty, reqVO.getXqty()) + .eqIfPresent(StrucAttrDO::getYqty, reqVO.getYqty()) + .eqIfPresent(StrucAttrDO::getZqty, reqVO.getZqty()) + .eqIfPresent(StrucAttrDO::getIsTempstruct, reqVO.getIsTempstruct()) + .eqIfPresent(StrucAttrDO::getRowNum, reqVO.getRowNum()) + .eqIfPresent(StrucAttrDO::getColNum, reqVO.getColNum()) + .eqIfPresent(StrucAttrDO::getLayerNum, reqVO.getLayerNum()) + .eqIfPresent(StrucAttrDO::getBlockNum, reqVO.getBlockNum()) + .eqIfPresent(StrucAttrDO::getPlacementType, reqVO.getPlacementType()) + .betweenIfPresent(StrucAttrDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(StrucAttrDO::getIsUsed, reqVO.getIsUsed()) + .eqIfPresent(StrucAttrDO::getIsZdepth, reqVO.getIsZdepth()) + .eqIfPresent(StrucAttrDO::getStoragevehicleCode, reqVO.getStoragevehicleCode()) + .eqIfPresent(StrucAttrDO::getStoragevehicleType, reqVO.getStoragevehicleType()) + .eqIfPresent(StrucAttrDO::getStoragevehicleQty, reqVO.getStoragevehicleQty()) + .eqIfPresent(StrucAttrDO::getLockType, reqVO.getLockType()) + .eqIfPresent(StrucAttrDO::getTaskCode, reqVO.getTaskCode()) + .eqIfPresent(StrucAttrDO::getInvType, reqVO.getInvType()) + .eqIfPresent(StrucAttrDO::getInvId, reqVO.getInvId()) + .eqIfPresent(StrucAttrDO::getInvCode, reqVO.getInvCode()) + .eqIfPresent(StrucAttrDO::getExtId, reqVO.getExtId()) + .eqIfPresent(StrucAttrDO::getRemark, reqVO.getRemark()) + .orderByDesc(StrucAttrDO::getStructId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/warehousestrategy/WarehouseStrategyMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/warehousestrategy/WarehouseStrategyMapper.java new file mode 100644 index 00000000..1136d163 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/warehousestrategy/WarehouseStrategyMapper.java @@ -0,0 +1,29 @@ +package cn.code.nl.module.wms.dal.mysql.warehousestrategy; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategy.WarehouseStrategyDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.warehousestrategy.vo.*; + +/** + * 出入库策略 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface WarehouseStrategyMapper extends BaseMapperX { + + default PageResult selectPage(WarehouseStrategyPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(WarehouseStrategyDO::getSectionCode, reqVO.getSectionCode()) + .eqIfPresent(WarehouseStrategyDO::getStrategy, reqVO.getStrategy()) + .eqIfPresent(WarehouseStrategyDO::getStrategyType, reqVO.getStrategyType()) + .betweenIfPresent(WarehouseStrategyDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(WarehouseStrategyDO::getId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/warehousestrategyconfig/WarehouseStrategyConfigMapper.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/warehousestrategyconfig/WarehouseStrategyConfigMapper.java new file mode 100644 index 00000000..61666e49 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/dal/mysql/warehousestrategyconfig/WarehouseStrategyConfigMapper.java @@ -0,0 +1,41 @@ +package cn.code.nl.module.wms.dal.mysql.warehousestrategyconfig; + +import java.util.*; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategyconfig.WarehouseStrategyConfigDO; +import org.apache.ibatis.annotations.Mapper; +import cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo.*; + +/** + * 仓储策略配置 Mapper + * + * @author 诺力管理员 + */ +@Mapper +public interface WarehouseStrategyConfigMapper extends BaseMapperX { + + default List selectList() { + return selectList(new LambdaQueryWrapperX() + .eq(WarehouseStrategyConfigDO::getIsUsed, true) + .orderByDesc(WarehouseStrategyConfigDO::getId)); + } + + default PageResult selectPage(WarehouseStrategyConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(WarehouseStrategyConfigDO::getStrategyCode, reqVO.getStrategyCode()) + .likeIfPresent(WarehouseStrategyConfigDO::getStrategyName, reqVO.getStrategyName()) + .eqIfPresent(WarehouseStrategyConfigDO::getStrategyType, reqVO.getStrategyType()) + .eqIfPresent(WarehouseStrategyConfigDO::getClassType, reqVO.getClassType()) + .eqIfPresent(WarehouseStrategyConfigDO::getParam, reqVO.getParam()) + .eqIfPresent(WarehouseStrategyConfigDO::getRemark, reqVO.getRemark()) + .eqIfPresent(WarehouseStrategyConfigDO::getIsUsed, reqVO.getIsUsed()) + .eqIfPresent(WarehouseStrategyConfigDO::getBan, reqVO.getBan()) + .eqIfPresent(WarehouseStrategyConfigDO::getFormData, reqVO.getFormData()) + .betweenIfPresent(WarehouseStrategyConfigDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(WarehouseStrategyConfigDO::getId)); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/enums/StrategyTypeEnum.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/enums/StrategyTypeEnum.java new file mode 100644 index 00000000..2bd7cd81 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/enums/StrategyTypeEnum.java @@ -0,0 +1,23 @@ +package cn.code.nl.module.wms.enums; + +import lombok.Getter; + +/** + * + * @Author: liyongde + * @Date: 2026/7/18 14:15 + */ +@Getter +public enum StrategyTypeEnum { + + INBOUND_STRATEGY("1", "入库策略"), + OUTBOUND_STRATEGY("2", "出库策略"); + + private final String code; + private final String name; + + StrategyTypeEnum(String code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/rpc/config/RpcConfiguration.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/rpc/config/RpcConfiguration.java new file mode 100644 index 00000000..8ef36bd0 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/rpc/config/RpcConfiguration.java @@ -0,0 +1,15 @@ +package cn.code.nl.module.wms.framework.rpc.config; + +import cn.code.nl.module.base.api.codegen.CodeGenApi; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Configuration; + +/** + * + * @Author: liyongde + * @Date: 2026/7/22 13:50 + */ +@Configuration(value = "wmsRpcConfiguration", proxyBeanMethods = false) +@EnableFeignClients(clients = {CodeGenApi.class}) +public class RpcConfiguration { +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/security/config/SecurityConfiguration.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/security/config/SecurityConfiguration.java index 20c30302..aa9fa217 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/security/config/SecurityConfiguration.java +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/framework/security/config/SecurityConfiguration.java @@ -11,7 +11,7 @@ import org.springframework.security.config.annotation.web.configurers.AuthorizeH * * @author zhouz */ -@Configuration(proxyBeanMethods = false, value = "baseSecurityConfiguration") +@Configuration(proxyBeanMethods = false, value = "wmsSecurityConfiguration") public class SecurityConfiguration { /* @@ -93,7 +93,7 @@ public class SecurityConfiguration { 3. 遵循了项目中每个模块定义各自安全配置的标准模式 * */ - @Bean("baseAuthorizeRequestsCustomizer") + @Bean("wmsAuthorizeRequestsCustomizer") public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { return new AuthorizeRequestsCustomizer() { diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/DecisionManage.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/DecisionManage.java new file mode 100644 index 00000000..3b64a7dd --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/DecisionManage.java @@ -0,0 +1,72 @@ +package cn.code.nl.module.wms.manage; + +import cn.code.nl.framework.common.exception.ServiceException; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategyconfig.WarehouseStrategyConfigDO; +import cn.code.nl.module.wms.dal.mysql.warehousestrategyconfig.WarehouseStrategyConfigMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.jspecify.annotations.NonNull; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; + +import java.util.List; + +/** + * 仓储策略决策器抽象基类 + *

+ * 子类通过 {@code @Service("策略编码")} 注册为 Spring Bean, + * 启动时根据 Bean 名称自动从数据库加载对应的策略配置。 + * + * @param 返回类型:货位/库存数据类型 + * @param

入参类型:决策参数类型 + * @Author: liyongde + * @Date: 2026/7/18 11:03 + */ +@Slf4j +public abstract class DecisionManage implements InitializingBean, BeanNameAware { + + /** + * 当前策略的数据库配置,子类通过此字段读取策略参数 + */ + public WarehouseStrategyConfigDO strategyConfig; + + /** + * Spring Bean 名称,即策略编码,对应 {@link WarehouseStrategyConfigDO#getStrategyCode()} + */ + private String beanName; + + @Resource + private WarehouseStrategyConfigMapper warehouseStrategyConfigMapper; + + /** + * 策略执行入口,由子类实现具体的货位分配逻辑 + * + * @param list 候选货位/库存列表 + * @param param 决策参数(物料信息、出入库类型等) + * @return 筛选/排序后的货位/库存列表 + */ + public abstract List handler(List list, P param); + + @Override + public void setBeanName(@NonNull String name) { + this.beanName = name; + } + + /** + * Spring Bean 初始化时自动加载策略配置 + *

+ * 通过 BeanNameAware 获取策略编码,从数据库查询对应的策略配置记录。 + * 若数据库中无对应记录则抛出异常阻止启动,避免运行时才发现配置缺失。 + */ + @Override + public void afterPropertiesSet() { + this.strategyConfig = warehouseStrategyConfigMapper.selectOne( + WarehouseStrategyConfigDO::getStrategyCode, beanName); + if (this.strategyConfig == null) { + log.error("策略 [{}] 初始化失败:数据库中未找到对应的策略配置记录", beanName); + throw new ServiceException(500, "启动失败:当前策略 " + beanName + " 没有实例信息"); + } + log.info("策略 [{}] 初始化成功,策略名称:{}", beanName, strategyConfig.getStrategyName()); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/StrategyChainExecutor.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/StrategyChainExecutor.java new file mode 100644 index 00000000..fcc0d0c9 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/StrategyChainExecutor.java @@ -0,0 +1,91 @@ +package cn.code.nl.module.wms.manage; + +import cn.code.nl.framework.common.exception.ServiceException; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategy.WarehouseStrategyDO; +import cn.code.nl.module.wms.dal.mysql.warehousestrategy.WarehouseStrategyMapper; +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSON; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 策略链执行器 + *

+ * 根据库区编码和策略类型加载策略链配置,从 Spring 容器中按名称精确获取策略处理器, + * 按序执行,每个处理器的输出作为下一个处理器的输入。 + * + * @Author: liyongde + * @Date: 2026/7/18 + */ +@Slf4j +@Component +public class StrategyChainExecutor { + + @Resource + private WarehouseStrategyMapper warehouseStrategyMapper; + + @Resource + private ApplicationContext applicationContext; + + /** + * 执行策略链 + * + * @param sectionCode 库区编码 + * @param strategyType 策略类型(1=入库,2=出库) + * @param candidates 初始候选列表,入库时为可用货位列表,出库时传空列表由首个策略自行查询 + * @param param 决策参数,类型由调用方决定(入库通常传 JSONObject,出库通常传强类型实体) + * @param 货位/库存数据类型 + * @param

决策参数类型,需与策略链中所有处理器的泛型参数一致 + * @return 策略链执行后的结果列表 + */ + @SuppressWarnings("unchecked") + public List execute(String sectionCode, String strategyType, List candidates, P param) { + // 1. 查询库区策略链配置 + WarehouseStrategyDO strategy = warehouseStrategyMapper.selectOne( + WarehouseStrategyDO::getSectionCode, sectionCode, + WarehouseStrategyDO::getStrategyType, strategyType); + if (strategy == null) { + throw new ServiceException(500, "当前库区 " + sectionCode + " 未配置策略链"); + } + + // 2. 解析策略编码列表 + List strategyCodes = JSON.parseArray(strategy.getStrategy(), String.class); + if (CollUtil.isEmpty(strategyCodes)) { + throw new ServiceException(500, "当前库区 " + sectionCode + " 策略链为空"); + } + + // 3. 按序执行策略链 + List result = candidates; + for (String strategyCode : strategyCodes) { + DecisionManage handler; + try { + handler = (DecisionManage) applicationContext.getBean(strategyCode); + } catch (Exception e) { + log.error("策略 [{}] 未找到对应的处理器 Bean", strategyCode, e); + throw new ServiceException(500, "策略 " + strategyCode + " 未注册"); + } + + String strategyName = handler.strategyConfig.getStrategyName(); + int inputSize = result != null ? result.size() : 0; + log.info("执行策略 [{}]:{},输入候选数量:{}", strategyCode, strategyName, inputSize); + + long startTime = System.currentTimeMillis(); + result = handler.handler(result, param); + long cost = System.currentTimeMillis() - startTime; + + int outputSize = result != null ? result.size() : 0; + log.info("策略 [{}] 执行完成,耗时:{}ms,输出数量:{}(过滤:{})", + strategyCode, cost, outputSize, inputSize - outputSize); + + if (CollUtil.isEmpty(result)) { + throw new ServiceException(500, "策略 " + strategyName + " 执行后无可用货位"); + } + } + return result; + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/AlleyAveHandleDTO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/AlleyAveHandleDTO.java new file mode 100644 index 00000000..0b1b3354 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/AlleyAveHandleDTO.java @@ -0,0 +1,216 @@ +package cn.code.nl.module.wms.manage.dto; + +import lombok.Data; + +/** + * alleyAve规则 + * @Author: liyongde + * @Date: 2026/7/18 14:12 + */ +@Data +public class AlleyAveHandleDTO { + private String id; + + /** 仓位编码 */ + private String structCode; + + /** + * 仓位名称 + */ + private String structName; + + /** + * 仓位简称 + */ + private String simpleName; + + /** + * 库区标识 + */ + private String sectId; + + /** + * 库区编码 + */ + private String sectCode; + + /** + * 库区名称 + */ + private String sectName; + + /** + * 仓库标识 + */ + private String storId; + + /** + * 仓库编码 + */ + private String storCode; + + /** + * 仓库名称 + */ + private String storName; + + /** + * 仓库类型 + */ + private String storType; + + /** + * 容量 + */ + private Integer capacity; + + /** + * 宽度 + */ + private Integer width; + + /** + * 高度 + */ + private Integer height; + + /** + * 深度 + */ + private Integer zdepth; + + /** + * 承受重量 + */ + private Integer weight; + + /** + * 起始X坐标 + */ + private Integer xqty; + + /** + * 起始Y坐标 + */ + private Integer yqty; + + /** + * 起始Z坐标 + */ + private Integer zqty; + + /** + * 是否临时仓位 + */ + private String isTempstruct; + + /** + * 排 + */ + private Integer rowNum; + + /** + * 列 + */ + private Integer colNum; + + /** + * 层 + */ + private Integer layerNum; + + /** + * 块 + */ + private Integer blockNum; + + /** + * 创建人 + */ + private String createId; + + /** + * 创建人姓名 + */ + private String createName; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 修改人 + */ + private String updateId; + + /** + * 修改人姓名 + */ + private String updateName; + + /** + * 修改时间 + */ + private String updateTime; + + /** + * 是否启用 + */ + private Boolean isUsed; + + /** + * 是否判断高度 + */ + private String isZdepth; + + /** + * 存储载具号 + */ + private String storageVehicleCode; + + /** + * 存储载具类型 + */ + private String storageVehicleType; + + /** + * 载具数量 + */ + private Integer storageVehicleQty; + + /** + * 锁定类型 + */ + private String lockType; + + /** + * 锁定任务编码 + */ + private String taskCode; + + /** + * 锁定单据类型 + */ + private String invType; + + /** + * 锁定单据标识 + */ + private String invId; + + /** + * 锁定单据编码 + */ + private String invCode; + + /** + * 外部标识 + */ + private String extId; + + /** + * 备注 + */ + private String remark; +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/AlleyAveHandleParam.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/AlleyAveHandleParam.java new file mode 100644 index 00000000..000b1b7d --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/AlleyAveHandleParam.java @@ -0,0 +1,14 @@ +package cn.code.nl.module.wms.manage.dto; + +import lombok.Data; + +/** + * + * @Author: liyongde + * @Date: 2026/7/18 14:12 + */ +@Data +public class AlleyAveHandleParam { + // 载具号 + private String vehicleCode; +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/StrategyStructParam.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/StrategyStructParam.java new file mode 100644 index 00000000..b8d1962f --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/dto/StrategyStructParam.java @@ -0,0 +1,75 @@ +package cn.code.nl.module.wms.manage.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 先入先出参数 + * @Author: liyongde + * @Date: 2026/7/20 16:38 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class StrategyStructParam { + /* + *库区,暂时不用 + */ + private String sectCode; + /** + * 同步单号 + */ + private String extCode; + /** + * 分配的单号 + */ + private String invCode; + /** + * 来源单据类型 + */ + private String extType; + + /** + * 出入库类型 + */ + private String ioType; + /** + * 载具编码 + */ + private String storageVehicleCode; + + /** + * 载具明细:混料的话则是数组 + */ + private List strategyMaters; + + @Data + public static class StrategyMater { + /** + * 物料标识 + */ + private String materialCode; + /** + * id + */ + private String materialId; + /** + * 批次 + */ + private String pcsn; + /** + * 计量单位标识 + */ + private String qtyUnitId; + /** + * 组盘数量 + */ + private BigDecimal qty; + } +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/AlleyAveRuleHandler.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/AlleyAveRuleHandler.java new file mode 100644 index 00000000..38797ccd --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/AlleyAveRuleHandler.java @@ -0,0 +1,57 @@ +package cn.code.nl.module.wms.manage.handle.base; + +import cn.code.nl.framework.common.exception.util.ServiceExceptionUtil; +import cn.code.nl.module.wms.dal.dataobject.structAttr.StrucAttrDO; +import cn.code.nl.module.wms.enums.ErrorCodeConstants; +import cn.code.nl.module.wms.manage.DecisionManage; +import cn.code.nl.module.wms.manage.dto.AlleyAveHandleParam; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @Author: liyongde + * @Date: 2026/7/18 13:39 + */ +@Slf4j +@Service("alleyAve") +public class AlleyAveRuleHandler extends DecisionManage { + @Override + public List handler(List list, AlleyAveHandleParam param) { + // 判断仓位是否为空 + if (CollectionUtils.isEmpty(list)) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.ALLEY_AVE_NO_AVAILABLE_LOCATION, param.getVehicleCode()); + } + /** + * 根据XYZ进行均衡排序:排层列 + */ + String configParam = this.strategyConfig.getParam(); + List configList = JSONObject.parseArray(configParam, String.class); + list.sort((o1, o2) -> { + Integer rowNum1 = o1.getRowNum(); + Integer colNum1 = o1.getColNum(); + Integer layerNum1 = o1.getLayerNum(); + Integer rowNum2 = o2.getRowNum(); + Integer colNum2 = o2.getColNum(); + Integer layerNum2 = o2.getLayerNum(); + HashMap of1 = new HashMap<>(Map.of("x", rowNum1, "y", colNum1, "z", layerNum1)); + HashMap of2 = new HashMap<>(Map.of("x", rowNum2, "y", colNum2, "z", layerNum2)); + for (String sort : configList) { + if (of1.get(sort) > of2.get(sort)) { + return 1; + } + if (of1.get(sort) < of2.get(sort)) { + return -1; + } + } + return 0; + }); + return list.subList(0, Math.min(list.size(), 10)); + } +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/ClusterRuleHandler.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/ClusterRuleHandler.java new file mode 100644 index 00000000..23c8e111 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/ClusterRuleHandler.java @@ -0,0 +1,22 @@ +package cn.code.nl.module.wms.manage.handle.base; + +import cn.code.nl.module.wms.dal.dataobject.structAttr.StrucAttrDO; +import cn.code.nl.module.wms.manage.DecisionManage; +import com.alibaba.fastjson.JSONObject; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * + * @Author: liyongde + * @Date: 2026/7/20 16:44 + */ +@Service("cluster") +public class ClusterRuleHandler extends DecisionManage { + + @Override + public List handler(List list, JSONObject param) { + return List.of(); + } +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/FIFORuleHandler.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/FIFORuleHandler.java new file mode 100644 index 00000000..a0652be1 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/base/FIFORuleHandler.java @@ -0,0 +1,25 @@ +package cn.code.nl.module.wms.manage.handle.base; + +import cn.code.nl.module.wms.dal.dataobject.structAttr.StrucAttrDO; +import cn.code.nl.module.wms.manage.DecisionManage; +import cn.code.nl.module.wms.manage.dto.StrategyStructParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 先进先出策略 + * @Author: liyongde + * @Date: 2026/7/20 16:23 + */ +@Service("fifo") +@Slf4j +public class FIFORuleHandler extends DecisionManage { + + @Override + public List handler(List list, StrategyStructParam param) { + return list; + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/package-info.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/package-info.java new file mode 100644 index 00000000..44ddb5b7 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/manage/handle/package-info.java @@ -0,0 +1,6 @@ +/** + * 所有出入库的处理器 + * @Author: liyongde + * @Date: 2026/7/18 14:11 + */ +package cn.code.nl.module.wms.manage.handle; \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/mq/consumer/WmsTaskStatusChangeConsumer.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/mq/consumer/WmsTaskStatusChangeConsumer.java new file mode 100644 index 00000000..0c41724a --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/mq/consumer/WmsTaskStatusChangeConsumer.java @@ -0,0 +1,118 @@ +package cn.code.nl.module.wms.mq.consumer; + +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.execute.core.AbstractTask; +import cn.code.nl.framework.execute.core.TaskFactory; +import cn.code.nl.framework.execute.core.dto.TaskExecuteDTO; +import cn.code.nl.module.task.api.TransportTaskApi; +import cn.code.nl.module.task.dto.TaskInfoDTO; +import cn.code.nl.module.task.enums.TransportTaskStatusEnum; +import cn.code.nl.module.task.message.TaskEventMessage; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Component; + +import static cn.code.nl.module.task.message.LockKeyConstants.TASK_STATUS_CHANGE_LOCK_KEY; + +/** + * 监听任务状态变更,根据 handleCode 定位任务子类并执行完成/取消逻辑 + * + * @Author: liyongde + * @Date: 2026/7/20 10:28 + */ +@Slf4j +@Component +@RocketMQMessageListener( + topic = "${rocketmq.consumer.wms-task-operate.topic}", + consumerGroup = "${rocketmq.consumer.wms-task-operate.group}" +) +public class WmsTaskStatusChangeConsumer implements RocketMQListener { + + @Resource + private TaskFactory taskFactory; + + @Resource + private TransportTaskApi transportTaskApi; + + @Resource + private RedissonClient redissonClient; + + @Override + public void onMessage(TaskEventMessage message) { + String handleCode = message.getHandleCode(); + String eventType = message.getEventType(); + log.info("收到任务状态变更消息, handleCode={}, eventType={}, taskId={}", handleCode, eventType, message.getTaskId()); + + RLock lock = redissonClient.getLock(TASK_STATUS_CHANGE_LOCK_KEY + message.getTaskId()); + if (!lock.tryLock()) { + log.warn("任务状态变更消息正在消费中,等待 MQ 重试, taskId={}, eventType={}", message.getTaskId(), eventType); + throw new IllegalStateException("任务状态变更消息正在消费中......"); + } + try { + if (!isTaskCallbackPending(message)) { + return; + } + executeTaskHandler(message, handleCode, eventType); + } finally { + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + } + + /** + * 判断任务是否处于当前事件对应的待业务处理状态 + */ + private boolean isTaskCallbackPending(TaskEventMessage message) { + String eventType = message.getEventType(); + String expectedStatus; + if (TaskEventMessage.EVENT_TYPE_FINISHED.equals(eventType)) { + expectedStatus = TransportTaskStatusEnum.FINISHED_CALLBACK_PENDING.getCode(); + } else if (TaskEventMessage.EVENT_TYPE_CANCELLED.equals(eventType)) { + expectedStatus = TransportTaskStatusEnum.CANCEL_CALLBACK_PENDING.getCode(); + } else { + log.warn("未知任务事件类型, eventType={}, taskId={}", eventType, message.getTaskId()); + return false; + } + + CommonResult result = transportTaskApi.getTaskById(message.getTaskId()); + TaskInfoDTO taskInfo = result.getCheckedData(); + if (taskInfo == null) { + log.warn("任务不存在,跳过任务状态变更消息, taskId={}, eventType={}", message.getTaskId(), eventType); + return false; + } + if (!expectedStatus.equals(taskInfo.getTaskStatus())) { + log.info("任务状态已处理,跳过重复消息, taskId={}, eventType={}, currentStatus={}, expectedStatus={}", + message.getTaskId(), eventType, taskInfo.getTaskStatus(), expectedStatus); + return false; + } + return true; + } + + /** + * 执行任务完成或取消业务处理器 + */ + private void executeTaskHandler(TaskEventMessage message, String handleCode, String eventType) { + AbstractTask task = taskFactory.getTask(handleCode); + if (task == null) { + log.warn("未找到对应任务处理器, handleCode={}", handleCode); + return; + } + + TaskExecuteDTO dto = new TaskExecuteDTO(); + dto.setTaskId(message.getTaskId()); + dto.setPayload(message.getPayload()); + + if (TaskEventMessage.EVENT_TYPE_FINISHED.equals(eventType)) { + task.doHandleFinish(dto); + } else if (TaskEventMessage.EVENT_TYPE_CANCELLED.equals(eventType)) { + task.doHandleCancel(dto); + } else { + log.warn("未知事件类型, eventType={}, handleCode={}", eventType, handleCode); + } + } +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/mq/package-info.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/mq/package-info.java new file mode 100644 index 00000000..2ed129a3 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/mq/package-info.java @@ -0,0 +1,6 @@ +/** + * 消息队列 + * @Author: liyongde + * @Date: 2026/7/20 10:26 + */ +package cn.code.nl.module.wms.mq; \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/bsrealstorattr/BsrealStorAttrService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/bsrealstorattr/BsrealStorAttrService.java index 43023e4d..dabf2073 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/bsrealstorattr/BsrealStorAttrService.java +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/bsrealstorattr/BsrealStorAttrService.java @@ -59,4 +59,11 @@ public interface BsrealStorAttrService { */ PageResult getBsrealStorAttrPage(BsrealStorAttrPageReqVO pageReqVO); + /** + * 获得启用的实物库属性精简列表 + * + * @return 实物库属性列表 + */ + List getBsrealStorAttrSimpleList(); + } \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/bsrealstorattr/BsrealStorAttrServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/bsrealstorattr/BsrealStorAttrServiceImpl.java index 13b92577..ca858077 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/bsrealstorattr/BsrealStorAttrServiceImpl.java +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/bsrealstorattr/BsrealStorAttrServiceImpl.java @@ -14,6 +14,7 @@ import cn.code.nl.framework.common.pojo.PageParam; import cn.code.nl.framework.common.util.object.BeanUtils; import cn.code.nl.module.wms.dal.mysql.bsrealstorattr.BsrealStorAttrMapper; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList; @@ -82,4 +83,11 @@ public class BsrealStorAttrServiceImpl implements BsrealStorAttrService { return bsrealStorAttrMapper.selectPage(pageReqVO); } + @Override + public List getBsrealStorAttrSimpleList() { + return bsrealStorAttrMapper.selectList(new LambdaQueryWrapperX() + .eq(BsrealStorAttrDO::getIsUsed, "1") + .orderByAsc(BsrealStorAttrDO::getStorId)); + } + } \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/groupplate/GroupPlateService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/groupplate/GroupPlateService.java new file mode 100644 index 00000000..83a9918b --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/groupplate/GroupPlateService.java @@ -0,0 +1,62 @@ +package cn.code.nl.module.wms.service.groupplate; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.groupplate.vo.*; +import cn.code.nl.module.wms.dal.dataobject.groupplate.GroupPlateDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 组盘记录 Service 接口 + * + * @author 诺力管理员 + */ +public interface GroupPlateService { + + /** + * 创建组盘记录 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createGroupPlate(@Valid GroupPlateSaveReqVO createReqVO); + + /** + * 更新组盘记录 + * + * @param updateReqVO 更新信息 + */ + void updateGroupPlate(@Valid GroupPlateSaveReqVO updateReqVO); + + /** + * 删除组盘记录 + * + * @param id 编号 + */ + void deleteGroupPlate(String id); + + /** + * 批量删除组盘记录 + * + * @param ids 编号 + */ + void deleteGroupPlateListByIds(List ids); + + /** + * 获得组盘记录 + * + * @param id 编号 + * @return 组盘记录 + */ + GroupPlateDO getGroupPlate(String id); + + /** + * 获得组盘记录分页 + * + * @param pageReqVO 分页查询 + * @return 组盘记录分页 + */ + PageResult getGroupPlatePage(GroupPlatePageReqVO pageReqVO); + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/groupplate/GroupPlateServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/groupplate/GroupPlateServiceImpl.java new file mode 100644 index 00000000..88fa1077 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/groupplate/GroupPlateServiceImpl.java @@ -0,0 +1,88 @@ +package cn.code.nl.module.wms.service.groupplate; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import cn.code.nl.framework.security.core.util.SecurityFrameworkUtils; +import cn.code.nl.module.wms.controller.admin.groupplate.vo.GroupPlatePageReqVO; +import cn.code.nl.module.wms.controller.admin.groupplate.vo.GroupPlateSaveReqVO; +import cn.code.nl.module.wms.dal.dataobject.groupplate.GroupPlateDO; +import cn.code.nl.module.wms.dal.mysql.groupplate.GroupPlateMapper; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.starter.annotation.LogRecord; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.module.system.enums.LogRecordConstants.*; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.GROUP_PLATE_NOT_EXISTS; + +/** + * 组盘记录 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class GroupPlateServiceImpl implements GroupPlateService { + + @Resource + private GroupPlateMapper groupPlateMapper; + + @Override + public Long createGroupPlate(GroupPlateSaveReqVO createReqVO) { + // 插入 + GroupPlateDO groupPlate = BeanUtils.toBean(createReqVO, GroupPlateDO.class); + groupPlateMapper.insert(groupPlate); + + // 返回 + return groupPlate.getGroupId(); + } + + @Override + @LogRecord(type = WMS_GROUP_PLATE, subType = WMS_GROUP_PLATE_UPDATE, bizNo = "{{#updateReqVO.groupId}}", + success = WMS_GROUP_PLATE_SUCCESS) + public void updateGroupPlate(GroupPlateSaveReqVO updateReqVO) { + // 校验存在 + validateGroupPlateExists(updateReqVO.getGroupId()); + // 更新 + GroupPlateDO updateObj = BeanUtils.toBean(updateReqVO, GroupPlateDO.class); + groupPlateMapper.updateById(updateObj); + LogRecordContext.putVariable("loginUserNickname", SecurityFrameworkUtils.getLoginUserNickname()); + LogRecordContext.putVariable("group", updateObj); + } + + @Override + public void deleteGroupPlate(String id) { + // 校验存在 + validateGroupPlateExists(id); + // 删除 + groupPlateMapper.deleteById(id); + } + + @Override + public void deleteGroupPlateListByIds(List ids) { + // 删除 + groupPlateMapper.deleteByIds(ids); + } + + + private void validateGroupPlateExists(String id) { + if (groupPlateMapper.selectById(id) == null) { + throw exception(GROUP_PLATE_NOT_EXISTS); + } + } + + @Override + public GroupPlateDO getGroupPlate(String id) { + return groupPlateMapper.selectById(id); + } + + @Override + public PageResult getGroupPlatePage(GroupPlatePageReqVO pageReqVO) { + return groupPlateMapper.selectPage(pageReqVO); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvService.java new file mode 100644 index 00000000..c2acd718 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvService.java @@ -0,0 +1,86 @@ +package cn.code.nl.module.wms.service.iostorinv; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinv.IostorInvDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 出入库单主表 Service 接口 + * + * @author 诺力管理员 + */ +public interface IostorInvService { + + /** + * 创建出库单 + * + * @param reqVO 出库单创建信息 + * @return 出库单编号 + */ + Long createOutbound(@Valid IostorInvCreateReqVO reqVO); + + /** + * 获得指定仓库的可用库存分页。 + * + * @param reqVO 分页查询条件 + * @return 可用库存分页 + */ + PageResult getAvailableInventoryPage(@Valid AvailableInventoryPageReqVO reqVO); + + /** + * 按箱号展开指定仓库中的全部可用子卷。 + * + * @param reqVO 展开条件 + * @return 可用子卷列表 + */ + List expandAvailableInventory(@Valid ExpandAvailableInventoryReqVO reqVO); + + /** + * 创建出入库单主表 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createIostorInv(@Valid IostorInvSaveReqVO createReqVO); + + /** + * 更新出入库单主表 + * + * @param updateReqVO 更新信息 + */ + void updateIostorInv(@Valid IostorInvSaveReqVO updateReqVO); + + /** + * 删除出入库单主表 + * + * @param id 编号 + */ + void deleteIostorInv(String id); + + /** + * 批量删除出入库单主表 + * + * @param ids 编号 + */ + void deleteIostorInvListByIds(List ids); + + /** + * 获得出入库单主表 + * + * @param id 编号 + * @return 出入库单主表 + */ + IostorInvDO getIostorInv(String id); + + /** + * 获得出入库单主表分页 + * + * @param pageReqVO 分页查询 + * @return 出入库单主表分页 + */ + PageResult getIostorInvPage(IostorInvPageReqVO pageReqVO); + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceImpl.java new file mode 100644 index 00000000..e25d6bd0 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceImpl.java @@ -0,0 +1,225 @@ +package cn.code.nl.module.wms.service.iostorinv; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.module.base.api.codegen.CodeGenApi; +import cn.code.nl.module.base.api.codegen.dto.CodeGenerateReqDTO; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdtl.IostorinvDtlDO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.*; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinv.IostorInvDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.util.object.BeanUtils; + +import cn.code.nl.module.wms.dal.mysql.iostorinv.IostorInvMapper; +import cn.code.nl.module.wms.dal.mysql.iostorinvdtl.IostorinvDtlMapper; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.diffList; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.*; + +/** + * 出入库单主表 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +@Slf4j +public class IostorInvServiceImpl implements IostorInvService { + + @Resource + private IostorInvMapper iostorInvMapper; + + @Resource + private IostorinvDtlMapper iostorinvDtlMapper; + + @Resource + private CodeGenApi codeGenApi; + + /** + * 创建出库单及其明细。 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long createOutbound(IostorInvCreateReqVO reqVO) { + Map inventorySnapshot = validateAndLockInventory(reqVO); + + String ruleCode = "IO_CODE"; + CodeGenerateReqDTO codeGenerateReqDTO = new CodeGenerateReqDTO(); + codeGenerateReqDTO.setRuleCode(ruleCode); + CommonResult codeResult; + try { + codeResult = codeGenApi.generate(codeGenerateReqDTO); + } catch (RuntimeException ex) { + log.error("[createOutbound][生成出库单号异常,规则编码:{}]", ruleCode, ex); + // 当前统一业务异常不支持 cause,远程异常堆栈已在此处完整记录。 + throw exception(IOSTOR_INV_CODE_GENERATE_FAILED); + } + if (codeResult == null || !codeResult.isSuccess() || StrUtil.isBlank(codeResult.getData())) { + String remoteMessage = codeResult == null ? "返回结果为空" : codeResult.getMsg(); + log.error("[createOutbound][生成出库单号失败,规则编码:{},远程信息:{}]", ruleCode, remoteMessage); + throw exception(IOSTOR_INV_CODE_GENERATE_FAILED); + } + + BigDecimal totalWeight = reqVO.getDetails().stream() + .map(IostorInvCreateReqVO.Detail::getPlanQty) + .reduce(BigDecimal.ZERO, BigDecimal::add); + IostorInvDO iostorInv = new IostorInvDO(); + iostorInv.setBillCode(codeResult.getData()); + iostorInv.setIoType("1"); + iostorInv.setBillType(reqVO.getBillType()); + iostorInv.setBizDate(reqVO.getBizDate()); + iostorInv.setStorId(reqVO.getStorId()); + iostorInv.setBillStatus("10"); + iostorInv.setRemark(reqVO.getRemark()); + iostorInv.setDetailCount(reqVO.getDetails().size()); + iostorInv.setTotalWeight(totalWeight); + iostorInvMapper.insert(iostorInv); + + for (int index = 0; index < reqVO.getDetails().size(); index++) { + IostorInvCreateReqVO.Detail detail = reqVO.getDetails().get(index); + IostorinvDtlDO detailDO = new IostorinvDtlDO(); + detailDO.setIostorinvId(iostorInv.getIostorinvId()); + detailDO.setSeqNo(index + 1); + AvailableInventoryRespVO inventory = inventorySnapshot.get(detail.getGroupId()); + detailDO.setMaterialCode(inventory == null ? detail.getMaterialCode() : inventory.getMaterialCode()); + detailDO.setMaterialId(inventory == null ? detail.getMaterialId() : inventory.getMaterialId()); + detailDO.setPcsn(inventory == null ? detail.getPcsn() : inventory.getPcsn()); + detailDO.setPlanQty(detail.getPlanQty()); + detailDO.setUnassignQty(detail.getPlanQty()); + detailDO.setAssignQty(BigDecimal.ZERO); + detailDO.setBillStatus("10"); + detailDO.setQtyUnitId(inventory == null ? detail.getQtyUnitId() : inventory.getQtyUnitId()); + detailDO.setSourceBillCode(inventory == null ? detail.getSourceBillCode() : inventory.getExtCode()); + detailDO.setSourceBillType(inventory == null ? detail.getSourceBillType() : inventory.getExtType()); + detailDO.setSourceBilldtlId(inventory == null ? detail.getSourceBilldtlId() : inventory.getExtDtlCode()); + detailDO.setRemark(detail.getRemark()); + iostorinvDtlMapper.insert(detailDO); + } + return iostorInv.getIostorinvId(); + } + + private Map validateAndLockInventory(IostorInvCreateReqVO reqVO) { + List inventoryDetails = new ArrayList<>(); + Set requestedGroupIds = new HashSet<>(); + Set vehicleCodes = new LinkedHashSet<>(); + for (IostorInvCreateReqVO.Detail detail : reqVO.getDetails()) { + boolean hasGroupId = detail.getGroupId() != null; + boolean hasVehicleCode = StrUtil.isNotBlank(detail.getVehicleCode()); + if (hasGroupId != hasVehicleCode) { + throw exception(IOSTOR_INV_INVENTORY_INVALID); + } + if (!hasGroupId) { + continue; + } + if (!requestedGroupIds.add(detail.getGroupId())) { + throw exception(IOSTOR_INV_INVENTORY_INVALID); + } + inventoryDetails.add(detail); + vehicleCodes.add(detail.getVehicleCode()); + } + if (inventoryDetails.isEmpty()) { + return Collections.emptyMap(); + } + + List lockedRows = + iostorinvDtlMapper.selectAvailableInventoryByVehicleCodesForUpdate(reqVO.getStorId(), vehicleCodes); + Map lockedByGroupId = new HashMap<>(); + for (AvailableInventoryRespVO row : lockedRows) { + if (lockedByGroupId.put(row.getGroupId(), row) != null) { + throw exception(IOSTOR_INV_INVENTORY_INVALID); + } + } + if (!lockedByGroupId.keySet().equals(requestedGroupIds)) { + throw exception(IOSTOR_INV_INVENTORY_INVALID); + } + for (IostorInvCreateReqVO.Detail detail : inventoryDetails) { + AvailableInventoryRespVO row = lockedByGroupId.get(detail.getGroupId()); + if (!Objects.equals(detail.getVehicleCode(), row.getVehicleCode()) + || !Objects.equals(detail.getMaterialId(), row.getMaterialId()) + || !Objects.equals(detail.getMaterialCode(), row.getMaterialCode()) + || !Objects.equals(detail.getPcsn(), row.getPcsn()) + || detail.getPlanQty() == null || detail.getPlanQty().signum() <= 0 + || detail.getPlanQty().compareTo(row.getAvailableQty()) > 0) { + throw exception(IOSTOR_INV_INVENTORY_INVALID); + } + } + // 建单仅验证库存快照;库存占用和冻结数量由后续分配流程处理。 + return lockedByGroupId; + } + + @Override + public PageResult getAvailableInventoryPage(AvailableInventoryPageReqVO reqVO) { + return iostorinvDtlMapper.selectAvailableInventoryPage(reqVO); + } + + @Override + public List expandAvailableInventory(ExpandAvailableInventoryReqVO reqVO) { + // 用户可以独立勾选子卷;按涉及箱号去重后,由数据库展开箱内全部可用子卷。 + Set vehicleCodes = new LinkedHashSet<>(reqVO.getVehicleCodes()); + return iostorinvDtlMapper.selectAvailableInventoryByVehicleCodes(reqVO.getStorId(), vehicleCodes); + } + + @Override + public Long createIostorInv(IostorInvSaveReqVO createReqVO) { + // 插入 + IostorInvDO iostorInv = BeanUtils.toBean(createReqVO, IostorInvDO.class); + iostorInvMapper.insert(iostorInv); + + // 返回 + return iostorInv.getIostorinvId(); + } + + @Override + public void updateIostorInv(IostorInvSaveReqVO updateReqVO) { + // 校验存在 + validateIostorInvExists(updateReqVO.getIostorinvId()); + // 更新 + IostorInvDO updateObj = BeanUtils.toBean(updateReqVO, IostorInvDO.class); + iostorInvMapper.updateById(updateObj); + } + + @Override + public void deleteIostorInv(String id) { + // 校验存在 + validateIostorInvExists(id); + // 删除 + iostorInvMapper.deleteById(id); + } + + @Override + public void deleteIostorInvListByIds(List ids) { + // 删除 + iostorInvMapper.deleteByIds(ids); + } + + + private void validateIostorInvExists(String id) { + if (iostorInvMapper.selectById(id) == null) { + throw exception(IOSTOR_INV_NOT_EXISTS); + } + } + + @Override + public IostorInvDO getIostorInv(String id) { + return iostorInvMapper.selectById(id); + } + + @Override + public PageResult getIostorInvPage(IostorInvPageReqVO pageReqVO) { + return iostorInvMapper.selectPage(pageReqVO); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdis/IostorinvDisService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdis/IostorinvDisService.java new file mode 100644 index 00000000..d6c135c1 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdis/IostorinvDisService.java @@ -0,0 +1,62 @@ +package cn.code.nl.module.wms.service.iostorinvdis; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.iostorinvdis.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdis.IostorinvDisDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 出入库单分配 Service 接口 + * + * @author 诺力管理员 + */ +public interface IostorinvDisService { + + /** + * 创建出入库单分配 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + String createIostorinvDis(@Valid IostorinvDisSaveReqVO createReqVO); + + /** + * 更新出入库单分配 + * + * @param updateReqVO 更新信息 + */ + void updateIostorinvDis(@Valid IostorinvDisSaveReqVO updateReqVO); + + /** + * 删除出入库单分配 + * + * @param id 编号 + */ + void deleteIostorinvDis(String id); + + /** + * 批量删除出入库单分配 + * + * @param ids 编号 + */ + void deleteIostorinvDisListByIds(List ids); + + /** + * 获得出入库单分配 + * + * @param id 编号 + * @return 出入库单分配 + */ + IostorinvDisDO getIostorinvDis(String id); + + /** + * 获得出入库单分配分页 + * + * @param pageReqVO 分页查询 + * @return 出入库单分配分页 + */ + PageResult getIostorinvDisPage(IostorinvDisPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdis/IostorinvDisServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdis/IostorinvDisServiceImpl.java new file mode 100644 index 00000000..272efbc3 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdis/IostorinvDisServiceImpl.java @@ -0,0 +1,85 @@ +package cn.code.nl.module.wms.service.iostorinvdis; + +import cn.hutool.core.collection.CollUtil; +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.code.nl.module.wms.controller.admin.iostorinvdis.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdis.IostorinvDisDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.util.object.BeanUtils; + +import cn.code.nl.module.wms.dal.mysql.iostorinvdis.IostorinvDisMapper; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.diffList; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.*; + +/** + * 出入库单分配 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class IostorinvDisServiceImpl implements IostorinvDisService { + + @Resource + private IostorinvDisMapper iostorinvDisMapper; + + @Override + public String createIostorinvDis(IostorinvDisSaveReqVO createReqVO) { + // 插入 + IostorinvDisDO iostorinvDis = BeanUtils.toBean(createReqVO, IostorinvDisDO.class); + iostorinvDisMapper.insert(iostorinvDis); + + // 返回 + return iostorinvDis.getIostorinvdisId(); + } + + @Override + public void updateIostorinvDis(IostorinvDisSaveReqVO updateReqVO) { + // 校验存在 + validateIostorinvDisExists(updateReqVO.getIostorinvdisId()); + // 更新 + IostorinvDisDO updateObj = BeanUtils.toBean(updateReqVO, IostorinvDisDO.class); + iostorinvDisMapper.updateById(updateObj); + } + + @Override + public void deleteIostorinvDis(String id) { + // 校验存在 + validateIostorinvDisExists(id); + // 删除 + iostorinvDisMapper.deleteById(id); + } + + @Override + public void deleteIostorinvDisListByIds(List ids) { + // 删除 + iostorinvDisMapper.deleteByIds(ids); + } + + + private void validateIostorinvDisExists(String id) { + if (iostorinvDisMapper.selectById(id) == null) { + throw exception(IOSTORINV_DIS_NOT_EXISTS); + } + } + + @Override + public IostorinvDisDO getIostorinvDis(String id) { + return iostorinvDisMapper.selectById(id); + } + + @Override + public PageResult getIostorinvDisPage(IostorinvDisPageReqVO pageReqVO) { + return iostorinvDisMapper.selectPage(pageReqVO); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdtl/IostorinvDtlService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdtl/IostorinvDtlService.java new file mode 100644 index 00000000..21fc23f0 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdtl/IostorinvDtlService.java @@ -0,0 +1,62 @@ +package cn.code.nl.module.wms.service.iostorinvdtl; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdtl.IostorinvDtlDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 出入库单明细 Service 接口 + * + * @author 诺力管理员 + */ +public interface IostorinvDtlService { + + /** + * 创建出入库单明细 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createIostorinvDtl(@Valid IostorinvDtlSaveReqVO createReqVO); + + /** + * 更新出入库单明细 + * + * @param updateReqVO 更新信息 + */ + void updateIostorinvDtl(@Valid IostorinvDtlSaveReqVO updateReqVO); + + /** + * 删除出入库单明细 + * + * @param id 编号 + */ + void deleteIostorinvDtl(String id); + + /** + * 批量删除出入库单明细 + * + * @param ids 编号 + */ + void deleteIostorinvDtlListByIds(List ids); + + /** + * 获得出入库单明细 + * + * @param id 编号 + * @return 出入库单明细 + */ + IostorinvDtlDO getIostorinvDtl(String id); + + /** + * 获得出入库单明细分页 + * + * @param pageReqVO 分页查询 + * @return 出入库单明细分页 + */ + PageResult getIostorinvDtlPage(IostorinvDtlPageReqVO pageReqVO); + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdtl/IostorinvDtlServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdtl/IostorinvDtlServiceImpl.java new file mode 100644 index 00000000..e50c722e --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/iostorinvdtl/IostorinvDtlServiceImpl.java @@ -0,0 +1,85 @@ +package cn.code.nl.module.wms.service.iostorinvdtl; + +import cn.hutool.core.collection.CollUtil; +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo.*; +import cn.code.nl.module.wms.dal.dataobject.iostorinvdtl.IostorinvDtlDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.util.object.BeanUtils; + +import cn.code.nl.module.wms.dal.mysql.iostorinvdtl.IostorinvDtlMapper; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.diffList; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.*; + +/** + * 出入库单明细 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class IostorinvDtlServiceImpl implements IostorinvDtlService { + + @Resource + private IostorinvDtlMapper iostorinvDtlMapper; + + @Override + public Long createIostorinvDtl(IostorinvDtlSaveReqVO createReqVO) { + // 插入 + IostorinvDtlDO iostorinvDtl = BeanUtils.toBean(createReqVO, IostorinvDtlDO.class); + iostorinvDtlMapper.insert(iostorinvDtl); + + // 返回 + return iostorinvDtl.getIostorinvdtlId(); + } + + @Override + public void updateIostorinvDtl(IostorinvDtlSaveReqVO updateReqVO) { + // 校验存在 + validateIostorinvDtlExists(updateReqVO.getIostorinvdtlId()); + // 更新 + IostorinvDtlDO updateObj = BeanUtils.toBean(updateReqVO, IostorinvDtlDO.class); + iostorinvDtlMapper.updateById(updateObj); + } + + @Override + public void deleteIostorinvDtl(String id) { + // 校验存在 + validateIostorinvDtlExists(id); + // 删除 + iostorinvDtlMapper.deleteById(id); + } + + @Override + public void deleteIostorinvDtlListByIds(List ids) { + // 删除 + iostorinvDtlMapper.deleteByIds(ids); + } + + + private void validateIostorinvDtlExists(String id) { + if (iostorinvDtlMapper.selectById(id) == null) { + throw exception(IOSTORINV_DTL_NOT_EXISTS); + } + } + + @Override + public IostorinvDtlDO getIostorinvDtl(String id) { + return iostorinvDtlMapper.selectById(id); + } + + @Override + public PageResult getIostorinvDtlPage(IostorinvDtlPageReqVO pageReqVO) { + return iostorinvDtlMapper.selectPage(pageReqVO); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/sectattr/SectAttrService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/sectattr/SectAttrService.java new file mode 100644 index 00000000..77c042e5 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/sectattr/SectAttrService.java @@ -0,0 +1,70 @@ +package cn.code.nl.module.wms.service.sectattr; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.sectattr.vo.*; +import cn.code.nl.module.wms.dal.dataobject.sectattr.SectAttrDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 库区属性 Service 接口 + * + * @author 诺力管理员 + */ +public interface SectAttrService { + + /** + * 创建库区属性 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + String createSectAttr(@Valid SectAttrSaveReqVO createReqVO); + + /** + * 更新库区属性 + * + * @param updateReqVO 更新信息 + */ + void updateSectAttr(@Valid SectAttrSaveReqVO updateReqVO); + + /** + * 删除库区属性 + * + * @param id 编号 + */ + void deleteSectAttr(String id); + + /** + * 批量删除库区属性 + * + * @param ids 编号 + */ + void deleteSectAttrListByIds(List ids); + + /** + * 获得库区属性 + * + * @param id 编号 + * @return 库区属性 + */ + SectAttrDO getSectAttr(String id); + + /** + * 获得库区属性分页 + * + * @param pageReqVO 分页查询 + * @return 库区属性分页 + */ + PageResult getSectAttrPage(SectAttrPageReqVO pageReqVO); + + /** + * 获得启用的库区属性精简列表 + * + * @param storId 仓库标识,可选 + * @return 库区属性列表 + */ + List getSectAttrSimpleList(String storId); + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/sectattr/SectAttrServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/sectattr/SectAttrServiceImpl.java new file mode 100644 index 00000000..871eab89 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/sectattr/SectAttrServiceImpl.java @@ -0,0 +1,92 @@ +package cn.code.nl.module.wms.service.sectattr; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.code.nl.module.wms.controller.admin.sectattr.vo.SectAttrPageReqVO; +import cn.code.nl.module.wms.controller.admin.sectattr.vo.SectAttrSaveReqVO; +import cn.code.nl.module.wms.dal.dataobject.sectattr.SectAttrDO; +import cn.code.nl.module.wms.dal.mysql.sectattr.SectAttrMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.SECT_ATTR_NOT_EXISTS; + +/** + * 库区属性 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class SectAttrServiceImpl implements SectAttrService { + + @Resource + private SectAttrMapper sectAttrMapper; + + @Override + public String createSectAttr(SectAttrSaveReqVO createReqVO) { + // 插入 + SectAttrDO sectAttr = BeanUtils.toBean(createReqVO, SectAttrDO.class); + sectAttrMapper.insert(sectAttr); + + // 返回 + return sectAttr.getSectId(); + } + + @Override + public void updateSectAttr(SectAttrSaveReqVO updateReqVO) { + // 校验存在 + validateSectAttrExists(updateReqVO.getSectId()); + // 更新 + SectAttrDO updateObj = BeanUtils.toBean(updateReqVO, SectAttrDO.class); + sectAttrMapper.updateById(updateObj); + } + + @Override + public void deleteSectAttr(String id) { + // 校验存在 + validateSectAttrExists(id); + // 删除 + sectAttrMapper.deleteById(id); + } + + @Override + public void deleteSectAttrListByIds(List ids) { + // 删除 + sectAttrMapper.deleteByIds(ids); + } + + + private void validateSectAttrExists(String id) { + if (sectAttrMapper.selectById(id) == null) { + throw exception(SECT_ATTR_NOT_EXISTS); + } + } + + @Override + public SectAttrDO getSectAttr(String id) { + return sectAttrMapper.selectById(id); + } + + @Override + public PageResult getSectAttrPage(SectAttrPageReqVO pageReqVO) { + return sectAttrMapper.selectPage(pageReqVO); + } + + @Override + public List getSectAttrSimpleList(String storId) { + LambdaQueryWrapperX wrapper = new LambdaQueryWrapperX() + .eq(SectAttrDO::getIsUsed, "1") + .orderByAsc(SectAttrDO::getSectId); + if (storId != null && !storId.isEmpty()) { + wrapper.eq(SectAttrDO::getStorId, storId); + } + return sectAttrMapper.selectList(wrapper); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleext/StorageVehicleExtService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleext/StorageVehicleExtService.java new file mode 100644 index 00000000..9fe2986c --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleext/StorageVehicleExtService.java @@ -0,0 +1,62 @@ +package cn.code.nl.module.wms.service.storagevehicleext; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.storagevehicleext.vo.*; +import cn.code.nl.module.wms.dal.dataobject.storagevehicleext.StorageVehicleExtDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 载具扩展属性信息 Service 接口 + * + * @author 诺力管理员 + */ +public interface StorageVehicleExtService { + + /** + * 创建载具扩展属性信息 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStorageVehicleExt(@Valid StorageVehicleExtSaveReqVO createReqVO); + + /** + * 更新载具扩展属性信息 + * + * @param updateReqVO 更新信息 + */ + void updateStorageVehicleExt(@Valid StorageVehicleExtSaveReqVO updateReqVO); + + /** + * 删除载具扩展属性信息 + * + * @param id 编号 + */ + void deleteStorageVehicleExt(Long id); + + /** + * 批量删除载具扩展属性信息 + * + * @param ids 编号 + */ + void deleteStorageVehicleExtListByIds(List ids); + + /** + * 获得载具扩展属性信息 + * + * @param id 编号 + * @return 载具扩展属性信息 + */ + StorageVehicleExtDO getStorageVehicleExt(Long id); + + /** + * 获得载具扩展属性信息分页 + * + * @param pageReqVO 分页查询 + * @return 载具扩展属性信息分页 + */ + PageResult getStorageVehicleExtPage(StorageVehicleExtPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleext/StorageVehicleExtServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleext/StorageVehicleExtServiceImpl.java new file mode 100644 index 00000000..38f28153 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleext/StorageVehicleExtServiceImpl.java @@ -0,0 +1,85 @@ +package cn.code.nl.module.wms.service.storagevehicleext; + +import cn.hutool.core.collection.CollUtil; +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.code.nl.module.wms.controller.admin.storagevehicleext.vo.*; +import cn.code.nl.module.wms.dal.dataobject.storagevehicleext.StorageVehicleExtDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.util.object.BeanUtils; + +import cn.code.nl.module.wms.dal.mysql.storagevehicleext.StorageVehicleExtMapper; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.diffList; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.*; + +/** + * 载具扩展属性信息 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class StorageVehicleExtServiceImpl implements StorageVehicleExtService { + + @Resource + private StorageVehicleExtMapper storageVehicleExtMapper; + + @Override + public Long createStorageVehicleExt(StorageVehicleExtSaveReqVO createReqVO) { + // 插入 + StorageVehicleExtDO storageVehicleExt = BeanUtils.toBean(createReqVO, StorageVehicleExtDO.class); + storageVehicleExtMapper.insert(storageVehicleExt); + + // 返回 + return storageVehicleExt.getStorageVehicleExtId(); + } + + @Override + public void updateStorageVehicleExt(StorageVehicleExtSaveReqVO updateReqVO) { + // 校验存在 + validateStorageVehicleExtExists(updateReqVO.getStorageVehicleExtId()); + // 更新 + StorageVehicleExtDO updateObj = BeanUtils.toBean(updateReqVO, StorageVehicleExtDO.class); + storageVehicleExtMapper.updateById(updateObj); + } + + @Override + public void deleteStorageVehicleExt(Long id) { + // 校验存在 + validateStorageVehicleExtExists(id); + // 删除 + storageVehicleExtMapper.deleteById(id); + } + + @Override + public void deleteStorageVehicleExtListByIds(List ids) { + // 删除 + storageVehicleExtMapper.deleteByIds(ids); + } + + + private void validateStorageVehicleExtExists(Long id) { + if (storageVehicleExtMapper.selectById(id) == null) { + throw exception(STORAGE_VEHICLE_EXT_NOT_EXISTS); + } + } + + @Override + public StorageVehicleExtDO getStorageVehicleExt(Long id) { + return storageVehicleExtMapper.selectById(id); + } + + @Override + public PageResult getStorageVehicleExtPage(StorageVehicleExtPageReqVO pageReqVO) { + return storageVehicleExtMapper.selectPage(pageReqVO); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleinfo/StorageVehicleInfoService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleinfo/StorageVehicleInfoService.java new file mode 100644 index 00000000..6912abaa --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleinfo/StorageVehicleInfoService.java @@ -0,0 +1,71 @@ +package cn.code.nl.module.wms.service.storagevehicleinfo; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.storagevehicleinfo.vo.*; +import cn.code.nl.module.wms.dal.dataobject.storagevehicleinfo.StorageVehicleInfoDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.pojo.CommonResult; + +/** + * 载具信息 Service 接口 + * + * @author 诺力管理员 + */ +public interface StorageVehicleInfoService { + + /** + * 创建载具信息 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStorageVehicleInfo(@Valid StorageVehicleInfoSaveReqVO createReqVO); + + /** + * 更新载具信息 + * + * @param updateReqVO 更新信息 + */ + void updateStorageVehicleInfo(@Valid StorageVehicleInfoSaveReqVO updateReqVO); + + /** + * 删除载具信息 + * + * @param id 编号 + */ + void deleteStorageVehicleInfo(Long id); + + /** + * 批量删除载具信息 + * + * @param ids 编号 + */ + void deleteStorageVehicleInfoListByIds(List ids); + + /** + * 获得载具信息 + * + * @param id 编号 + * @return 载具信息 + */ + StorageVehicleInfoDO getStorageVehicleInfo(Long id); + + /** + * 获得载具信息分页 + * + * @param pageReqVO 分页查询 + * @return 载具信息分页 + */ + PageResult getStorageVehicleInfoPage(StorageVehicleInfoPageReqVO pageReqVO); + + /** + * 批量生成载具信息 + * + * @param reqVO 批量生成请求 + * @return 生成的载具ID列表 + */ + List batchCreateStorageVehicleInfo(StorageVehicleInfoBatchCreateReqVO reqVO); + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleinfo/StorageVehicleInfoServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleinfo/StorageVehicleInfoServiceImpl.java new file mode 100644 index 00000000..b7bbac83 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/storagevehicleinfo/StorageVehicleInfoServiceImpl.java @@ -0,0 +1,123 @@ +package cn.code.nl.module.wms.service.storagevehicleinfo; + +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.module.base.api.codegen.CodeGenApi; +import cn.code.nl.module.base.api.codegen.dto.CodeGenerateReqDTO; +import cn.hutool.core.collection.CollUtil; +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.regex.*; +import cn.code.nl.module.wms.controller.admin.storagevehicleinfo.vo.*; +import cn.code.nl.module.wms.dal.dataobject.storagevehicleinfo.StorageVehicleInfoDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.util.object.BeanUtils; + +import cn.code.nl.module.wms.dal.mysql.storagevehicleinfo.StorageVehicleInfoMapper; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.diffList; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.*; + +/** + * 载具信息 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class StorageVehicleInfoServiceImpl implements StorageVehicleInfoService { + + @Resource + private StorageVehicleInfoMapper storageVehicleInfoMapper; + + @Resource + private CodeGenApi codeGenApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStorageVehicleInfo(StorageVehicleInfoSaveReqVO createReqVO) { + // 插入 + StorageVehicleInfoDO storageVehicleInfo = BeanUtils.toBean(createReqVO, StorageVehicleInfoDO.class); + CodeGenerateReqDTO codeGenerateReqDTO = new CodeGenerateReqDTO(); + codeGenerateReqDTO.setRuleCode(createReqVO.getStorageVehicleType() + "_CODE"); + CommonResult generate = codeGenApi.generate(codeGenerateReqDTO); + storageVehicleInfo.setStorageVehicleCode(generate.getData()); + storageVehicleInfoMapper.insert(storageVehicleInfo); + // 返回 + return storageVehicleInfo.getStorageVehicleId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public List batchCreateStorageVehicleInfo(StorageVehicleInfoBatchCreateReqVO reqVO) { + List ids = new ArrayList<>(); + // 提取编码中数字部分的正则 + Pattern numPattern = Pattern.compile("\\d+"); + for (int i = 0; i < reqVO.getCount(); i++) { + CodeGenerateReqDTO genReq = new CodeGenerateReqDTO(); + genReq.setRuleCode(reqVO.getStorageVehicleType() + "_CODE"); + CommonResult result = codeGenApi.generate(genReq); + String code = result.getData(); + // 提取编码中的数字部分 + String numSuffix = ""; + Matcher matcher = numPattern.matcher(code); + if (matcher.find()) { + numSuffix = matcher.group(); + } + StorageVehicleInfoDO info = new StorageVehicleInfoDO(); + info.setStorageVehicleCode(code); + info.setStorageVehicleName(reqVO.getStorageVehicleTypeLabel() + numSuffix); + info.setStorageVehicleType(reqVO.getStorageVehicleType()); + storageVehicleInfoMapper.insert(info); + ids.add(info.getStorageVehicleId()); + } + return ids; + } + + @Override + public void updateStorageVehicleInfo(StorageVehicleInfoSaveReqVO updateReqVO) { + // 校验存在 + validateStorageVehicleInfoExists(updateReqVO.getStorageVehicleId()); + // 更新 + StorageVehicleInfoDO updateObj = BeanUtils.toBean(updateReqVO, StorageVehicleInfoDO.class); + storageVehicleInfoMapper.updateById(updateObj); + } + + @Override + public void deleteStorageVehicleInfo(Long id) { + // 校验存在 + validateStorageVehicleInfoExists(id); + // 删除 + storageVehicleInfoMapper.deleteById(id); + } + + @Override + public void deleteStorageVehicleInfoListByIds(List ids) { + // 删除 + storageVehicleInfoMapper.deleteByIds(ids); + } + + + private void validateStorageVehicleInfoExists(Long id) { + if (storageVehicleInfoMapper.selectById(id) == null) { + throw exception(STORAGE_VEHICLE_INFO_NOT_EXISTS); + } + } + + @Override + public StorageVehicleInfoDO getStorageVehicleInfo(Long id) { + return storageVehicleInfoMapper.selectById(id); + } + + @Override + public PageResult getStorageVehicleInfoPage(StorageVehicleInfoPageReqVO pageReqVO) { + return storageVehicleInfoMapper.selectPage(pageReqVO); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/structAttr/StrucAttrService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/structAttr/StrucAttrService.java new file mode 100644 index 00000000..ae6a1163 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/structAttr/StrucAttrService.java @@ -0,0 +1,62 @@ +package cn.code.nl.module.wms.service.structAttr; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.structAttr.vo.*; +import cn.code.nl.module.wms.dal.dataobject.structAttr.StrucAttrDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 仓位属性 Service 接口 + * + * @author 诺力管理员 + */ +public interface StrucAttrService { + + /** + * 创建仓位属性 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + String createStrucAttr(@Valid StrucAttrSaveReqVO createReqVO); + + /** + * 更新仓位属性 + * + * @param updateReqVO 更新信息 + */ + void updateStrucAttr(@Valid StrucAttrSaveReqVO updateReqVO); + + /** + * 删除仓位属性 + * + * @param id 编号 + */ + void deleteStrucAttr(String id); + + /** + * 批量删除仓位属性 + * + * @param ids 编号 + */ + void deleteStrucAttrListByIds(List ids); + + /** + * 获得仓位属性 + * + * @param id 编号 + * @return 仓位属性 + */ + StrucAttrDO getStrucAttr(String id); + + /** + * 获得仓位属性分页 + * + * @param pageReqVO 分页查询 + * @return 仓位属性分页 + */ + PageResult getStrucAttrPage(StrucAttrPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/structAttr/StrucAttrServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/structAttr/StrucAttrServiceImpl.java new file mode 100644 index 00000000..5e1e1c2d --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/structAttr/StrucAttrServiceImpl.java @@ -0,0 +1,80 @@ +package cn.code.nl.module.wms.service.structAttr; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import cn.code.nl.module.wms.controller.admin.structAttr.vo.StrucAttrPageReqVO; +import cn.code.nl.module.wms.controller.admin.structAttr.vo.StrucAttrSaveReqVO; +import cn.code.nl.module.wms.dal.dataobject.structAttr.StrucAttrDO; +import cn.code.nl.module.wms.dal.mysql.structAttr.StrucAttrMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.STRUC_ATTR_NOT_EXISTS; + +/** + * 仓位属性 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class StrucAttrServiceImpl implements StrucAttrService { + + @Resource + private StrucAttrMapper strucAttrMapper; + + @Override + public String createStrucAttr(StrucAttrSaveReqVO createReqVO) { + // 插入 + StrucAttrDO strucAttr = BeanUtils.toBean(createReqVO, StrucAttrDO.class); + strucAttrMapper.insert(strucAttr); + + // 返回 + return strucAttr.getStructId(); + } + + @Override + public void updateStrucAttr(StrucAttrSaveReqVO updateReqVO) { + // 校验存在 + validateStrucAttrExists(updateReqVO.getStructId()); + // 更新 + StrucAttrDO updateObj = BeanUtils.toBean(updateReqVO, StrucAttrDO.class); + strucAttrMapper.updateById(updateObj); + } + + @Override + public void deleteStrucAttr(String id) { + // 校验存在 + validateStrucAttrExists(id); + // 删除 + strucAttrMapper.deleteById(id); + } + + @Override + public void deleteStrucAttrListByIds(List ids) { + // 删除 + strucAttrMapper.deleteByIds(ids); + } + + + private void validateStrucAttrExists(String id) { + if (strucAttrMapper.selectById(id) == null) { + throw exception(STRUC_ATTR_NOT_EXISTS); + } + } + + @Override + public StrucAttrDO getStrucAttr(String id) { + return strucAttrMapper.selectById(id); + } + + @Override + public PageResult getStrucAttrPage(StrucAttrPageReqVO pageReqVO) { + return strucAttrMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategy/WarehouseStrategyService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategy/WarehouseStrategyService.java new file mode 100644 index 00000000..44c5461c --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategy/WarehouseStrategyService.java @@ -0,0 +1,62 @@ +package cn.code.nl.module.wms.service.warehousestrategy; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.warehousestrategy.vo.*; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategy.WarehouseStrategyDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 出入库策略 Service 接口 + * + * @author 诺力管理员 + */ +public interface WarehouseStrategyService { + + /** + * 创建出入库策略 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createWarehouseStrategy(@Valid WarehouseStrategySaveReqVO createReqVO); + + /** + * 更新出入库策略 + * + * @param updateReqVO 更新信息 + */ + void updateWarehouseStrategy(@Valid WarehouseStrategySaveReqVO updateReqVO); + + /** + * 删除出入库策略 + * + * @param id 编号 + */ + void deleteWarehouseStrategy(Long id); + + /** + * 批量删除出入库策略 + * + * @param ids 编号 + */ + void deleteWarehouseStrategyListByIds(List ids); + + /** + * 获得出入库策略 + * + * @param id 编号 + * @return 出入库策略 + */ + WarehouseStrategyDO getWarehouseStrategy(Long id); + + /** + * 获得出入库策略分页 + * + * @param pageReqVO 分页查询 + * @return 出入库策略分页 + */ + PageResult getWarehouseStrategyPage(WarehouseStrategyPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategy/WarehouseStrategyServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategy/WarehouseStrategyServiceImpl.java new file mode 100644 index 00000000..d18c8d34 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategy/WarehouseStrategyServiceImpl.java @@ -0,0 +1,85 @@ +package cn.code.nl.module.wms.service.warehousestrategy; + +import cn.hutool.core.collection.CollUtil; +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.code.nl.module.wms.controller.admin.warehousestrategy.vo.*; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategy.WarehouseStrategyDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; +import cn.code.nl.framework.common.util.object.BeanUtils; + +import cn.code.nl.module.wms.dal.mysql.warehousestrategy.WarehouseStrategyMapper; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList; +import static cn.code.nl.framework.common.util.collection.CollectionUtils.diffList; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.*; + +/** + * 出入库策略 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class WarehouseStrategyServiceImpl implements WarehouseStrategyService { + + @Resource + private WarehouseStrategyMapper warehouseStrategyMapper; + + @Override + public Long createWarehouseStrategy(WarehouseStrategySaveReqVO createReqVO) { + // 插入 + WarehouseStrategyDO warehouseStrategy = BeanUtils.toBean(createReqVO, WarehouseStrategyDO.class); + warehouseStrategyMapper.insert(warehouseStrategy); + + // 返回 + return warehouseStrategy.getId(); + } + + @Override + public void updateWarehouseStrategy(WarehouseStrategySaveReqVO updateReqVO) { + // 校验存在 + validateWarehouseStrategyExists(updateReqVO.getId()); + // 更新 + WarehouseStrategyDO updateObj = BeanUtils.toBean(updateReqVO, WarehouseStrategyDO.class); + warehouseStrategyMapper.updateById(updateObj); + } + + @Override + public void deleteWarehouseStrategy(Long id) { + // 校验存在 + validateWarehouseStrategyExists(id); + // 删除 + warehouseStrategyMapper.deleteById(id); + } + + @Override + public void deleteWarehouseStrategyListByIds(List ids) { + // 删除 + warehouseStrategyMapper.deleteByIds(ids); + } + + + private void validateWarehouseStrategyExists(Long id) { + if (warehouseStrategyMapper.selectById(id) == null) { + throw exception(WAREHOUSE_STRATEGY_NOT_EXISTS); + } + } + + @Override + public WarehouseStrategyDO getWarehouseStrategy(Long id) { + return warehouseStrategyMapper.selectById(id); + } + + @Override + public PageResult getWarehouseStrategyPage(WarehouseStrategyPageReqVO pageReqVO) { + return warehouseStrategyMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategyconfig/WarehouseStrategyConfigService.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategyconfig/WarehouseStrategyConfigService.java new file mode 100644 index 00000000..e720d0c6 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategyconfig/WarehouseStrategyConfigService.java @@ -0,0 +1,69 @@ +package cn.code.nl.module.wms.service.warehousestrategyconfig; + +import java.util.*; +import jakarta.validation.*; +import cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo.*; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategyconfig.WarehouseStrategyConfigDO; +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.pojo.PageParam; + +/** + * 仓储策略配置 Service 接口 + * + * @author 诺力管理员 + */ +public interface WarehouseStrategyConfigService { + + /** + * 创建仓储策略配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createWarehouseStrategyConfig(@Valid WarehouseStrategyConfigSaveReqVO createReqVO); + + /** + * 更新仓储策略配置 + * + * @param updateReqVO 更新信息 + */ + void updateWarehouseStrategyConfig(@Valid WarehouseStrategyConfigSaveReqVO updateReqVO); + + /** + * 删除仓储策略配置 + * + * @param id 编号 + */ + void deleteWarehouseStrategyConfig(Long id); + + /** + * 批量删除仓储策略配置 + * + * @param ids 编号 + */ + void deleteWarehouseStrategyConfigListByIds(List ids); + + /** + * 获得仓储策略配置 + * + * @param id 编号 + * @return 仓储策略配置 + */ + WarehouseStrategyConfigDO getWarehouseStrategyConfig(Long id); + + /** + * 获得仓储策略配置分页 + * + * @param pageReqVO 分页查询 + * @return 仓储策略配置分页 + */ + PageResult getWarehouseStrategyConfigPage(WarehouseStrategyConfigPageReqVO pageReqVO); + + /** + * 获得仓储策略配置列表(仅启用的) + * + * @return 仓储策略配置列表 + */ + List getWarehouseStrategyConfigList(); + +} \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategyconfig/WarehouseStrategyConfigServiceImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategyconfig/WarehouseStrategyConfigServiceImpl.java new file mode 100644 index 00000000..4d3bf1a8 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/service/warehousestrategyconfig/WarehouseStrategyConfigServiceImpl.java @@ -0,0 +1,85 @@ +package cn.code.nl.module.wms.service.warehousestrategyconfig; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.framework.common.util.object.BeanUtils; +import cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo.WarehouseStrategyConfigPageReqVO; +import cn.code.nl.module.wms.controller.admin.warehousestrategyconfig.vo.WarehouseStrategyConfigSaveReqVO; +import cn.code.nl.module.wms.dal.dataobject.warehousestrategyconfig.WarehouseStrategyConfigDO; +import cn.code.nl.module.wms.dal.mysql.warehousestrategyconfig.WarehouseStrategyConfigMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.WAREHOUSE_STRATEGY_CONFIG_NOT_EXISTS; + +/** + * 仓储策略配置 Service 实现类 + * + * @author 诺力管理员 + */ +@Service +@Validated +public class WarehouseStrategyConfigServiceImpl implements WarehouseStrategyConfigService { + + @Resource + private WarehouseStrategyConfigMapper warehouseStrategyConfigMapper; + + @Override + public Long createWarehouseStrategyConfig(WarehouseStrategyConfigSaveReqVO createReqVO) { + // 插入 + WarehouseStrategyConfigDO warehouseStrategyConfig = BeanUtils.toBean(createReqVO, WarehouseStrategyConfigDO.class); + warehouseStrategyConfigMapper.insert(warehouseStrategyConfig); + + // 返回 + return warehouseStrategyConfig.getId(); + } + + @Override + public void updateWarehouseStrategyConfig(WarehouseStrategyConfigSaveReqVO updateReqVO) { + // 校验存在 + validateWarehouseStrategyConfigExists(updateReqVO.getId()); + // 更新 + WarehouseStrategyConfigDO updateObj = BeanUtils.toBean(updateReqVO, WarehouseStrategyConfigDO.class); + warehouseStrategyConfigMapper.updateById(updateObj); + } + + @Override + public void deleteWarehouseStrategyConfig(Long id) { + // 校验存在 + validateWarehouseStrategyConfigExists(id); + // 删除 + warehouseStrategyConfigMapper.deleteById(id); + } + + @Override + public void deleteWarehouseStrategyConfigListByIds(List ids) { + // 删除 + warehouseStrategyConfigMapper.deleteByIds(ids); + } + + + private void validateWarehouseStrategyConfigExists(Long id) { + if (warehouseStrategyConfigMapper.selectById(id) == null) { + throw exception(WAREHOUSE_STRATEGY_CONFIG_NOT_EXISTS); + } + } + + @Override + public WarehouseStrategyConfigDO getWarehouseStrategyConfig(Long id) { + return warehouseStrategyConfigMapper.selectById(id); + } + + @Override + public PageResult getWarehouseStrategyConfigPage(WarehouseStrategyConfigPageReqVO pageReqVO) { + return warehouseStrategyConfigMapper.selectPage(pageReqVO); + } + + @Override + public List getWarehouseStrategyConfigList() { + return warehouseStrategyConfigMapper.selectList(); + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/application-dev.yaml b/nl-module-wms/nl-module-wms-server/src/main/resources/application-dev.yaml index 4f34ac9c..fa721e92 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/resources/application-dev.yaml +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/application-dev.yaml @@ -3,16 +3,16 @@ spring: cloud: nacos: - server-addr: http://192.168.81.193:8848 # Nacos 服务器地址 + server-addr: 192.168.81.193:8848 # Nacos 服务器地址 username: nacos password: nacos discovery: # 【配置中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP metadata: version: 1.0.0 # 服务实例的版本号,可用于灰度发布 config: # 【注册中心】配置项 - namespace: dev # 命名空间。这里使用 dev 开发环境 + namespace: 91c8ac41-7fb0-423b-947e-2caad4c87d41 # 命名空间。这里使用 dev 开发环境 group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP --- #################### 数据库相关配置 #################### @@ -57,14 +57,14 @@ spring: primary: master datasource: master: - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: @@ -76,7 +76,6 @@ spring: --- #################### MQ 消息队列相关配置 #################### -# rocketmq 配置项,对应 RocketMQProperties 配置类 rocketmq: name-server: 127.0.0.1:9876 # RocketMQ Namesrv @@ -95,11 +94,11 @@ spring: xxl: job: admin: - addresses: http://localhost:8080/xxl-job-admin # 调度中心部署跟地址 - accessToken: 123456 # 执行器通讯TOKEN + addresses: http://192.168.81.193:8080/xxl-job-admin # 调度中心部署跟地址 + accessToken: default_token # 执行器通讯TOKEN executor: ip: localhost - port: 9995 + port: 8995 --- #################### 服务保障相关配置 #################### @@ -140,4 +139,6 @@ logging: # 芋道配置项,设置当前项目所有自定义的配置 nl: - demo: false # 开启演示模式 \ No newline at end of file + demo: false # 开启演示模式 + websocket: + enable: false # 本地开发禁用 WebSocket(避免 RocketMQ consumer 连不上报错) \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/application-mq-dev.yaml b/nl-module-wms/nl-module-wms-server/src/main/resources/application-mq-dev.yaml new file mode 100644 index 00000000..883a1894 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/application-mq-dev.yaml @@ -0,0 +1,11 @@ +--- #################### MQ 消息队列相关配置 #################### +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 192.168.81.193:9876 + producer: + group: wms_producer_dev_group # 事务消息需要配置一样 + send-message-timeout: 3000 + consumer: + wms-task-operate: + group: wms_task_status_change_dev_group + topic: wms_task_status_change_dev_topic \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/application-mq-test.yaml b/nl-module-wms/nl-module-wms-server/src/main/resources/application-mq-test.yaml new file mode 100644 index 00000000..91e76da5 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/application-mq-test.yaml @@ -0,0 +1,8 @@ +--- #################### MQ 消息队列相关配置 #################### +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 127.0.0.1:9876 + consumer: + wms-task-operate: + group: wms-task-status-change-test-group + topic: wms-task-status-change-test-topic \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/application-test.yaml b/nl-module-wms/nl-module-wms-server/src/main/resources/application-test.yaml index 7c03eb65..a0cc978f 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/resources/application-test.yaml +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/application-test.yaml @@ -59,12 +59,12 @@ spring: master: url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/application.yaml b/nl-module-wms/nl-module-wms-server/src/main/resources/application.yaml index c5fb3505..de00b69f 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/resources/application.yaml +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/application.yaml @@ -13,6 +13,7 @@ spring: import: - optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置 - optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置 + - optional:classpath:application-mq-${spring.profiles.active}.yaml # 加载 MQ 配置 # Servlet 配置 servlet: @@ -64,7 +65,7 @@ mybatis-plus: map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 global-config: db-config: - #id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 + # id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 # id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库 # id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/groupplate/GroupPlateMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/groupplate/GroupPlateMapper.xml new file mode 100644 index 00000000..21bd592d --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/groupplate/GroupPlateMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinv/IostorInvMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinv/IostorInvMapper.xml new file mode 100644 index 00000000..1446a25f --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinv/IostorInvMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinvdis/IostorinvDisMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinvdis/IostorinvDisMapper.xml new file mode 100644 index 00000000..9d8c0e56 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinvdis/IostorinvDisMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinvdtl/IostorinvDtlMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinvdtl/IostorinvDtlMapper.xml new file mode 100644 index 00000000..a07c69b6 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/iostorinvdtl/IostorinvDtlMapper.xml @@ -0,0 +1,95 @@ + + + + + + gp.group_id AS group_id, + gp.vehicle_code AS vehicle_code, + gp.pcsn AS pcsn, + gp.material_id AS material_id, + gp.material_code AS material_code, + mb.material_name AS material_name, + gp.qty - COALESCE(gp.frozen_qty, 0) AS available_qty, + gp.qty_unit_id AS qty_unit_id, + gp.qty_unit_name AS qty_unit_name, + gp.ext_code AS ext_code, + gp.ext_type AS ext_type, + gp.ext_dtl_code AS ext_dtl_code, + sa.stor_id AS stor_id, + sa.stor_code AS stor_code, + sa.stor_name AS stor_name + + + + + + + + + diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/sectattr/SectAttrMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/sectattr/SectAttrMapper.xml new file mode 100644 index 00000000..cd03eb18 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/sectattr/SectAttrMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/storagevehicleext/StorageVehicleExtMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/storagevehicleext/StorageVehicleExtMapper.xml new file mode 100644 index 00000000..0580c32b --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/storagevehicleext/StorageVehicleExtMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/storagevehicleinfo/StorageVehicleInfoMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/storagevehicleinfo/StorageVehicleInfoMapper.xml new file mode 100644 index 00000000..104b0180 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/storagevehicleinfo/StorageVehicleInfoMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/structAttr/StrucAttrMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/structAttr/StrucAttrMapper.xml new file mode 100644 index 00000000..cc1b886b --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/structAttr/StrucAttrMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/warehousestrategy/WarehouseStrategyMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/warehousestrategy/WarehouseStrategyMapper.xml new file mode 100644 index 00000000..e0158ff1 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/warehousestrategy/WarehouseStrategyMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/warehousestrategyconfig/WarehouseStrategyConfigMapper.xml b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/warehousestrategyconfig/WarehouseStrategyConfigMapper.xml new file mode 100644 index 00000000..eb9dd4a5 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/resources/mapper/warehousestrategyconfig/WarehouseStrategyConfigMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/dal/mysql/iostorinvdtl/IostorinvDtlMapperTest.java b/nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/dal/mysql/iostorinvdtl/IostorinvDtlMapperTest.java new file mode 100644 index 00000000..f5be587a --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/dal/mysql/iostorinvdtl/IostorinvDtlMapperTest.java @@ -0,0 +1,119 @@ +package cn.code.nl.module.wms.dal.mysql.iostorinvdtl; + +import cn.code.nl.framework.common.pojo.PageResult; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryPageReqVO; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryRespVO; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.ExpandAvailableInventoryReqVO; +import cn.code.nl.module.wms.service.iostorinv.IostorInvServiceImpl; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.core.MybatisConfiguration; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import org.apache.ibatis.session.SqlSessionFactory; +import org.junit.jupiter.api.Test; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.Transactional; + +import javax.sql.DataSource; +import jakarta.annotation.Resource; +import java.lang.reflect.Field; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringJUnitConfig +@ContextConfiguration(classes = IostorinvDtlMapperTest.TestConfiguration.class) +@Sql("/sql/iostorinv/available-inventory.sql") +@Transactional +class IostorinvDtlMapperTest { + + @Resource + private IostorinvDtlMapper mapper; + + @Test + void shouldExpandAvailableChildrenAndExecutePageFilters() throws Exception { + IostorInvServiceImpl service = new IostorInvServiceImpl(); + Field mapperField = IostorInvServiceImpl.class.getDeclaredField("iostorinvDtlMapper"); + mapperField.setAccessible(true); + mapperField.set(service, mapper); + + ExpandAvailableInventoryReqVO expandReqVO = new ExpandAvailableInventoryReqVO(); + expandReqVO.setStorId("STOR-001"); + expandReqVO.setVehicleCodes(List.of("BOX-001", "BOX-001")); + List expanded = service.expandAvailableInventory(expandReqVO); + + assertEquals(2, expanded.size()); + assertEquals(List.of(1L, 2L), expanded.stream().map(AvailableInventoryRespVO::getGroupId).toList()); + assertTrue(expanded.stream().allMatch(item -> "BOX-001".equals(item.getVehicleCode()))); + assertTrue(expanded.stream().allMatch(item -> "STOR-001".equals(item.getStorId()))); + assertEquals(2, expanded.stream().map(AvailableInventoryRespVO::getPcsn).distinct().count()); + assertTrue(expanded.stream().allMatch(item -> item.getAvailableQty().signum() > 0)); + assertEquals(0, new java.math.BigDecimal("5").compareTo(expanded.get(1).getAvailableQty())); + + List locked = mapper.selectAvailableInventoryByVehicleCodesForUpdate( + "STOR-001", List.of("BOX-001")); + assertEquals(List.of(1L, 2L), locked.stream().map(AvailableInventoryRespVO::getGroupId).toList()); + + AvailableInventoryPageReqVO warehousePageReqVO = new AvailableInventoryPageReqVO(); + warehousePageReqVO.setStorId("STOR-001"); + warehousePageReqVO.setPageNo(1); + warehousePageReqVO.setPageSize(10); + PageResult warehousePage = mapper.selectAvailableInventoryPage(warehousePageReqVO); + assertEquals(2L, warehousePage.getTotal()); + + AvailableInventoryPageReqVO pageReqVO = new AvailableInventoryPageReqVO(); + pageReqVO.setStorId("STOR-001"); + pageReqVO.setMaterialCode("MAT-001"); + pageReqVO.setVehicleCode("BOX-001"); + pageReqVO.setPcsn("PCSN-002"); + pageReqVO.setPageNo(1); + pageReqVO.setPageSize(10); + PageResult page = mapper.selectAvailableInventoryPage(pageReqVO); + + assertEquals(1L, page.getTotal()); + assertEquals("PCSN-002", page.getList().get(0).getPcsn()); + assertEquals(2L, page.getList().get(0).getGroupId()); + assertEquals("材料一", page.getList().get(0).getMaterialName()); + } + + @Configuration(proxyBeanMethods = false) + @MapperScan(basePackageClasses = IostorinvDtlMapper.class) + static class TestConfiguration { + + @Bean + DataSource dataSource() { + return new DriverManagerDataSource("jdbc:h2:mem:available_inventory;MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", ""); + } + + @Bean + SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { + MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); + factory.setDataSource(dataSource); + factory.setMapperLocations(new org.springframework.core.io.ClassPathResource( + "mapper/iostorinvdtl/IostorinvDtlMapper.xml")); + MybatisConfiguration configuration = new MybatisConfiguration(); + configuration.setMapUnderscoreToCamelCase(true); + factory.setConfiguration(configuration); + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); + factory.setPlugins(interceptor); + return factory.getObject(); + } + + @Bean + PlatformTransactionManager transactionManager(DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + } + +} diff --git a/nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceLocalSpringTest.java b/nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceLocalSpringTest.java new file mode 100644 index 00000000..37f76725 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/test/java/cn/code/nl/module/wms/service/iostorinv/IostorInvServiceLocalSpringTest.java @@ -0,0 +1,377 @@ +package cn.code.nl.module.wms.service.iostorinv; + +import cn.code.nl.framework.common.exception.ServiceException; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.module.base.api.codegen.CodeGenApi; +import cn.code.nl.module.base.api.codegen.dto.CodeGenerateReqDTO; +import cn.code.nl.module.wms.controller.admin.iostorinv.vo.IostorInvCreateReqVO; +import com.baomidou.mybatisplus.core.MybatisConfiguration; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import jakarta.annotation.Resource; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.apache.ibatis.session.SqlSessionFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import javax.sql.DataSource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static cn.code.nl.module.wms.enums.ErrorCodeConstants.IOSTOR_INV_CODE_GENERATE_FAILED; + +@SpringJUnitConfig +@ContextConfiguration(classes = IostorInvServiceLocalSpringTest.TestConfiguration.class) +@Sql("/sql/iostorinv/create-outbound.sql") +class IostorInvServiceLocalSpringTest { + + @Resource + private IostorInvService iostorInvService; + @Resource + private JdbcTemplate jdbcTemplate; + @Resource + private TestCodeGenApi codeGenApi; + @Resource + private SecondDetailInsertFailureAspect detailInsertFailureAspect; + + @BeforeEach + void resetCodeGenApi() { + codeGenApi.setResult(CommonResult.success("OUT-TEST-0001")); + codeGenApi.setFailure(null); + detailInsertFailureAspect.disable(); + } + + @Test + void shouldCreateOutboundUsingLockedInventoryIdentityInsteadOfClientUnitAndSource() { + String id = iostorInvService.createOutbound(buildRequest()); + + assertNotNull(id); + assertFalse(id.isBlank()); + jdbcTemplate.queryForObject("SELECT * FROM wms_iostorinv WHERE iostorinv_id = ?", (rs, rowNum) -> { + assertEquals("OUT-TEST-0001", rs.getString("bill_code")); + assertEquals("OUT", rs.getString("io_type")); + assertEquals("销售出库", rs.getString("bill_type")); + assertEquals(LocalDateTime.of(2026, 7, 22, 0, 0), + rs.getTimestamp("biz_date").toLocalDateTime()); + assertEquals("STOR-01", rs.getString("stor_id")); + assertEquals("生成", rs.getString("bill_status")); + assertEquals("主表备注", rs.getString("remark")); + assertEquals(2, rs.getInt("detail_count")); + assertEquals(new BigDecimal("19.750"), rs.getBigDecimal("total_weight")); + return null; + }, id); + + List details = jdbcTemplate.query( + "SELECT * FROM wms_iostorinvdtl WHERE iostorinv_id = ? ORDER BY seq_no", + (rs, rowNum) -> new DetailRow(rs.getString("iostorinvdtl_id"), rs.getString("iostorinv_id"), + rs.getInt("seq_no"), rs.getString("material_code"), + rs.getString("material_id"), rs.getString("pcsn"), rs.getBigDecimal("plan_qty"), + rs.getBigDecimal("assign_qty"), rs.getBigDecimal("unassign_qty"), + rs.getString("qty_unit_id"), rs.getString("qty_unit_name"), + rs.getString("source_bill_code"), rs.getString("source_bill_type"), + rs.getString("source_billdtl_id"), rs.getString("remark")), id); + assertEquals(2, details.size()); + assertNotNull(details.get(0).detailId()); + assertNotNull(details.get(1).detailId()); + assertFalse(details.get(0).detailId().isBlank()); + assertFalse(details.get(1).detailId().isBlank()); + assertNotEquals(details.get(0).detailId(), details.get(1).detailId()); + assertEquals(id, details.get(0).headerId()); + assertEquals(id, details.get(1).headerId()); + assertEquals(new DetailRow(details.get(0).detailId(), id, 1, "MAT-01", "MID-01", "PCSN-01", + new BigDecimal("12.500"), BigDecimal.ZERO.setScale(3), new BigDecimal("12.500"), + "DB-KG", "数据库千克", "DB-SRC-01", "DB-TYPE", "DB-DTL-01", "明细一"), details.get(0)); + assertEquals(new DetailRow(details.get(1).detailId(), id, 2, "MAT-02", "MID-02", "PCSN-02", + new BigDecimal("7.250"), BigDecimal.ZERO.setScale(3), new BigDecimal("7.250"), + "DB-KG", "数据库千克", "DB-SRC-02", "DB-TYPE", "DB-DTL-02", "明细二"), details.get(1)); + } + + @Test + void shouldNotInsertAnythingWhenCodeGenerationFails() { + codeGenApi.setResult(CommonResult.error(500, "编码服务暂不可用")); + + ServiceException exception = assertThrows(ServiceException.class, + () -> iostorInvService.createOutbound(buildRequest())); + + assertEquals("单据号生成失败", exception.getMessage()); + assertEquals(IOSTOR_INV_CODE_GENERATE_FAILED.getCode(), exception.getCode()); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinv", Integer.class)); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class)); + } + + @Test + void shouldRejectBlankGeneratedCodeWithoutInsertingAnything() { + codeGenApi.setResult(CommonResult.success(" ")); + + ServiceException exception = assertThrows(ServiceException.class, + () -> iostorInvService.createOutbound(buildRequest())); + + assertEquals(IOSTOR_INV_CODE_GENERATE_FAILED.getCode(), exception.getCode()); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinv", Integer.class)); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class)); + } + + @Test + void shouldConvertRemoteCodeGenerationExceptionToBusinessError() { + codeGenApi.setFailure(new IllegalStateException("远程连接失败")); + + ServiceException exception = assertThrows(ServiceException.class, + () -> iostorInvService.createOutbound(buildRequest())); + + assertEquals(IOSTOR_INV_CODE_GENERATE_FAILED.getCode(), exception.getCode()); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinv", Integer.class)); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class)); + } + + @Test + void shouldRollbackRealInsertsWhenInjectedSecondDetailFailureOccurs() { + detailInsertFailureAspect.failOnSecondInsert(); + + assertThrows(DataAccessResourceFailureException.class, + () -> iostorInvService.createOutbound(buildRequest())); + + assertEquals(1, detailInsertFailureAspect.getRowsVisibleBeforeFailure()); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinv", Integer.class)); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class)); + } + + @Test + void shouldRejectMissingChildOfSameBoxBeforeGeneratingCode() { + jdbcTemplate.update("INSERT INTO wms_group_plate VALUES (104,'BOX-01','可用','MID-01','MAT-01','PCSN-EXTRA',1,0,'KG','千克',NULL,NULL,NULL,FALSE)"); + assertInventoryRejected(buildRequest()); + } + + @Test + void shouldRejectCrossWarehouseGroup() { + IostorInvCreateReqVO request = buildRequest(); + IostorInvCreateReqVO.Detail detail = request.getDetails().get(0); + detail.setGroupId(103L); + detail.setVehicleCode("BOX-X"); + detail.setPcsn("PCSN-X"); + detail.setPlanQty(new BigDecimal("5")); + assertInventoryRejected(request); + } + + @Test + void shouldRejectQuantityAboveAvailable() { + IostorInvCreateReqVO request = buildRequest(); + request.getDetails().get(1).setPlanQty(new BigDecimal("7.251")); + assertInventoryRejected(request); + } + + @Test + void shouldRejectDuplicateGroup() { + IostorInvCreateReqVO request = buildRequest(); + request.getDetails().get(1).setGroupId(101L); + request.getDetails().get(1).setVehicleCode("BOX-01"); + assertInventoryRejected(request); + } + + @Test + void shouldRejectInventoryChangedToUnavailable() { + jdbcTemplate.update("UPDATE wms_group_plate SET status = '不可用' WHERE group_id = 101"); + assertInventoryRejected(buildRequest()); + } + + @Test + void shouldRejectInventoryChangedToFullyFrozen() { + jdbcTemplate.update("UPDATE wms_group_plate SET frozen_qty = qty WHERE group_id = 101"); + assertInventoryRejected(buildRequest()); + } + + @Test + void shouldRejectInventoryChangedToPartiallyFrozenBelowRequestedQuantity() { + jdbcTemplate.update("UPDATE wms_group_plate SET qty = 10, frozen_qty = 6 WHERE group_id = 101"); + IostorInvCreateReqVO request = buildRequest(); + request.getDetails().get(0).setPlanQty(new BigDecimal("5")); + assertInventoryRejected(request); + } + + private void assertInventoryRejected(IostorInvCreateReqVO request) { + ServiceException ex = assertThrows(ServiceException.class, () -> iostorInvService.createOutbound(request)); + assertEquals("出库库存已变化,请刷新后重新选择完整箱库存", ex.getMessage()); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinv", Integer.class)); + assertEquals(0, jdbcTemplate.queryForObject("SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class)); + } + + private IostorInvCreateReqVO buildRequest() { + IostorInvCreateReqVO request = new IostorInvCreateReqVO(); + request.setBillType("销售出库"); + request.setStorId("STOR-01"); + request.setBizDate(LocalDateTime.of(2026, 7, 22, 0, 0)); + request.setRemark("主表备注"); + request.setDetails(List.of(buildDetail("01", "12.500", "明细一"), + buildDetail("02", "7.250", "明细二"))); + return request; + } + + private IostorInvCreateReqVO.Detail buildDetail(String suffix, String planQty, String remark) { + IostorInvCreateReqVO.Detail detail = new IostorInvCreateReqVO.Detail(); + detail.setMaterialCode("MAT-" + suffix); + detail.setMaterialId("MID-" + suffix); + detail.setPcsn("PCSN-" + suffix); + detail.setPlanQty(new BigDecimal(planQty)); + detail.setQtyUnitId("KG"); + detail.setQtyUnitName("千克"); + detail.setSourceBillCode("SRC-" + suffix); + detail.setSourceBillType("ORDER"); + detail.setSourceBilldtlId("SRC-DTL-" + suffix); + detail.setRemark(remark); + detail.setGroupId(Long.valueOf("1" + suffix)); + detail.setVehicleCode("BOX-" + suffix); + return detail; + } + + private record DetailRow(String detailId, String headerId, Integer seqNo, String materialCode, + String materialId, String pcsn, + BigDecimal planQty, BigDecimal assignQty, BigDecimal unassignQty, + String qtyUnitId, String qtyUnitName, String sourceBillCode, + String sourceBillType, String sourceBilldtlId, String remark) { + } + + @Configuration(proxyBeanMethods = false) + @EnableTransactionManagement + @EnableAspectJAutoProxy + @MapperScan(basePackages = {"cn.code.nl.module.wms.dal.mysql.iostorinv", + "cn.code.nl.module.wms.dal.mysql.iostorinvdtl"}) + static class TestConfiguration { + + @Bean + DataSource dataSource() { + return new DriverManagerDataSource("jdbc:h2:mem:create_outbound;MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", ""); + } + + @Bean + SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { + MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); + factory.setDataSource(dataSource); + factory.setMapperLocations(new org.springframework.core.io.ClassPathResource( + "mapper/iostorinvdtl/IostorinvDtlMapper.xml")); + MybatisConfiguration configuration = new MybatisConfiguration(); + configuration.setMapUnderscoreToCamelCase(true); + factory.setConfiguration(configuration); + return factory.getObject(); + } + + @Bean + PlatformTransactionManager transactionManager(DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Bean + JdbcTemplate jdbcTemplate(DataSource dataSource) { + return new JdbcTemplate(dataSource); + } + + @Bean + static MethodValidationPostProcessor methodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + + @Bean + IostorInvService iostorInvService() { + return new IostorInvServiceImpl(); + } + + @Bean + TestCodeGenApi codeGenApi() { + return new TestCodeGenApi(); + } + + @Bean + SecondDetailInsertFailureAspect detailInsertFailureAspect(JdbcTemplate jdbcTemplate) { + return new SecondDetailInsertFailureAspect(jdbcTemplate); + } + } + + static class TestCodeGenApi implements CodeGenApi { + private CommonResult result; + private RuntimeException failure; + + void setResult(CommonResult result) { + this.result = result; + } + + void setFailure(RuntimeException failure) { + this.failure = failure; + } + + @Override + public CommonResult generate(CodeGenerateReqDTO reqDTO) { + assertEquals("IO_CODE", reqDTO.getRuleCode()); + if (failure != null) { + throw failure; + } + return result; + } + + @Override + public CommonResult preview(String ruleCode) { + throw new UnsupportedOperationException(); + } + } + + /** 在第二次明细真实插入的调用点注入数据库访问故障,用于验证事务回滚。 */ + @Aspect + static class SecondDetailInsertFailureAspect { + private final JdbcTemplate jdbcTemplate; + private boolean enabled; + private int insertCount; + private int rowsVisibleBeforeFailure; + + SecondDetailInsertFailureAspect(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + void failOnSecondInsert() { + enabled = true; + insertCount = 0; + rowsVisibleBeforeFailure = 0; + } + + void disable() { + enabled = false; + insertCount = 0; + rowsVisibleBeforeFailure = 0; + } + + int getRowsVisibleBeforeFailure() { + return rowsVisibleBeforeFailure; + } + + @Around("bean(iostorinvDtlMapper) && execution(* insert(..))") + Object injectFailureOnSecondInsert(ProceedingJoinPoint joinPoint) throws Throwable { + if (!enabled) { + return joinPoint.proceed(); + } + insertCount++; + if (insertCount == 2) { + rowsVisibleBeforeFailure = jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM wms_iostorinvdtl", Integer.class); + throw new DataAccessResourceFailureException("测试注入:第二条明细写入失败"); + } + return joinPoint.proceed(); + } + } +} diff --git a/nl-module-wms/nl-module-wms-server/src/test/resources/sql/iostorinv/available-inventory.sql b/nl-module-wms/nl-module-wms-server/src/test/resources/sql/iostorinv/available-inventory.sql new file mode 100644 index 00000000..cfa74a51 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/test/resources/sql/iostorinv/available-inventory.sql @@ -0,0 +1,59 @@ +DROP TABLE IF EXISTS wms_group_plate; +DROP TABLE IF EXISTS wms_structattr; +DROP TABLE IF EXISTS base_materialbase; + +CREATE TABLE base_materialbase ( + material_id BIGINT PRIMARY KEY, + material_name VARCHAR(64), + deleted BOOLEAN NOT NULL +); + +CREATE TABLE wms_structattr ( + struct_id VARCHAR(64) PRIMARY KEY, + storagevehicle_code VARCHAR(64), + stor_id VARCHAR(64), + stor_code VARCHAR(64), + stor_name VARCHAR(64), + deleted BOOLEAN NOT NULL +); + +CREATE TABLE wms_group_plate ( + group_id BIGINT PRIMARY KEY, + vehicle_code VARCHAR(64), + status VARCHAR(16), + material_id VARCHAR(64), + material_code VARCHAR(64), + pcsn VARCHAR(64), + qty DECIMAL(18, 6), + frozen_qty DECIMAL(18, 6), + qty_unit_id VARCHAR(64), + qty_unit_name VARCHAR(64), + ext_code VARCHAR(64), + ext_type VARCHAR(64), + ext_dtl_code VARCHAR(64), + deleted BOOLEAN NOT NULL +); + +INSERT INTO base_materialbase(material_id, material_name, deleted) +VALUES (1001, '材料一', FALSE), (1002, '已删除材料', TRUE); + +INSERT INTO wms_structattr(struct_id, storagevehicle_code, stor_id, stor_code, stor_name, deleted) +VALUES ('S-001', 'BOX-001', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE), + ('S-001-B', 'BOX-001', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE), + ('S-002', 'BOX-001', 'STOR-002', 'STOR-CODE-002', '二号仓', FALSE), + ('S-003', 'BOX-002', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE), + ('S-004', 'BOX-003', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE), + ('S-005', 'BOX-004', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE), + ('S-006', 'BOX-005', 'STOR-001', 'STOR-CODE-001', '一号仓', TRUE); + +INSERT INTO wms_group_plate(group_id, vehicle_code, status, material_id, material_code, pcsn, + qty, frozen_qty, qty_unit_id, qty_unit_name, ext_code, ext_type, + ext_dtl_code, deleted) +VALUES (1, 'BOX-001', '可用', '1001', 'MAT-001', 'PCSN-001', 10, 2, 'UNIT-1', '卷', 'EXT-1', 'TYPE-1', 'DTL-1', FALSE), + (2, 'BOX-001', '可用', '1001', 'MAT-001', 'PCSN-002', 5, 1, 'UNIT-1', '卷', 'EXT-2', 'TYPE-1', 'DTL-2', FALSE), + (3, 'BOX-002', '不可用', '1001', 'MAT-001', 'PCSN-003', 10, 0, 'UNIT-1', '卷', 'EXT-3', 'TYPE-1', 'DTL-3', FALSE), + (4, 'BOX-003', '可用', '1001', 'MAT-001', 'PCSN-004', 10, 10, 'UNIT-1', '卷', 'EXT-4', 'TYPE-1', 'DTL-4', FALSE), + (5, 'BOX-004', '可用', '1001', 'MAT-001', 'PCSN-005', 10, 0, 'UNIT-1', '卷', 'EXT-5', 'TYPE-1', 'DTL-5', TRUE), + (6, 'BOX-005', '可用', '1001', 'MAT-001', 'PCSN-006', 10, 0, 'UNIT-1', '卷', 'EXT-6', 'TYPE-1', 'DTL-6', FALSE); + +UPDATE wms_group_plate SET frozen_qty = NULL WHERE group_id = 2; diff --git a/nl-module-wms/nl-module-wms-server/src/test/resources/sql/iostorinv/create-outbound.sql b/nl-module-wms/nl-module-wms-server/src/test/resources/sql/iostorinv/create-outbound.sql new file mode 100644 index 00000000..2d00a69e --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/test/resources/sql/iostorinv/create-outbound.sql @@ -0,0 +1,37 @@ +DROP TABLE IF EXISTS wms_iostorinvdtl; +DROP TABLE IF EXISTS wms_iostorinv; +DROP TABLE IF EXISTS wms_group_plate; +DROP TABLE IF EXISTS wms_structattr; +DROP TABLE IF EXISTS base_materialbase; +CREATE TABLE wms_iostorinv ( + iostorinv_id VARCHAR(64) PRIMARY KEY, + bill_code VARCHAR(64), io_type VARCHAR(32), bill_type VARCHAR(64), biz_date TIMESTAMP, + stor_id VARCHAR(64), stor_code VARCHAR(64), stor_name VARCHAR(128), source_id VARCHAR(64), + source_name VARCHAR(128), source_type VARCHAR(64), total_qty DECIMAL(18, 3), + total_weight DECIMAL(18, 3), detail_count INT, bill_status VARCHAR(32), remark VARCHAR(255), + create_mode VARCHAR(32), dis_optid VARCHAR(64), dis_time TIMESTAMP, confirm_optid VARCHAR(64), + confirm_time TIMESTAMP, sysdeptid VARCHAR(64), syscompanyid VARCHAR(64), is_upload VARCHAR(16), + upload_optid VARCHAR(64), upload_time VARCHAR(64), create_time TIMESTAMP, update_time TIMESTAMP, + creator VARCHAR(64), updater VARCHAR(64), deleted BOOLEAN DEFAULT FALSE +); + +CREATE TABLE wms_iostorinvdtl ( + iostorinvdtl_id VARCHAR(64) PRIMARY KEY, iostorinv_id VARCHAR(64), seq_no INT, + pcsn VARCHAR(128), bill_status VARCHAR(32), qty_unit_id VARCHAR(64), qty_unit_name VARCHAR(64), + plan_qty DECIMAL(18, 3), real_qty DECIMAL(18, 3), source_billdtl_id VARCHAR(64), + source_bill_type VARCHAR(64), source_bill_code VARCHAR(64), source_bill_table VARCHAR(128), + remark VARCHAR(255), assign_qty DECIMAL(18, 3), unassign_qty DECIMAL(18, 3), + material_code VARCHAR(64), source_load_port VARCHAR(64), callback_strategy VARCHAR(255), + material_id VARCHAR(64), create_time TIMESTAMP, update_time TIMESTAMP, + creator VARCHAR(64), updater VARCHAR(64), deleted BOOLEAN DEFAULT FALSE +); + +CREATE TABLE base_materialbase (material_id VARCHAR(64) PRIMARY KEY, material_name VARCHAR(64), deleted BOOLEAN NOT NULL); +CREATE TABLE wms_structattr (struct_id VARCHAR(64) PRIMARY KEY, storagevehicle_code VARCHAR(64), stor_id VARCHAR(64), stor_code VARCHAR(64), stor_name VARCHAR(64), deleted BOOLEAN NOT NULL); +CREATE TABLE wms_group_plate (group_id BIGINT PRIMARY KEY, vehicle_code VARCHAR(64), status VARCHAR(16), material_id VARCHAR(64), material_code VARCHAR(64), pcsn VARCHAR(64), qty DECIMAL(18,3), frozen_qty DECIMAL(18,3), qty_unit_id VARCHAR(64), qty_unit_name VARCHAR(64), ext_code VARCHAR(64), ext_type VARCHAR(64), ext_dtl_code VARCHAR(64), deleted BOOLEAN NOT NULL); +INSERT INTO base_materialbase VALUES ('MID-01','物料一',FALSE), ('MID-02','物料二',FALSE); +INSERT INTO wms_structattr VALUES ('S1','BOX-01','STOR-01','S01','一号仓',FALSE), ('S2','BOX-02','STOR-01','S01','一号仓',FALSE), ('S3','BOX-X','STOR-02','S02','二号仓',FALSE); +INSERT INTO wms_group_plate VALUES + (101,'BOX-01','可用','MID-01','MAT-01','PCSN-01',12.500,NULL,'DB-KG','数据库千克','DB-SRC-01','DB-TYPE','DB-DTL-01',FALSE), + (102,'BOX-02','可用','MID-02','MAT-02','PCSN-02',8.000,0.750,'DB-KG','数据库千克','DB-SRC-02','DB-TYPE','DB-DTL-02',FALSE), + (103,'BOX-X','可用','MID-01','MAT-01','PCSN-X',5.000,0,'KG','千克',NULL,NULL,NULL,FALSE); diff --git a/nl-server/pom.xml b/nl-server/pom.xml index b165c739..22b3c9ce 100644 --- a/nl-server/pom.xml +++ b/nl-server/pom.xml @@ -46,6 +46,16 @@ nl-module-task-server ${revision} + + cn.nl.cloud + nl-module-wms-server + ${revision} + + + cn.nl.cloud + nl-module-base-server + ${revision} + diff --git a/nl-server/src/main/resources/application-dev.yaml b/nl-server/src/main/resources/application-dev.yaml index 79fa9cf0..4d76d57a 100644 --- a/nl-server/src/main/resources/application-dev.yaml +++ b/nl-server/src/main/resources/application-dev.yaml @@ -47,14 +47,14 @@ spring: primary: master datasource: master: - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://192.168.10.41:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://192.168.10.41:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root - password: root123 + password: root # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: @@ -78,9 +78,6 @@ xxl: --- #################### 消息队列相关 #################### -# rocketmq 配置项,对应 RocketMQProperties 配置类 -rocketmq: - name-server: 127.0.0.1:9876 # RocketMQ Namesrv spring: # RabbitMQ 配置项,对应 RabbitProperties 配置类 diff --git a/nl-server/src/main/resources/application-mq-dev.yaml b/nl-server/src/main/resources/application-mq-dev.yaml new file mode 100644 index 00000000..836b81dd --- /dev/null +++ b/nl-server/src/main/resources/application-mq-dev.yaml @@ -0,0 +1,16 @@ +--- #################### MQ 消息队列相关配置 #################### +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 192.168.81.193:9876 + producer: + group: nl_producer_dev_group + send-message-timeout: 3000 + consumer: + wms-task-operate: + group: wms_task_status_change_dev_group + topic: wms_task_status_change_dev_topic + lms-task-operate: + group: lms_task_status_change_dev_group + topic: lms_task_status_change_dev_topic + task: + topic: task_status_change_dev_topic \ No newline at end of file diff --git a/nl-server/src/main/resources/application-mq-test.yaml b/nl-server/src/main/resources/application-mq-test.yaml new file mode 100644 index 00000000..836b81dd --- /dev/null +++ b/nl-server/src/main/resources/application-mq-test.yaml @@ -0,0 +1,16 @@ +--- #################### MQ 消息队列相关配置 #################### +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 192.168.81.193:9876 + producer: + group: nl_producer_dev_group + send-message-timeout: 3000 + consumer: + wms-task-operate: + group: wms_task_status_change_dev_group + topic: wms_task_status_change_dev_topic + lms-task-operate: + group: lms_task_status_change_dev_group + topic: lms_task_status_change_dev_topic + task: + topic: task_status_change_dev_topic \ No newline at end of file diff --git a/nl-server/src/main/resources/application-test.yaml b/nl-server/src/main/resources/application-test.yaml index 33f9f080..5724823a 100644 --- a/nl-server/src/main/resources/application-test.yaml +++ b/nl-server/src/main/resources/application-test.yaml @@ -59,10 +59,10 @@ spring: # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: redis: - host: 192.168.81.193 # 地址 + host: 127.0.0.1 # 地址 port: 6379 # 端口 database: 1 # 数据库索引 - password: redis123 +# password: redis123 --- #################### 定时任务相关配置 #################### diff --git a/nl-server/src/main/resources/application.yaml b/nl-server/src/main/resources/application.yaml index 22ed0606..ec408e0f 100644 --- a/nl-server/src/main/resources/application.yaml +++ b/nl-server/src/main/resources/application.yaml @@ -5,6 +5,9 @@ spring: profiles: active: dev + config: + import: + - optional:classpath:application-mq-${spring.profiles.active}.yaml # 加载 MQ 配置 main: allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 @@ -85,10 +88,10 @@ mybatis-plus: map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 global-config: db-config: - id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 +# id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 # id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库 # id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 -# id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 + id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) banner: false # 关闭控制台的 Banner 打印 diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/.env.production b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/.env.production index a8f3d29a..28a7c86c 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/.env.production +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/.env.production @@ -3,7 +3,7 @@ VITE_BASE=/ # 请求路径 VITE_BASE_URL=http://127.0.0.1:48080 # 接口地址 -VITE_GLOB_API_URL=http://127.0.0.1:48080/admin-api +VITE_GLOB_API_URL=/admin-api # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 VITE_UPLOAD_TYPE=server @@ -23,4 +23,4 @@ VITE_INJECT_APP_LOADING=true VITE_ARCHIVER=true # 验证码的开关 -VITE_APP_CAPTCHA_ENABLE=true \ No newline at end of file +VITE_APP_CAPTCHA_ENABLE=true diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/base/materialbase/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/base/materialbase/index.ts index 4c6091e1..e0b1b6bd 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/base/materialbase/index.ts +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/base/materialbase/index.ts @@ -1,11 +1,11 @@ import type { PageParam, PageResult } from '@vben/request'; -import type { Dayjs } from 'dayjs'; import { requestClient } from '#/api/request'; export namespace BaseMaterialBaseApi { /** 物料基本信息信息 */ export interface MaterialBase { + materialId: number | string; // 物料标识 materialCode?: string; // 物料编码 materialName?: string; // 物料名称 materialSpec: string; // 规格 diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/task/transporttask/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/task/transporttask/index.ts index 324cda8b..93edf5f8 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/task/transporttask/index.ts +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/task/transporttask/index.ts @@ -92,5 +92,3 @@ export function operateTransportTask(data: { }) { return requestClient.post('/task/transport-task/operate', data); } - - diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/bsrealstorattr/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/bsrealstorattr/index.ts index c20a7a08..d95ab1f2 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/bsrealstorattr/index.ts +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/bsrealstorattr/index.ts @@ -48,7 +48,7 @@ export function getBsrealStorAttrPage(params: PageParam) { } /** 查询实物库属性详情 */ -export function getBsrealStorAttr(id: number) { +export function getBsrealStorAttr(id: string) { return requestClient.get( `/wms/bsreal-stor-attr/get?id=${id}`, ); @@ -65,12 +65,12 @@ export function updateBsrealStorAttr(data: WmsBsrealStorAttrApi.BsrealStorAttr) } /** 删除实物库属性 */ -export function deleteBsrealStorAttr(id: number) { +export function deleteBsrealStorAttr(id: string) { return requestClient.delete(`/wms/bsreal-stor-attr/delete?id=${id}`); } /** 批量删除实物库属性 */ -export function deleteBsrealStorAttrList(ids: number[]) { +export function deleteBsrealStorAttrList(ids: string[]) { return requestClient.delete( `/wms/bsreal-stor-attr/delete-list?ids=${ids.join(',')}`, ); @@ -80,3 +80,10 @@ export function deleteBsrealStorAttrList(ids: number[]) { export function exportBsrealStorAttr(params: any) { return requestClient.download('/wms/bsreal-stor-attr/export-excel', { params }); } + +/** 获得启用的实物库属性精简列表 */ +export function getBsrealStorAttrSimpleList() { + return requestClient.get<{ storId: string; storName: string }[]>( + '/wms/bsreal-stor-attr/simple-list', + ); +} diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/groupplate/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/groupplate/index.ts new file mode 100644 index 00000000..bf258969 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/groupplate/index.ts @@ -0,0 +1,70 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WmsGroupPlateApi { + /** 组盘记录信息 */ + export interface GroupPlate { + groupId?: number; + vehicleCode: string; // 载具编码 + status?: string; // 状态 + materialId: string; // 物料id + pcsn?: string; // 批次 + qty?: number; // 组盘数量 + frozenQty: number; // 冻结数量 + qtyUnitId: string; // 计量单位标识 + qtyUnitName: string; // 计量单位名称 + remark: string; // 备注 + extCode: string; // 来源单据号 + extType: string; // 来源单据类型 + extDtlCode: string; // 来源单据明细号 + md5: string; // md5 + materialCode?: string; // 物料编码 + creatorName?: string; // 创建者名称 + updaterName?: string; // 更新者名称 + } +} + +/** 查询组盘记录分页 */ +export function getGroupPlatePage(params: PageParam) { + return requestClient.get>( + '/wms/group-plate/page', + { params }, + ); +} + +/** 查询组盘记录详情 */ +export function getGroupPlate(id: number) { + return requestClient.get( + `/wms/group-plate/get?id=${id}`, + ); +} + +/** 新增组盘记录 */ +export function createGroupPlate(data: WmsGroupPlateApi.GroupPlate) { + return requestClient.post('/wms/group-plate/create', data); +} + +/** 修改组盘记录 */ +export function updateGroupPlate(data: WmsGroupPlateApi.GroupPlate) { + return requestClient.put('/wms/group-plate/update', data); +} + +/** 删除组盘记录 */ +export function deleteGroupPlate(id: number) { + return requestClient.delete(`/wms/group-plate/delete?id=${id}`); +} + +/** 批量删除组盘记录 */ +export function deleteGroupPlateList(ids: number[]) { + return requestClient.delete( + `/wms/group-plate/delete-list?ids=${ids.join(',')}`, + ); +} + +/** 导出组盘记录 */ +export function exportGroupPlate(params: any) { + return requestClient.download('/wms/group-plate/export-excel', { params }); +} + + diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/iostorinv/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/iostorinv/index.ts new file mode 100644 index 00000000..d180c9b3 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/iostorinv/index.ts @@ -0,0 +1,169 @@ +import type { Dayjs } from 'dayjs'; + +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WmsIostorInvApi { + /** 出入库单主表信息 */ + export interface IostorInv { + iostorinvId: string; // 出入单标识 + billCode?: string; // 单据编号 + ioType?: string; // 出入类型 + billType?: string; // 单据类型 + bizDate?: Dayjs | string; // 业务日期 + storId: string; // 仓库标识 + storCode: string; // 仓库编码 + storName: string; // 仓库名称 + sourceId: string; // 来源方标识 + sourceName: string; // 来源方名称 + sourceType: string; // 来源方类型 + totalQty?: number; // 总数量 + totalWeight: number; // 总重量 + detailCount?: number; // 明细数 + billStatus?: string; // 单据状态 + remark: string; // 备注 + createMode?: string; // 生成方式 + disOptid: string; // 分配人 + disTime?: Dayjs | string; // 分配时间 + confirmOptid: string; // 确认人 + confirmTime?: Dayjs | string; // 确认时间 + sysdeptid: string; // 部门ID + syscompanyid: string; // 公司ID + isUpload?: string; // 是否已上传 + uploadOptid: string; // 回传人 + uploadTime: string; // 回传时间 + } + + /** 出库单可持久化明细 */ + export interface OutboundDetail { + groupId?: number | string; // 组盘记录标识(库存选择方式) + vehicleCode?: string; // 箱号(库存选择方式) + materialCode: string; // 物料编码 + materialId?: string; // 物料标识 + pcsn?: string; // 批次序列号 + planQty: number; // 出库重量 + qtyUnitId?: string; // 数量单位标识 + qtyUnitName?: string; // 数量单位名称 + sourceBillCode?: string; // 来源单据编号 + sourceBillType?: string; // 来源单据类型 + sourceBilldtlId?: string; // 来源单据明细标识 + remark?: string; // 备注 + } + + /** 出库明细页面展示模型(提交时应转换为 OutboundDetail) */ + export interface OutboundDisplayDetail extends OutboundDetail { + materialName?: string; + rowKey?: string; + sapBatchNo?: string; + } + + /** 出库单新增请求 */ + export interface OutboundCreateReq { + billType: string; // 单据类型 + storId: string; // 仓库标识 + bizDate: number; // 业务日期(毫秒时间戳) + remark?: string; // 备注 + details: OutboundDetail[]; // 出库单明细 + } + + /** 可用库存 */ + export interface AvailableInventory { + groupId: number | string; // 组盘记录标识 + vehicleCode: string; // 箱号 + pcsn?: null | string; // 批次 + materialId: string; // 物料标识 + materialCode: string; // 物料编码 + materialName?: null | string; // 物料名称 + availableQty: number; // 可用数量 + qtyUnitId?: null | string; // 计量单位标识 + qtyUnitName?: null | string; // 计量单位名称 + extCode?: null | string; // 来源单据号 + extType?: null | string; // 来源单据类型 + extDtlCode?: null | string; // 来源单据明细号 + storId: string; // 仓库标识 + storCode?: null | string; // 仓库编码 + storName?: null | string; // 仓库名称 + } + + /** 可用库存分页请求 */ + export interface AvailableInventoryPageReq extends PageParam { + storId: string; // 仓库标识 + materialCode?: string; // 物料编码 + vehicleCode?: string; // 箱号 + pcsn?: string; // 批次 + } + + /** 按箱号展开可用库存请求 */ + export interface ExpandAvailableInventoryReq { + storId: string; // 仓库标识 + vehicleCodes: string[]; // 箱号列表 + } +} + +/** 查询出入库单主表分页 */ +export function getIostorInvPage(params: PageParam) { + return requestClient.get>( + '/wms/iostor-inv/page', + { params }, + ); +} + +/** 查询出入库单主表详情 */ +export function getIostorInv(id: string) { + return requestClient.get( + `/wms/iostor-inv/get?id=${encodeURIComponent(id)}`, + ); +} + +/** 新增出入库单主表 */ +export function createIostorInv(data: WmsIostorInvApi.IostorInv) { + return requestClient.post('/wms/iostor-inv/create', data); +} + +/** 修改出入库单主表 */ +export function updateIostorInv(data: WmsIostorInvApi.IostorInv) { + return requestClient.put('/wms/iostor-inv/update', data); +} + +/** 删除出入库单主表 */ +export function deleteIostorInv(id: number) { + return requestClient.delete(`/wms/iostor-inv/delete?id=${id}`); +} + +/** 批量删除出入库单主表 */ +export function deleteIostorInvList(ids: number[]) { + return requestClient.delete( + `/wms/iostor-inv/delete-list?ids=${ids.join(',')}`, + ); +} + +/** 导出出入库单主表 */ +export function exportIostorInv(params: any) { + return requestClient.download('/wms/iostor-inv/export-excel', { params }); +} + +/** 查询可用库存分页 */ +export function getAvailableInventoryPage( + params: WmsIostorInvApi.AvailableInventoryPageReq, + signal?: AbortSignal, +) { + return requestClient.get< + PageResult + >('/wms/iostor-inv/availableInventoryPage', { params, signal }); +} + +/** 按箱号展开可用库存 */ +export function expandAvailableInventory( + data: WmsIostorInvApi.ExpandAvailableInventoryReq, +) { + return requestClient.post( + '/wms/iostor-inv/expandAvailableInventory', + data, + ); +} + +/** 创建出库单 */ +export function createOutbound(data: WmsIostorInvApi.OutboundCreateReq) { + return requestClient.post('/wms/iostor-inv/createOutbound', data); +} diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/sectattr/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/sectattr/index.ts new file mode 100644 index 00000000..241830b4 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/sectattr/index.ts @@ -0,0 +1,83 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WmsSectAttrApi { + /** 库区属性信息 */ + export interface SectAttr { + sectId: string; // 库区标识 + sectCode?: string; // 库区编码 + sectName?: string; // 库区名称 + simpleName: string; // 库区简称 + sectTypeAttr?: string; // 库区类型 + storId?: string; // 仓库标识 + storType: string; // 仓库类型 + capacity: number; // 容量 + width: number; // 宽度 + height: number; // 高度 + zdepth: number; // 深度 + xqty: number; // 起始X坐标 + yqty: number; // 起始Y坐标 + zqty: number; // 起始Z坐标 + sectManagerName: string; // 负责人 + mobileNo: string; // 负责人电话 + remark: string; // 备注 + backGroundColor: string; // 背景色 + frontGroundColor: string; // 前景色 + backGroundPic: string; // 背景图片 + fontDirectionScode: string; // 字体显示方向 + floorNo: number; // 所在楼层 + isUsed?: string; // 是否启用 + extId: string; // 外部标识 + } +} + +/** 查询库区属性分页 */ +export function getSectAttrPage(params: PageParam) { + return requestClient.get>( + '/wms/sect-attr/page', + { params }, + ); +} + +/** 查询库区属性详情 */ +export function getSectAttr(id: string) { + return requestClient.get( + `/wms/sect-attr/get?id=${id}`, + ); +} + +/** 新增库区属性 */ +export function createSectAttr(data: WmsSectAttrApi.SectAttr) { + return requestClient.post('/wms/sect-attr/create', data); +} + +/** 修改库区属性 */ +export function updateSectAttr(data: WmsSectAttrApi.SectAttr) { + return requestClient.put('/wms/sect-attr/update', data); +} + +/** 删除库区属性 */ +export function deleteSectAttr(id: string) { + return requestClient.delete(`/wms/sect-attr/delete?id=${id}`); +} + +/** 批量删除库区属性 */ +export function deleteSectAttrList(ids: string[]) { + return requestClient.delete( + `/wms/sect-attr/delete-list?ids=${ids.join(',')}`, + ); +} + +/** 导出库区属性 */ +export function exportSectAttr(params: any) { + return requestClient.download('/wms/sect-attr/export-excel', { params }); +} + +/** 获得启用的库区属性精简列表(可按仓库筛选) */ +export function getSectAttrSimpleList(storId?: string) { + return requestClient.get<{ sectId: string; sectName: string; storId: string }[]>( + '/wms/sect-attr/simple-list', + { params: storId ? { storId } : {} }, + ); +} diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/storagevehicleext/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/storagevehicleext/index.ts new file mode 100644 index 00000000..a8fe113f --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/storagevehicleext/index.ts @@ -0,0 +1,67 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WmsStorageVehicleExtApi { + /** 载具扩展属性信息信息 */ + export interface StorageVehicleExt { + storageVehicleExtId?: number; + storageVehicleId?: number; // 载具标识 + storageVehicleCode?: string; // 载具编码 + storageVehicleType?: string; // 载具类型 + materialId: number; // 物料标识 + pcsn: string; // 批次 + boxNo: string; // 木箱号 + qtyUnitId: number; // 数量计量单位标识 + qtyUnitName: string; // 数量计量单位名称 + qty: number; // 物料数量 + vehicleWeight?: number; // 托盘重量 + weightUnitId: number; // 重量计量单位标识 + weightUnitName: string; // 重量计量单位名称 + remark: string; // 备注 + } +} + +/** 查询载具扩展属性信息分页 */ +export function getStorageVehicleExtPage(params: PageParam) { + return requestClient.get>( + '/wms/storage-vehicle-ext/page', + { params }, + ); +} + +/** 查询载具扩展属性信息详情 */ +export function getStorageVehicleExt(id: number) { + return requestClient.get( + `/wms/storage-vehicle-ext/get?id=${id}`, + ); +} + +/** 新增载具扩展属性信息 */ +export function createStorageVehicleExt(data: WmsStorageVehicleExtApi.StorageVehicleExt) { + return requestClient.post('/wms/storage-vehicle-ext/create', data); +} + +/** 修改载具扩展属性信息 */ +export function updateStorageVehicleExt(data: WmsStorageVehicleExtApi.StorageVehicleExt) { + return requestClient.put('/wms/storage-vehicle-ext/update', data); +} + +/** 删除载具扩展属性信息 */ +export function deleteStorageVehicleExt(id: number) { + return requestClient.delete(`/wms/storage-vehicle-ext/delete?id=${id}`); +} + +/** 批量删除载具扩展属性信息 */ +export function deleteStorageVehicleExtList(ids: number[]) { + return requestClient.delete( + `/wms/storage-vehicle-ext/delete-list?ids=${ids.join(',')}`, + ); +} + +/** 导出载具扩展属性信息 */ +export function exportStorageVehicleExt(params: any) { + return requestClient.download('/wms/storage-vehicle-ext/export-excel', { params }); +} + + diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/storagevehicleinfo/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/storagevehicleinfo/index.ts new file mode 100644 index 00000000..4203b3e7 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/storagevehicleinfo/index.ts @@ -0,0 +1,79 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WmsStorageVehicleInfoApi { + /** 载具信息信息 */ + export interface StorageVehicleInfo { + storageVehicleId?: number; + storageVehicleCode?: string; // 载具编码 + storageVehicleName: string; // 载具名称 + oneCode: string; // 一维码 + twoCode: string; // 二维码 + isUsed?: boolean; // 是否启用 + storageVehicleType?: string; // 载具类型 + vehicleWidth: number; // 载具宽度 + vehicleLong: number; // 载具长度 + vehicleHeight: number; // 载具高度 + weigth: number; // 托盘重量 + overStructType?: string; // 载具是否超仓位 + occupyStructQty?: number; // 占仓位数 + + } +} + +/** 查询载具信息分页 */ +export function getStorageVehicleInfoPage(params: PageParam) { + return requestClient.get>( + '/wms/storage-vehicle-info/page', + { params }, + ); +} + +/** 查询载具信息详情 */ +export function getStorageVehicleInfo(id: number) { + return requestClient.get( + `/wms/storage-vehicle-info/get?id=${id}`, + ); +} + +/** 新增载具信息 */ +export function createStorageVehicleInfo(data: WmsStorageVehicleInfoApi.StorageVehicleInfo) { + return requestClient.post('/wms/storage-vehicle-info/create', data); +} + +/** 修改载具信息 */ +export function updateStorageVehicleInfo(data: WmsStorageVehicleInfoApi.StorageVehicleInfo) { + return requestClient.put('/wms/storage-vehicle-info/update', data); +} + +/** 删除载具信息 */ +export function deleteStorageVehicleInfo(id: number) { + return requestClient.delete(`/wms/storage-vehicle-info/delete?id=${id}`); +} + +/** 批量删除载具信息 */ +export function deleteStorageVehicleInfoList(ids: number[]) { + return requestClient.delete( + `/wms/storage-vehicle-info/delete-list?ids=${ids.join(',')}`, + ); +} + +/** 批量生成载具信息 */ +export interface BatchCreateStorageVehicleInfoReqVO { + storageVehicleType: string; + storageVehicleTypeLabel: string; + count: number; +} + +/** 批量生成载具信息 */ +export function batchCreateStorageVehicleInfo(data: BatchCreateStorageVehicleInfoReqVO) { + return requestClient.post('/wms/storage-vehicle-info/batch-create', data); +} + +/** 导出载具信息 */ +export function exportStorageVehicleInfo(params: any) { + return requestClient.download('/wms/storage-vehicle-info/export-excel', { params }); +} + + diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/structAttr/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/structAttr/index.ts new file mode 100644 index 00000000..346db433 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/structAttr/index.ts @@ -0,0 +1,88 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WmsStrucAttrApi { + /** 仓位属性信息 */ + export interface StrucAttr { + structId: string; // 仓位标识 + structCode?: string; // 仓位编码 + structName?: string; // 仓位名称 + simpleName: string; // 仓位简称 + sectId?: string; // 库区标识 + sectCode?: string; // 库区编码 + sectName?: string; // 库区名称 + storId?: string; // 仓库标识 + storCode?: string; // 仓库编码 + storName?: string; // 仓库名称 + storType: string; // 仓库类型 + capacity: number; // 容量 + width: number; // 宽度 + height: number; // 高度 + zdepth: number; // 深度 + weight: number; // 承受重量 + xqty: number; // 起始X坐标 + yqty: number; // 起始Y坐标 + zqty: number; // 起始Z坐标 + isTempstruct?: string; // 是否临时仓位 + rowNum: number; // 排 + colNum: number; // 列 + layerNum: number; // 层 + blockNum: number; // 块 + placementType: string; // 放置类型 + isUsed?: boolean; // 是否启用 + isZdepth: string; // 是否判断高度 + storagevehicleCode: string; // 存储载具号 + storagevehicleType: string; // 载具类型 + storagevehicleQty: number; // 载具数量 + lockType?: string; // 锁定类型 + taskCode: string; // 锁定任务编码 + invType: string; // 锁定单据类型 + invId: string; // 锁定单据标识 + invCode: string; // 锁定单据编码 + extId: string; // 外部标识 + remark: string; // 备注 + } +} + +/** 查询仓位属性分页 */ +export function getStrucAttrPage(params: PageParam) { + return requestClient.get>( + '/wms/struc-attr/page', + { params }, + ); +} + +/** 查询仓位属性详情 */ +export function getStrucAttr(id: number) { + return requestClient.get( + `/wms/struc-attr/get?id=${id}`, + ); +} + +/** 新增仓位属性 */ +export function createStrucAttr(data: WmsStrucAttrApi.StrucAttr) { + return requestClient.post('/wms/struc-attr/create', data); +} + +/** 修改仓位属性 */ +export function updateStrucAttr(data: WmsStrucAttrApi.StrucAttr) { + return requestClient.put('/wms/struc-attr/update', data); +} + +/** 删除仓位属性 */ +export function deleteStrucAttr(id: number) { + return requestClient.delete(`/wms/struc-attr/delete?id=${id}`); +} + +/** 批量删除仓位属性 */ +export function deleteStrucAttrList(ids: number[]) { + return requestClient.delete( + `/wms/struc-attr/delete-list?ids=${ids.join(',')}`, + ); +} + +/** 导出仓位属性 */ +export function exportStrucAttr(params: any) { + return requestClient.download('/wms/struc-attr/export-excel', { params }); +} diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/warehousestrategy/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/warehousestrategy/index.ts new file mode 100644 index 00000000..160512d6 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/warehousestrategy/index.ts @@ -0,0 +1,58 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WmsWarehouseStrategyApi { + /** 出入库策略信息 */ + export interface WarehouseStrategy { + id?: number; + sectionCode?: string; // 库区编码 + strategy?: string; // 规则 + strategyType: string; // 策略类型 + description: string; // 描述 + } +} + +/** 查询出入库策略分页 */ +export function getWarehouseStrategyPage(params: PageParam) { + return requestClient.get>( + '/wms/warehouse-strategy/page', + { params }, + ); +} + +/** 查询出入库策略详情 */ +export function getWarehouseStrategy(id: number) { + return requestClient.get( + `/wms/warehouse-strategy/get?id=${id}`, + ); +} + +/** 新增出入库策略 */ +export function createWarehouseStrategy(data: WmsWarehouseStrategyApi.WarehouseStrategy) { + return requestClient.post('/wms/warehouse-strategy/create', data); +} + +/** 修改出入库策略 */ +export function updateWarehouseStrategy(data: WmsWarehouseStrategyApi.WarehouseStrategy) { + return requestClient.put('/wms/warehouse-strategy/update', data); +} + +/** 删除出入库策略 */ +export function deleteWarehouseStrategy(id: number) { + return requestClient.delete(`/wms/warehouse-strategy/delete?id=${id}`); +} + +/** 批量删除出入库策略 */ +export function deleteWarehouseStrategyList(ids: number[]) { + return requestClient.delete( + `/wms/warehouse-strategy/delete-list?ids=${ids.join(',')}`, + ); +} + +/** 导出出入库策略 */ +export function exportWarehouseStrategy(params: any) { + return requestClient.download('/wms/warehouse-strategy/export-excel', { params }); +} + + diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/warehousestrategyconfig/index.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/warehousestrategyconfig/index.ts new file mode 100644 index 00000000..a4292f72 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/wms/warehousestrategyconfig/index.ts @@ -0,0 +1,77 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WmsWarehouseStrategyConfigApi { + /** 仓储策略配置信息 */ + export interface WarehouseStrategyConfig { + id?: string; + strategyCode?: string; // 策略编码 + strategyName?: string; // 策略名称 + strategyType?: string; // 策略类型 + classType?: string; // 类处理类型 + param?: string; // 处理类 + remark: string; // 描述 + isUsed: boolean; // 是否启用 + ban: boolean; // 禁止操作 + formData: string; // 限定参数 + } + + /** 仓储策略配置精简信息 */ + export interface WarehouseStrategyConfigSimple { + strategyCode: string; // 策略编码 + strategyName: string; // 策略名称 + classType?: string; // 类处理类型 + } +} + +/** 查询仓储策略配置分页 */ +export function getWarehouseStrategyConfigPage(params: PageParam) { + return requestClient.get>( + '/wms/warehouse-strategy-config/page', + { params }, + ); +} + +/** 查询仓储策略配置详情 */ +export function getWarehouseStrategyConfig(id: number) { + return requestClient.get( + `/wms/warehouse-strategy-config/get?id=${id}`, + ); +} + +/** 新增仓储策略配置 */ +export function createWarehouseStrategyConfig(data: WmsWarehouseStrategyConfigApi.WarehouseStrategyConfig) { + return requestClient.post('/wms/warehouse-strategy-config/create', data); +} + +/** 修改仓储策略配置 */ +export function updateWarehouseStrategyConfig(data: WmsWarehouseStrategyConfigApi.WarehouseStrategyConfig) { + return requestClient.put('/wms/warehouse-strategy-config/update', data); +} + +/** 删除仓储策略配置 */ +export function deleteWarehouseStrategyConfig(id: number) { + return requestClient.delete(`/wms/warehouse-strategy-config/delete?id=${id}`); +} + +/** 批量删除仓储策略配置 */ +export function deleteWarehouseStrategyConfigList(ids: number[]) { + return requestClient.delete( + `/wms/warehouse-strategy-config/delete-list?ids=${ids.join(',')}`, + ); +} + +/** 导出仓储策略配置 */ +export function exportWarehouseStrategyConfig(params: any) { + return requestClient.download('/wms/warehouse-strategy-config/export-excel', { params }); +} + +/** 查询仓储策略配置精简列表 */ +export function getWarehouseStrategyConfigSimpleList() { + return requestClient.get( + '/wms/warehouse-strategy-config/simple-list', + ); +} + + diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/components/table-action/icons.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/components/table-action/icons.ts index 67e8ad4e..17fb2e8a 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/components/table-action/icons.ts +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/components/table-action/icons.ts @@ -14,5 +14,7 @@ export const ACTION_ICON = { BOOK: 'lucide:book', AUDIT: 'lucide:file-check', SEND: 'lucide:send', + CIRCLE_CHECK: 'lucide:circle-check', + CIRCLE_X: 'lucide:circle-x', CANCEL: 'lucide:ban', }; diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/materialbase/components/MaterialSelectModal.vue b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/materialbase/components/MaterialSelectModal.vue new file mode 100644 index 00000000..3faaea02 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/materialbase/components/MaterialSelectModal.vue @@ -0,0 +1,137 @@ + + + diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/materialbase/data.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/materialbase/data.ts index 0937d1bd..79a612ff 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/materialbase/data.ts +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/materialbase/data.ts @@ -1,12 +1,12 @@ -import type { VbenFormSchema } from '#/adapter/form'; -import type { VxeTableGridOptions } from '#/adapter/vxe-table'; -import type { BaseMaterialBaseApi } from '#/api/base/materialbase'; +import type {VbenFormSchema} from '#/adapter/form'; +import type {VxeTableGridOptions} from '#/adapter/vxe-table'; +import type {BaseMaterialBaseApi} from '#/api/base/materialbase'; -import { handleTree } from '@vben/utils'; +import {handleTree} from '@vben/utils'; -import { getClassStandardList, getClassStandardListByCode } from '#/api/base/classstandard'; -import { getSimpleMeasureUnitList } from '#/api/base/measureunit'; -import { getRangePickerDefaultProps } from '#/utils'; +import {getClassStandardList, getClassStandardListByCode} from '#/api/base/classstandard'; +import {getSimpleMeasureUnitList} from '#/api/base/measureunit'; +import {getRangePickerDefaultProps} from '#/utils'; // ========== 分类映射:classId → className ========== const classNameMap: Record = {}; @@ -46,102 +46,218 @@ async function loadMeasureUnitList() { // ========== 新增/修改的表单 ========== export function useFormSchema(): VbenFormSchema[] { return [ - { fieldName: 'materialId', component: 'Input', dependencies: { triggerFields: [''], show: () => false } }, - { fieldName: 'materialCode', label: '物料编码', rules: 'required', component: 'Input', componentProps: { placeholder: '请输入物料编码' } }, - { fieldName: 'materialName', label: '物料名称', rules: 'required', component: 'Input', componentProps: { placeholder: '请输入物料名称' } }, - { fieldName: 'materialSpec', label: '规格', component: 'Input', componentProps: { placeholder: '请输入规格' } }, - { fieldName: 'materialModel', label: '型号', component: 'Input', componentProps: { placeholder: '请输入型号' } }, - { fieldName: 'englishName', label: '外文名称', component: 'Input', componentProps: { placeholder: '请输入外文名称' } }, + { + fieldName: 'materialId', + component: 'Input', + dependencies: {triggerFields: [''], show: () => false} + }, + { + fieldName: 'materialCode', + label: '物料编码', + rules: 'required', + component: 'Input', + componentProps: {placeholder: '请输入物料编码'} + }, + { + fieldName: 'materialName', + label: '物料名称', + rules: 'required', + component: 'Input', + componentProps: {placeholder: '请输入物料名称'} + }, + { + fieldName: 'materialSpec', + label: '规格', + component: 'Input', + componentProps: {placeholder: '请输入规格'} + }, + { + fieldName: 'materialModel', + label: '型号', + component: 'Input', + componentProps: {placeholder: '请输入型号'} + }, + { + fieldName: 'englishName', + label: '外文名称', + component: 'Input', + componentProps: {placeholder: '请输入外文名称'} + }, { fieldName: 'materialTypeId', label: '物料分类', component: 'ApiTreeSelect', - componentProps: { api: loadMaterialTypeTree, labelField: 'className', valueField: 'classId', childrenField: 'children', placeholder: '请选择物料分类', allowClear: true, treeDefaultExpandAll: true }, + componentProps: { + api: loadMaterialTypeTree, + labelField: 'className', + valueField: 'classId', + childrenField: 'children', + placeholder: '请选择物料分类', + allowClear: true, + treeDefaultExpandAll: true + }, }, { fieldName: 'baseUnitId', label: '基本计量单位', rules: 'required', component: 'ApiSelect', - componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择基本计量单位', allowClear: true }, + componentProps: { + api: loadMeasureUnitList, + labelField: 'unitCode', + valueField: 'measureUnitId', + placeholder: '请选择基本计量单位', + allowClear: true + }, }, { fieldName: 'assUnitId', label: '辅助计量单位', component: 'ApiSelect', - componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择辅助计量单位', allowClear: true }, + componentProps: { + api: loadMeasureUnitList, + labelField: 'unitCode', + valueField: 'measureUnitId', + placeholder: '请选择辅助计量单位', + allowClear: true + }, }, { fieldName: 'lenUnitId', label: '长度单位', component: 'ApiSelect', - componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择长度单位', allowClear: true }, + componentProps: { + api: loadMeasureUnitList, + labelField: 'unitCode', + valueField: 'measureUnitId', + placeholder: '请选择长度单位', + allowClear: true + }, }, { fieldName: 'weightUnitId', label: '重量单位', component: 'ApiSelect', - componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择重量单位', allowClear: true }, + componentProps: { + api: loadMeasureUnitList, + labelField: 'unitCode', + valueField: 'measureUnitId', + placeholder: '请选择重量单位', + allowClear: true + }, }, { fieldName: 'cubageUnitId', label: '体积单位', component: 'ApiSelect', - componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择体积单位', allowClear: true }, + componentProps: { + api: loadMeasureUnitList, + labelField: 'unitCode', + valueField: 'measureUnitId', + placeholder: '请选择体积单位', + allowClear: true + }, }, { fieldName: 'isUsed', label: '是否启用', rules: 'required', component: 'RadioGroup', - componentProps: { options: [{ label: '是', value: '1' }, { label: '否', value: '0' }], buttonStyle: 'solid', optionType: 'button' }, + componentProps: { + options: [{label: '是', value: '1'}, {label: '否', value: '0'}], + buttonStyle: 'solid', + optionType: 'button' + }, + }, + { + fieldName: 'extId', + label: '外部标识', + component: 'Input', + componentProps: {placeholder: '请输入外部标识'} }, - { fieldName: 'extId', label: '外部标识', component: 'Input', componentProps: { placeholder: '请输入外部标识' } }, ]; } // ========== 列表的搜索表单 ========== export function useGridFormSchema(): VbenFormSchema[] { return [ - { fieldName: 'materialCode', label: '物料编码', component: 'Input', componentProps: { allowClear: true, placeholder: '请输入物料编码' } }, - { fieldName: 'materialName', label: '物料名称', component: 'Input', componentProps: { allowClear: true, placeholder: '请输入物料名称' } }, + { + fieldName: 'materialCode', + label: '物料编码', + component: 'Input', + componentProps: {allowClear: true, placeholder: '请输入物料编码'} + }, + { + fieldName: 'materialName', + label: '物料名称', + component: 'Input', + componentProps: {allowClear: true, placeholder: '请输入物料名称'} + }, { fieldName: 'materialTypeId', label: '物料分类', component: 'ApiTreeSelect', - componentProps: { api: loadMaterialTypeTree, labelField: 'className', valueField: 'classId', childrenField: 'children', placeholder: '请选择物料分类', allowClear: true }, + componentProps: { + api: loadMaterialTypeTree, + labelField: 'className', + valueField: 'classId', + childrenField: 'children', + placeholder: '请选择物料分类', + allowClear: true + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: {...getRangePickerDefaultProps(), allowClear: true} + }, + { + fieldName: 'isUsed', + label: '是否启用', + component: 'Select', + componentProps: { + allowClear: true, + placeholder: '请选择', + options: [{label: '是', value: '1'}, {label: '否', value: '0'}] + } }, - { fieldName: 'createTime', label: '创建时间', component: 'RangePicker', componentProps: { ...getRangePickerDefaultProps(), allowClear: true } }, - { fieldName: 'isUsed', label: '是否启用', component: 'Select', componentProps: { allowClear: true, placeholder: '请选择', options: [{ label: '是', value: '1' }, { label: '否', value: '0' }] } }, ]; } // ========== 列表的字段 ========== export function useGridColumns(): VxeTableGridOptions['columns'] { return [ - { type: 'checkbox', width: 40 }, - { field: 'materialCode', title: '物料编码', minWidth: 120 }, - { field: 'materialName', title: '物料名称', minWidth: 200 }, - { field: 'materialSpec', title: '规格', minWidth: 120 }, - { field: 'materialModel', title: '型号', minWidth: 120 }, - { field: 'englishName', title: '外文名称', minWidth: 120 }, + {type: 'checkbox', width: 40}, + {field: 'materialCode', title: '物料编码', minWidth: 120}, + {field: 'materialName', title: '物料名称', minWidth: 200}, + {field: 'materialSpec', title: '规格', minWidth: 120}, + {field: 'materialModel', title: '型号', minWidth: 120}, + {field: 'englishName', title: '外文名称', minWidth: 120}, { field: 'materialTypeId', title: '物料分类', minWidth: 150, - formatter: ({ cellValue }: { cellValue: number }) => classNameMap[cellValue] || cellValue || '-', + formatter: ({cellValue}: { + cellValue: number + }) => classNameMap[cellValue] || cellValue || '-', }, { field: 'baseUnitId', title: '基本计量单位', minWidth: 120, - formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', + formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', }, { field: 'assUnitId', title: '辅助计量单位', minWidth: 120, - formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', + formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', }, { field: 'lenUnitId', title: '长度单位', minWidth: 120, - formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', + formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', }, { field: 'weightUnitId', title: '重量单位', minWidth: 120, - formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', + formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', }, { field: 'cubageUnitId', title: '体积单位', minWidth: 120, - formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', + formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-', }, - { field: 'createTime', title: '创建时间', minWidth: 180, formatter: 'formatDateTime' }, - { field: 'isUsed', title: '是否启用', minWidth: 100, formatter: ({ cellValue }: { cellValue: string }) => (cellValue === '1' ? '是' : '否') }, - { field: 'extId', title: '外部标识', minWidth: 120 }, - { title: '操作', width: 200, fixed: 'right', slots: { default: 'actions' } }, + {field: 'createTime', title: '创建时间', minWidth: 180, formatter: 'formatDateTime'}, + { + field: 'isUsed', + title: '是否启用', + minWidth: 100, + formatter: ({cellValue}: { cellValue: string }) => (cellValue === '1' ? '是' : '否') + }, + {field: 'extId', title: '外部标识', minWidth: 120}, + {title: '操作', width: 200, fixed: 'right', slots: {default: 'actions'}}, ]; } diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/measureunit/components/MeasureUnitSelectModal.vue b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/measureunit/components/MeasureUnitSelectModal.vue new file mode 100644 index 00000000..ef4cf7e0 --- /dev/null +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/base/measureunit/components/MeasureUnitSelectModal.vue @@ -0,0 +1,114 @@ + + + diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/task/transporttask/data.ts b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/task/transporttask/data.ts index da5443dd..8032b1bb 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/task/transporttask/data.ts +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/task/transporttask/data.ts @@ -4,12 +4,31 @@ import type { TaskTransportTaskApi } from '#/api/task/transporttask'; import { DICT_TYPE } from '@vben/constants'; import { getDictOptions } from '@vben/hooks'; +import { handleTree } from '@vben/utils'; import dayjs from 'dayjs'; +import { getClassStandardListByCode } from '#/api/base/classstandard'; import { getRangePickerDefaultProps } from '#/utils'; +const taskTypeNameMap: Record = {}; + +async function loadTaskTypeTree() { + const data = await getClassStandardListByCode('0002'); + if (!data || data.length === 0) return []; + return handleTree(data, 'classId', 'parentClassId'); +} + /** 新增/修改的表单 */ +export async function loadAllLookupData() { + const taskTypeData = await getClassStandardListByCode('0002'); + taskTypeData?.forEach((item) => { + if (item.classCode) { + taskTypeNameMap[item.classCode] = item.className; + } + }); +} + export function useFormSchema(): VbenFormSchema[] { return [ { @@ -369,11 +388,15 @@ export function useGridFormSchema(): VbenFormSchema[] { { fieldName: 'taskType', label: '任务类型', - component: 'Select', + component: 'ApiTreeSelect', componentProps: { allowClear: true, - options: [], + api: loadTaskTypeTree, + childrenField: 'children', + labelField: 'className', placeholder: '请选择任务类型', + treeDefaultExpandAll: true, + valueField: 'classCode', }, }, { @@ -588,6 +611,8 @@ export function useGridColumns(): VxeTableGridOptions + taskTypeNameMap[cellValue] || cellValue || '-', }, { field: 'acsTaskType', @@ -608,6 +633,10 @@ export function useGridColumns(): VxeTableGridOptions { + await loadAllLookupData(); + ready.value = true; +}); + const [FormModal, formModalApi] = useVbenModal({ connectedComponent: Form, destroyOnClose: true, @@ -141,7 +147,7 @@ const [Grid, gridApi] = useVbenVxeGrid({