From ac19f00697b5eff8ba81826d3935e0d168c56388 Mon Sep 17 00:00:00 2001 From: zhouz <> Date: Fri, 24 Jul 2026 10:35:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=87=BA=E5=BA=93=E5=8D=95=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/iostorinv/IostorInvController.java | 21 ++- .../iostorinv/vo/IostorInvCreateReqVO.java | 4 + .../iostorinv/vo/IostorInvDetailRespVO.java | 14 ++ .../admin/iostorinv/vo/IostorInvRespVO.java | 3 + .../iostorinv/vo/IostorInvUpdateReqVO.java | 16 ++ .../iostorinvdtl/IostorinvDtlMapper.java | 4 + .../service/iostorinv/IostorInvService.java | 13 +- .../iostorinv/IostorInvServiceImpl.java | 52 +++++- .../iostorinvdtl/IostorinvDtlMapper.xml | 21 +++ .../IostorInvServiceLocalSpringTest.java | 12 +- .../src/api/wms/iostorinv/index.ts | 19 ++ .../src/views/wms/iostorinv/modules/form.vue | 166 +++++++++--------- .../iostorinv/modules/outbound-form.test.ts | 10 +- .../wms/iostorinv/modules/outbound-form.ts | 2 + 14 files changed, 257 insertions(+), 100 deletions(-) create mode 100644 nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvDetailRespVO.java create mode 100644 nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvUpdateReqVO.java 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 index db3d3830..670f15dc 100644 --- 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 @@ -70,10 +70,10 @@ public class IostorInvController { } @PutMapping("/update") - @Operation(summary = "更新出入库单主表") + @Operation(summary = "更新出库单主表及明细") @PreAuthorize("@ss.hasPermission('wms:iostor-inv:update')") - public CommonResult updateIostorInv(@Valid @RequestBody IostorInvSaveReqVO updateReqVO) { - iostorInvService.updateIostorInv(updateReqVO); + public CommonResult updateIostorInv(@Valid @RequestBody IostorInvUpdateReqVO reqVO) { + iostorInvService.updateOutbound(reqVO); return success(true); } @@ -99,9 +99,20 @@ public class IostorInvController { @Operation(summary = "获得出入库单主表") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('wms:iostor-inv:query')") - public CommonResult getIostorInv(@RequestParam("id") String id) { + public CommonResult getIostorInv(@RequestParam("id") Long id) { IostorInvDO iostorInv = iostorInvService.getIostorInv(id); - return success(BeanUtils.toBean(iostorInv, IostorInvRespVO.class)); + IostorInvRespVO respVO = BeanUtils.toBean(iostorInv, IostorInvRespVO.class); + respVO.setDetails(iostorInvService.getIostorInvDetails(id)); + return success(respVO); + } + + @GetMapping("/details") + @Operation(summary = "获得出入库单全部明细") + @Parameter(name = "iostorinvId", description = "出入库单主表标识", required = true) + @PreAuthorize("@ss.hasPermission('wms:iostor-inv:query')") + public CommonResult> getIostorInvDetails( + @RequestParam("iostorinvId") Long iostorinvId) { + return success(iostorInvService.getIostorInvDetails(iostorinvId)); } @GetMapping("/page") 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 index 2b5faf60..caf56b68 100644 --- 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 @@ -19,6 +19,10 @@ public class IostorInvCreateReqVO { @NotEmpty(message = "单据类型不能为空") private String billType; + @Schema(description = "单据状态", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "单据状态不能为空") + private String billStatus; + @Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "仓库标识不能为空") private String storId; diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvDetailRespVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvDetailRespVO.java new file mode 100644 index 00000000..c5e40f65 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvDetailRespVO.java @@ -0,0 +1,14 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 出入库单编辑明细 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class IostorInvDetailRespVO extends IostorInvCreateReqVO.Detail { + + @Schema(description = "物料名称") + private String materialName; +} 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 index b1ba3283..768356af 100644 --- 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 @@ -130,4 +130,7 @@ public class IostorInvRespVO implements VO { @ExcelProperty("回传时间") private String uploadTime; + @Schema(description = "出入库单明细") + private List details; + } diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvUpdateReqVO.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvUpdateReqVO.java new file mode 100644 index 00000000..46604872 --- /dev/null +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/controller/admin/iostorinv/vo/IostorInvUpdateReqVO.java @@ -0,0 +1,16 @@ +package cn.code.nl.module.wms.controller.admin.iostorinv.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 出库单修改 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class IostorInvUpdateReqVO extends IostorInvCreateReqVO { + + @Schema(description = "出入库单主表标识", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出入库单主表标识不能为空") + private Long iostorinvId; +} 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 index 61324e0e..337e93cf 100644 --- 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 @@ -12,6 +12,7 @@ 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.iostorinv.vo.IostorInvDetailRespVO; import cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo.*; /** @@ -47,6 +48,9 @@ public interface IostorinvDtlMapper extends BaseMapperX { List selectAvailableInventoryByVehicleCodesForUpdate( @Param("storId") String storId, @Param("vehicleCodes") Collection vehicleCodes); + /** 查询指定出入库单的编辑明细,并带出物料名称。 */ + List selectEditDetails(@Param("iostorinvId") Long iostorinvId); + default PageResult selectPage(IostorinvDtlPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(IostorinvDtlDO::getIostorinvId, reqVO.getIostorinvId()) 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 index c2acd718..a4ad27d3 100644 --- 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 @@ -4,6 +4,7 @@ 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.module.wms.dal.dataobject.iostorinvdtl.IostorinvDtlDO; import cn.code.nl.framework.common.pojo.PageResult; import cn.code.nl.framework.common.pojo.PageParam; @@ -53,6 +54,11 @@ public interface IostorInvService { */ void updateIostorInv(@Valid IostorInvSaveReqVO updateReqVO); + /** + * 更新出库单主表并替换全部明细。 + */ + void updateOutbound(@Valid IostorInvUpdateReqVO reqVO); + /** * 删除出入库单主表 * @@ -73,7 +79,12 @@ public interface IostorInvService { * @param id 编号 * @return 出入库单主表 */ - IostorInvDO getIostorInv(String id); + IostorInvDO getIostorInv(Long id); + + /** + * 获得出入库单的全部明细。 + */ + List getIostorInvDetails(Long id); /** * 获得出入库单主表分页 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 index 91aff9a8..330dd229 100644 --- 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 @@ -90,16 +90,24 @@ public class IostorInvServiceImpl implements IostorInvService { iostorInv.setBillType(reqVO.getBillType()); iostorInv.setBizDate(reqVO.getBizDate()); iostorInv.setStorId(reqVO.getStorId()); - iostorInv.setBillStatus("10"); + iostorInv.setBillStatus(reqVO.getBillStatus()); 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); + insertOutboundDetails(iostorInv.getIostorinvId(), reqVO.getBillStatus(), + reqVO.getDetails(), inventorySnapshot); + return iostorInv.getIostorinvId(); + } + + private void insertOutboundDetails(Long iostorinvId, String billStatus, + List details, + Map inventorySnapshot) { + for (int index = 0; index < details.size(); index++) { + IostorInvCreateReqVO.Detail detail = details.get(index); IostorinvDtlDO detailDO = new IostorinvDtlDO(); - detailDO.setIostorinvId(iostorInv.getIostorinvId()); + detailDO.setIostorinvId(iostorinvId); detailDO.setSeqNo(index + 1); AvailableInventoryRespVO inventory = inventorySnapshot.get(detail.getGroupId()); detailDO.setMaterialCode(inventory == null ? detail.getMaterialCode() : inventory.getMaterialCode()); @@ -108,7 +116,7 @@ public class IostorInvServiceImpl implements IostorInvService { detailDO.setPlanQty(detail.getPlanQty()); detailDO.setUnassignQty(detail.getPlanQty()); detailDO.setAssignQty(BigDecimal.ZERO); - detailDO.setBillStatus("10"); + detailDO.setBillStatus(billStatus); detailDO.setQtyUnitId(inventory == null ? detail.getQtyUnitId() : inventory.getQtyUnitId()); detailDO.setSourceBillCode(inventory == null ? detail.getSourceBillCode() : inventory.getExtCode()); detailDO.setSourceBillType(inventory == null ? detail.getSourceBillType() : inventory.getExtType()); @@ -116,7 +124,6 @@ public class IostorInvServiceImpl implements IostorInvService { detailDO.setRemark(detail.getRemark()); iostorinvDtlMapper.insert(detailDO); } - return iostorInv.getIostorinvId(); } private Map validateAndLockInventory(IostorInvCreateReqVO reqVO) { @@ -199,6 +206,32 @@ public class IostorInvServiceImpl implements IostorInvService { iostorInvMapper.updateById(updateObj); } + @Override + @Transactional(rollbackFor = Exception.class) + public void updateOutbound(IostorInvUpdateReqVO reqVO) { + validateIostorInvExists(String.valueOf(reqVO.getIostorinvId())); + Map inventorySnapshot = validateAndLockInventory(reqVO); + BigDecimal totalWeight = reqVO.getDetails().stream() + .map(IostorInvCreateReqVO.Detail::getPlanQty) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + IostorInvDO updateObj = new IostorInvDO(); + updateObj.setIostorinvId(reqVO.getIostorinvId()); + updateObj.setBillType(reqVO.getBillType()); + updateObj.setBillStatus(reqVO.getBillStatus()); + updateObj.setBizDate(reqVO.getBizDate()); + updateObj.setStorId(reqVO.getStorId()); + updateObj.setRemark(reqVO.getRemark()); + updateObj.setDetailCount(reqVO.getDetails().size()); + updateObj.setTotalWeight(totalWeight); + iostorInvMapper.updateById(updateObj); + + iostorinvDtlMapper.delete(new LambdaQueryWrapperX() + .eq(IostorinvDtlDO::getIostorinvId, reqVO.getIostorinvId())); + insertOutboundDetails(reqVO.getIostorinvId(), reqVO.getBillStatus(), + reqVO.getDetails(), inventorySnapshot); + } + @Override public void deleteIostorInv(String id) { // 校验存在 @@ -221,10 +254,15 @@ public class IostorInvServiceImpl implements IostorInvService { } @Override - public IostorInvDO getIostorInv(String id) { + public IostorInvDO getIostorInv(Long id) { return iostorInvMapper.selectById(id); } + @Override + public List getIostorInvDetails(Long id) { + return iostorinvDtlMapper.selectEditDetails(id); + } + @Override public PageResult getIostorInvPage(IostorInvPageReqVO pageReqVO) { PageResult pageResult = iostorInvMapper.selectPage(pageReqVO); 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 index a07c69b6..134ab6c2 100644 --- 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 @@ -92,4 +92,25 @@ FOR UPDATE + + 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 index 37f76725..fe6ea822 100644 --- 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 @@ -64,10 +64,9 @@ class IostorInvServiceLocalSpringTest { @Test void shouldCreateOutboundUsingLockedInventoryIdentityInsteadOfClientUnitAndSource() { - String id = iostorInvService.createOutbound(buildRequest()); + Long 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")); @@ -97,12 +96,12 @@ class IostorInvServiceLocalSpringTest { 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", + assertEquals(id.toString(), details.get(0).headerId()); + assertEquals(id.toString(), details.get(1).headerId()); + assertEquals(new DetailRow(details.get(0).detailId(), id.toString(), 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", + assertEquals(new DetailRow(details.get(1).detailId(), id.toString(), 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)); } @@ -218,6 +217,7 @@ class IostorInvServiceLocalSpringTest { private IostorInvCreateReqVO buildRequest() { IostorInvCreateReqVO request = new IostorInvCreateReqVO(); request.setBillType("销售出库"); + request.setBillStatus("生成"); request.setStorId("STOR-01"); request.setBizDate(LocalDateTime.of(2026, 7, 22, 0, 0)); request.setRemark("主表备注"); 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 index b460f57c..037b35a0 100644 --- 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 @@ -27,6 +27,7 @@ export namespace WmsIostorInvApi { creator?: string; // 创建者标识 creatorName?: string; // 创建者名称 createTime?: Dayjs | string; // 创建时间 + details?: OutboundDetail[]; // 出入库单明细 disOptid: string; // 分配人 disTime?: Dayjs | string; // 分配时间 confirmOptid: string; // 确认人 @@ -64,12 +65,18 @@ export namespace WmsIostorInvApi { /** 出库单新增请求 */ export interface OutboundCreateReq { billType: string; // 单据类型 + billStatus: string; // 单据状态 storId: string; // 仓库标识 bizDate: number; // 业务日期(毫秒时间戳) remark?: string; // 备注 details: OutboundDetail[]; // 出库单明细 } + /** 出库单修改请求 */ + export interface OutboundUpdateReq extends OutboundCreateReq { + iostorinvId: string; + } + /** 可用库存 */ export interface AvailableInventory { groupId: number | string; // 组盘记录标识 @@ -119,6 +126,13 @@ export function getIostorInv(id: string) { ); } +/** 查询出入库单全部明细 */ +export function getIostorInvDetails(iostorinvId: string) { + return requestClient.get( + `/wms/iostor-inv/details?iostorinvId=${encodeURIComponent(iostorinvId)}`, + ); +} + /** 新增出入库单主表 */ export function createIostorInv(data: WmsIostorInvApi.IostorInv) { return requestClient.post('/wms/iostor-inv/create', data); @@ -129,6 +143,11 @@ export function updateIostorInv(data: WmsIostorInvApi.IostorInv) { return requestClient.put('/wms/iostor-inv/update', data); } +/** 修改出库单主表及明细 */ +export function updateOutbound(data: WmsIostorInvApi.OutboundUpdateReq) { + return requestClient.put('/wms/iostor-inv/update', data); +} + /** 删除出入库单主表 */ export function deleteIostorInv(id: number) { return requestClient.delete(`/wms/iostor-inv/delete?id=${id}`); diff --git a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/form.vue b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/form.vue index 4eed162d..774c05a8 100644 --- a/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/form.vue +++ b/nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/wms/iostorinv/modules/form.vue @@ -9,37 +9,37 @@ import { Button, Input, InputNumber, message, Space, Table } from 'antdv-next'; import dayjs from 'dayjs'; import { useVbenForm } from '#/adapter/form'; -import { getSimpleDictDataList } from '#/api/system/dict/data'; import { getBsrealStorAttrSimpleList } from '#/api/wms/bsrealstorattr'; import { createOutbound, getIostorInv, - updateIostorInv, + getIostorInvDetails, + updateOutbound, } from '#/api/wms/iostorinv'; import { $t } from '#/locales'; -import { useFormSchema } from '../data'; import { summarizeDetails } from './detail-summary'; import InventorySelectComponent from './inventory-select.vue'; import ManualDetailComponent from './manual-detail.vue'; import { buildOutboundPayload, - filterOutboundBillTypeOptions, mergeOutboundInventory, type OutboundFormDetail, shouldApplyEditResult, shouldClearDetailsForWarehouseChange, } from './outbound-form'; +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; const emit = defineEmits(['success']); const formData = ref(); const details = ref([]); const currentStorId = ref(); let manualRowSequence = 0; -let billTypeRequest: null | ReturnType = null; let mainModalOpen = false; let mainOpenToken = 0; let activeEditId: string | undefined; +let suppressWarehouseChange = false; const isEdit = computed(() => Boolean(formData.value?.iostorinvId)); const getTitle = computed(() => @@ -48,17 +48,6 @@ const getTitle = computed(() => : '出库单新增', ); -const [LegacyForm, legacyFormApi] = useVbenForm({ - commonConfig: { - componentProps: { class: 'w-full' }, - formItemClass: 'col-span-2', - labelWidth: 80, - }, - layout: 'horizontal', - schema: useFormSchema(), - showDefaultActions: false, -}); - async function handleWarehouseChange(nextStorId?: string) { const shouldClear = shouldClearDetailsForWarehouseChange( currentStorId.value, @@ -78,7 +67,7 @@ const [OutboundForm, outboundFormApi] = useVbenForm({ labelWidth: 88, }, handleValuesChange: (values) => { - if (Object.hasOwn(values, 'storId')) { + if (!suppressWarehouseChange && Object.hasOwn(values, 'storId')) { void handleWarehouseChange(values.storId); } }, @@ -108,7 +97,7 @@ const [OutboundForm, outboundFormApi] = useVbenForm({ component: 'Select', componentProps: { allowClear: true, - options: [], + options: getDictOptions(DICT_TYPE.WMS_OUT_BILL_TYPE), placeholder: '请选择业务类型', }, fieldName: 'billType', @@ -116,11 +105,15 @@ const [OutboundForm, outboundFormApi] = useVbenForm({ rules: 'required', }, { - component: 'Input', - componentProps: { disabled: true }, - defaultValue: '生成', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.WMS_IO_BILL_STATUS), + placeholder: '请选择单据状态', + }, fieldName: 'billStatus', label: '单据状态', + rules: 'required', }, { component: 'InputNumber', @@ -164,28 +157,6 @@ const [ManualDetail, manualDetailApi] = useVbenModal({ destroyOnClose: true, }); -async function loadBillTypeOptions() { - billTypeRequest ??= getSimpleDictDataList(); - const request = billTypeRequest; - try { - const dictItems = await request; - outboundFormApi.updateSchema([ - { - componentProps: { - allowClear: true, - options: filterOutboundBillTypeOptions(dictItems), - placeholder: '请选择业务类型', - }, - fieldName: 'billType', - }, - ]); - } catch { - message.error('出库业务类型加载失败,请稍后重试'); - } finally { - if (billTypeRequest === request) billTypeRequest = null; - } -} - const columns = [ { key: 'index', title: '序号', width: 60 }, { dataIndex: 'materialCode', key: 'materialCode', title: '物料编码', width: 130 }, @@ -265,34 +236,23 @@ function validateDetails() { const [Modal, modalApi] = useVbenModal({ async onConfirm() { - if (isEdit.value) { - const { valid } = await legacyFormApi.validate(); - if (!valid) return; - modalApi.lock(); - try { - await updateIostorInv( - (await legacyFormApi.getValues()) as WmsIostorInvApi.IostorInv, - ); - await modalApi.close(); - emit('success'); - message.success($t('ui.actionMessage.operationSuccess')); - } finally { - modalApi.unlock(); - } - return; - } - const { valid } = await outboundFormApi.validate(); if (!valid || !validateDetails()) return; const values = await outboundFormApi.getValues(); modalApi.lock(); try { - await createOutbound( - buildOutboundPayload( - { ...values, bizDate: dayjs(values.bizDate).valueOf() }, - details.value, - ), + const payload = buildOutboundPayload( + { ...values, bizDate: dayjs(values.bizDate).valueOf() }, + details.value, ); + if (isEdit.value) { + await updateOutbound({ + ...payload, + iostorinvId: formData.value!.iostorinvId, + }); + } else { + await createOutbound(payload); + } await modalApi.close(); emit('success'); message.success($t('ui.actionMessage.operationSuccess')); @@ -318,17 +278,32 @@ const [Modal, modalApi] = useVbenModal({ formData.value = undefined; details.value = []; currentStorId.value = undefined; - await outboundFormApi.resetForm(); + suppressWarehouseChange = true; + try { + await outboundFormApi.resetForm(); + await outboundFormApi.updateSchema([ + { + componentProps: { + allowClear: true, + disabled: false, + options: getDictOptions(DICT_TYPE.WMS_IO_BILL_STATUS), + placeholder: '请选择单据状态', + }, + fieldName: 'billStatus', + }, + ]); + if (!mainModalOpen || mainOpenToken !== token || activeEditId) return; + await outboundFormApi.setValues({ + billCode: '保存时自动生成', + billStatus: '10', + bizDate: dayjs(), + detailCount: 0, + totalWeight: '0.000', + }); + } finally { + suppressWarehouseChange = false; + } if (!mainModalOpen || mainOpenToken !== token || activeEditId) return; - await outboundFormApi.setValues({ - billCode: '保存时自动生成', - billStatus: '生成', - bizDate: dayjs(), - detailCount: 0, - totalWeight: '0.000', - }); - if (!mainModalOpen || mainOpenToken !== token || activeEditId) return; - await loadBillTypeOptions(); return; } const editId = data.iostorinvId; @@ -336,7 +311,10 @@ const [Modal, modalApi] = useVbenModal({ formData.value = data; modalApi.lock(); try { - const editResult = await getIostorInv(editId); + const [editResult, editDetails] = await Promise.all([ + getIostorInv(editId), + getIostorInvDetails(editId), + ]); if ( !shouldApplyEditResult( mainModalOpen, @@ -349,7 +327,38 @@ const [Modal, modalApi] = useVbenModal({ return; } formData.value = editResult; - await legacyFormApi.setValues(editResult); + suppressWarehouseChange = true; + try { + await outboundFormApi.resetForm(); + await outboundFormApi.updateSchema([ + { + componentProps: { + allowClear: true, + disabled: true, + options: getDictOptions(DICT_TYPE.WMS_IO_BILL_STATUS), + placeholder: '请选择单据状态', + }, + fieldName: 'billStatus', + }, + ]); + details.value = editDetails.map((detail, index) => ({ + ...detail, + rowKey: `edit-${editId}-${index}`, + })); + await outboundFormApi.setValues({ + billCode: editResult.billCode, + billStatus: editResult.billStatus, + billType: editResult.billType, + bizDate: editResult.bizDate ? dayjs(editResult.bizDate) : undefined, + detailCount: details.value.length, + remark: editResult.remark, + storId: editResult.storId, + totalWeight: Number(editResult.totalWeight || 0).toFixed(3), + }); + currentStorId.value = editResult.storId; + } finally { + suppressWarehouseChange = false; + } } finally { if ( shouldApplyEditResult( @@ -369,8 +378,7 @@ const [Modal, modalApi] = useVbenModal({