fix(biz): 修复入库退料相关功能

This commit is contained in:
zxy 2026-06-01 16:33:25 +08:00
parent 9835388514
commit 8c0e19372c
14 changed files with 830 additions and 236 deletions

View File

@ -30,7 +30,7 @@ public class RawStorageRespVO {
@Schema(description = "业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料)", example = "1") @Schema(description = "业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料)", example = "1")
@ExcelProperty("业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料)") @ExcelProperty("业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料)")
private Integer businessType; private String businessType;
@Schema(description = "备注", example = "随便") @Schema(description = "备注", example = "随便")
@ExcelProperty("备注") @ExcelProperty("备注")

View File

@ -82,4 +82,6 @@ public class RawStorageMatPageReqVO extends PageParam {
@Schema(description = "存货账单号") @Schema(description = "存货账单号")
private String inventBillNo; private String inventBillNo;
private String billNo;
} }

View File

@ -39,7 +39,7 @@ public class RawStorageDO extends BaseDO {
/** /**
* 业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料) * 业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料)
*/ */
private Integer businessType; private String businessType;
/** /**
* 备注 * 备注
*/ */

View File

@ -109,4 +109,6 @@ public class RawStorageMatDO extends BaseDO {
*/ */
private String inventBillNo; private String inventBillNo;
private BigDecimal returnQty;
} }

View File

@ -22,11 +22,10 @@ public interface RawStorageMapper extends BaseMapperX<RawStorageDO> {
.eqIfPresent(RawStorageDO::getBusinessType, reqVO.getBusinessType()) .eqIfPresent(RawStorageDO::getBusinessType, reqVO.getBusinessType())
.eqIfPresent(RawStorageDO::getRemark, reqVO.getRemark()) .eqIfPresent(RawStorageDO::getRemark, reqVO.getRemark())
.eqIfPresent(RawStorageDO::getStatus, reqVO.getStatus()) .eqIfPresent(RawStorageDO::getStatus, reqVO.getStatus())
.betweenIfPresent(RawStorageDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(RawStorageDO::getSupplierNo, reqVO.getSupplierNo()) .eqIfPresent(RawStorageDO::getSupplierNo, reqVO.getSupplierNo())
.likeIfPresent(RawStorageDO::getSupplierName, reqVO.getSupplierName()) .likeIfPresent(RawStorageDO::getSupplierName, reqVO.getSupplierName())
.eqIfPresent(RawStorageDO::getSupplierId, reqVO.getSupplierId()) .eqIfPresent(RawStorageDO::getSupplierId, reqVO.getSupplierId())
// .betweenIfPresent(RawStorageDO::getBillDate, reqVO.getBillDate()) .betweenIfPresent(RawStorageDO::getBillDate, reqVO.getBillDate())
.eqIfPresent(RawStorageDO::getOperatorId, reqVO.getOperatorId()) .eqIfPresent(RawStorageDO::getOperatorId, reqVO.getOperatorId())
.likeIfPresent(RawStorageDO::getOperatorName, reqVO.getOperatorName()) .likeIfPresent(RawStorageDO::getOperatorName, reqVO.getOperatorName())
.eqIfPresent(RawStorageDO::getRelarionNo, reqVO.getRelarionNo()) .eqIfPresent(RawStorageDO::getRelarionNo, reqVO.getRelarionNo())

View File

@ -39,11 +39,12 @@ public interface RawStorageInventoryMapper extends BaseMapperX<RawStorageInvento
return inventoryDO != null ? inventoryDO.getInventBillNo() : null; return inventoryDO != null ? inventoryDO.getInventBillNo() : null;
} }
default RawStorageInventoryDO selectByMatCodeAndBatchNo(String matCode, String spec, Integer storeHouseId, Integer storeAreaId) { default RawStorageInventoryDO selectByMatCodeAndBatchNo(String matCode, String spec, Integer storeHouseId, Integer storeAreaId, String lotNo) {
return selectOne(new LambdaQueryWrapperX<RawStorageInventoryDO>() return selectOne(new LambdaQueryWrapperX<RawStorageInventoryDO>()
.eq(RawStorageInventoryDO::getMatCode, matCode) .eq(RawStorageInventoryDO::getMatCode, matCode)
.eq(RawStorageInventoryDO::getSpec, spec)
.eq(RawStorageInventoryDO::getStoreHouseId, storeHouseId) .eq(RawStorageInventoryDO::getStoreHouseId, storeHouseId)
.eq(RawStorageInventoryDO::getStoreAreaId, storeAreaId)); .eq(RawStorageInventoryDO::getStoreAreaId, storeAreaId)
.eqIfPresent(RawStorageInventoryDO::getLotNo, lotNo)
.last("LIMIT 1"));
} }
} }

View File

@ -26,6 +26,7 @@ import com.ningxia.yunxi.chemmes.module.biz.service.rawstoragelog.RawStorageLogS
import com.ningxia.yunxi.chemmes.module.system.dal.dataobject.user.AdminUserDO; import com.ningxia.yunxi.chemmes.module.system.dal.dataobject.user.AdminUserDO;
import com.ningxia.yunxi.chemmes.module.system.service.user.AdminUserService; import com.ningxia.yunxi.chemmes.module.system.service.user.AdminUserService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -81,51 +82,100 @@ public class RawStorageServiceImpl implements RawStorageService {
} }
if (createReqVO.getStatus().equals("2")) { if (createReqVO.getStatus().equals("2")) {
List<RawStorageMatDO> rawStorageMatDOS = rawStorageMatMapper.selectListByStockId(rawStorage.getId()); saveStorageLog(rawStorage);
// 保存入库单
// 物料编码 批次号 存在则更新
for (RawStorageMatDO rawStorageMatDO : rawStorageMatDOS) {
RawStorageInventoryDO rawStorageInventoryDO = rawStorageInventoryService.selectByMatCodeAndBatchNo(rawStorageMatDO);
if (rawStorageInventoryDO != null) {
rawStorageInventoryDO.setYardQty(rawStorageInventoryDO.getYardQty().add(rawStorageMatDO.getPurQty()));
rawStorageInventoryDO.setUseQty(rawStorageInventoryDO.getUseQty().add(rawStorageMatDO.getPurQty()));
rawStorageInventoryService.updateRawStorageInventory(rawStorageInventoryDO);
} else {
rawStorageInventoryDO = new RawStorageInventoryDO();
rawStorageInventoryDO.setStoreHouseId(rawStorageMatDO.getStoreHouseId());
rawStorageInventoryDO.setStoreAreaId(rawStorageMatDO.getStoreAreaId());
rawStorageInventoryDO.setStoreHouseCd(rawStorageMatDO.getStoreHouseCd());
rawStorageInventoryDO.setStoreHouseName(rawStorageMatDO.getStoreHouseName());
rawStorageInventoryDO.setStoreAreCd(rawStorageMatDO.getStoreAreCd());
rawStorageInventoryDO.setStoreAreaName(rawStorageMatDO.getStoreAreaName());
rawStorageInventoryDO.setMaterialId(rawStorageMatDO.getMaterialId());
rawStorageInventoryDO.setMatName(rawStorageMatDO.getMatName());
rawStorageInventoryDO.setMatCode(rawStorageMatDO.getMatCode());
rawStorageInventoryDO.setSpec(rawStorageMatDO.getSpec());
rawStorageInventoryDO.setUnit(rawStorageMatDO.getUnit());
rawStorageInventoryDO.setLotNo(rawStorageMatDO.getLotNo());
rawStorageInventoryDO.setDescription(rawStorageMatDO.getDescription());
rawStorageInventoryDO.setYardQty(rawStorageMatDO.getPurQty());
rawStorageInventoryDO.setUseQty(rawStorageMatDO.getPurQty());
rawStorageInventoryDO.setPreQty(BigDecimal.ZERO);
// rawStorageInventoryDO.setPrice(rawStorageMatDO.getPrice());
// rawStorageInventoryDO.setPackQty(rawStorageMatDO.getPackQty());
// rawStorageInventoryDO.setBagSpec(rawStorageMatDO.getBagSpec());
// rawStorageInventoryDO.setEarStoreDate(rawStorageMatDO.getEarStoreDate());
rawStorageInventoryDO.setInventBillNo(rawStorageInventoryService.getBillNo());
rawStorageInventoryService.saveRawStorageInventory(rawStorageInventoryDO);
}
}
rawStorageLogService.saveRawStorageLog(null);
} }
// 返回 // 返回
return rawStorage.getId(); return rawStorage.getId();
} }
private void saveStorageLog(RawStorageDO rawStorage) {
List<RawStorageMatDO> rawStorageMatDOS = rawStorageMatMapper.selectListByStockId(rawStorage.getId());
// 保存入库单
String dpstNo = rawStorageLogService.generateOrderNo(rawStorage.getOperatorType());
for (RawStorageMatDO rawStorageMatDO : rawStorageMatDOS) {
RawStorageInventoryDO rawStorageInventoryDO = rawStorageInventoryService.selectByMatCodeAndBatchNo(rawStorageMatDO);
if (rawStorageInventoryDO != null) {
rawStorageInventoryDO.setYardQty(rawStorageInventoryDO.getYardQty().add(rawStorageMatDO.getOperatorQty()));
rawStorageInventoryDO.setUseQty(rawStorageInventoryDO.getUseQty().add(rawStorageMatDO.getOperatorQty()));
rawStorageInventoryService.updateRawStorageInventory(rawStorageInventoryDO);
} else {
rawStorageInventoryDO = getRawStorageInventoryDO(rawStorageMatDO);
}
rawStorageMatDO.setInventBillNo(rawStorageInventoryDO.getInventBillNo());
rawStorageMatMapper.updateById(rawStorageMatDO);
saveStorageLog(rawStorage, rawStorageMatDO, dpstNo, rawStorageInventoryDO);
}
}
@NotNull
private RawStorageInventoryDO getRawStorageInventoryDO(RawStorageMatDO rawStorageMatDO) {
RawStorageInventoryDO rawStorageInventoryDO;
rawStorageInventoryDO = new RawStorageInventoryDO();
rawStorageInventoryDO.setStoreHouseId(rawStorageMatDO.getStoreHouseId());
rawStorageInventoryDO.setStoreAreaId(rawStorageMatDO.getStoreAreaId());
rawStorageInventoryDO.setStoreHouseCd(rawStorageMatDO.getStoreHouseCd());
rawStorageInventoryDO.setStoreHouseName(rawStorageMatDO.getStoreHouseName());
rawStorageInventoryDO.setStoreAreCd(rawStorageMatDO.getStoreAreCd());
rawStorageInventoryDO.setStoreAreaName(rawStorageMatDO.getStoreAreaName());
rawStorageInventoryDO.setMaterialId(rawStorageMatDO.getMaterialId());
rawStorageInventoryDO.setMatName(rawStorageMatDO.getMatName());
rawStorageInventoryDO.setMatCode(rawStorageMatDO.getMatCode());
rawStorageInventoryDO.setSpec(rawStorageMatDO.getSpec());
rawStorageInventoryDO.setUnit(rawStorageMatDO.getUnit());
rawStorageInventoryDO.setLotNo(rawStorageMatDO.getLotNo());
rawStorageInventoryDO.setDescription(rawStorageMatDO.getDescription());
rawStorageInventoryDO.setYardQty(rawStorageMatDO.getOperatorQty());
rawStorageInventoryDO.setUseQty(rawStorageMatDO.getOperatorQty());
rawStorageInventoryDO.setPreQty(BigDecimal.ZERO);
// rawStorageInventoryDO.setPrice(rawStorageMatDO.getPrice());
// rawStorageInventoryDO.setPackQty(rawStorageMatDO.getPackQty());
// rawStorageInventoryDO.setBagSpec(rawStorageMatDO.getBagSpec());
// rawStorageInventoryDO.setEarStoreDate(rawStorageMatDO.getEarStoreDate());
rawStorageInventoryDO.setInventBillNo(rawStorageInventoryService.getBillNo());
rawStorageInventoryService.saveRawStorageInventory(rawStorageInventoryDO);
return rawStorageInventoryDO;
}
private void saveStorageLog(RawStorageDO rawStorage, RawStorageMatDO rawStorageMatDO, String dpstNo, RawStorageInventoryDO rawStorageInventoryDO) {
RawStorageLogDO rawStorageLogDO = new RawStorageLogDO();
// rawStorageLogDO.setStockId();
// rawStorageLogDO.setDescription();
rawStorageLogDO.setStatus("1");
rawStorageLogDO.setStoreHouseId(rawStorageMatDO.getStoreHouseId());
rawStorageLogDO.setStoreAreaId(rawStorageMatDO.getStoreAreaId());
rawStorageLogDO.setStoreHouseCd(rawStorageMatDO.getStoreHouseCd());
rawStorageLogDO.setStoreHouseName(rawStorageMatDO.getStoreHouseName());
rawStorageLogDO.setStoreAreCd(rawStorageMatDO.getStoreAreCd());
rawStorageLogDO.setStoreAreaName(rawStorageMatDO.getStoreAreaName());
rawStorageLogDO.setMaterialId(rawStorageMatDO.getMaterialId());
rawStorageLogDO.setMatName(rawStorageMatDO.getMatName());
rawStorageLogDO.setMatCode(rawStorageMatDO.getMatCode());
rawStorageLogDO.setSpec(rawStorageMatDO.getSpec());
rawStorageLogDO.setUnit(rawStorageMatDO.getUnit());
rawStorageLogDO.setLotNo(rawStorageMatDO.getLotNo());
rawStorageLogDO.setOperatorQty(rawStorageMatDO.getOperatorQty());
rawStorageLogDO.setOperatorType("1");
rawStorageLogDO.setBusinessType(rawStorage.getBusinessType());
// rawStorageLogDO.setStorageAft();
// rawStorageLogDO.setStorageBef();
// rawStorageLogDO.setStockItemId(rawStorageMatDO.getId());
rawStorageLogDO.setDpstNo(dpstNo);
rawStorageLogDO.setSupplierNo(rawStorage.getSupplierNo());
rawStorageLogDO.setSupplierName(rawStorage.getSupplierName());
rawStorageLogDO.setSupplierId(rawStorage.getSupplierId());
rawStorageLogDO.setOperatorQty(rawStorageMatDO.getOperatorQty());
rawStorageLogDO.setBillDate(LocalDate.now());
rawStorageLogDO.setOperatorId(rawStorage.getOperatorId());
rawStorageLogDO.setOperatorName(rawStorage.getOperatorName());
rawStorageLogDO.setRelarionNo(rawStorage.getBillNo());
rawStorageLogDO.setRelarionId(rawStorage.getId());
rawStorageLogDO.setRelarionDetailId(rawStorageMatDO.getId());
rawStorageLogDO.setInventBillNo(rawStorageInventoryDO.getInventBillNo());
rawStorageLogService.saveRawStorageLog(rawStorageLogDO);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateRawStorage(RawStorageSaveReqVO updateReqVO) { public void updateRawStorage(RawStorageSaveReqVO updateReqVO) {
@ -149,10 +199,14 @@ public class RawStorageServiceImpl implements RawStorageService {
for (RawStorageMatSaveReqVO matVO : updateReqVO.getItems()) { for (RawStorageMatSaveReqVO matVO : updateReqVO.getItems()) {
RawStorageMatDO mat = BeanUtils.toBean(matVO, RawStorageMatDO.class); RawStorageMatDO mat = BeanUtils.toBean(matVO, RawStorageMatDO.class);
mat.setStockId(updateReqVO.getId()); mat.setStockId(updateReqVO.getId());
mat.setId(null);
rawStorageMatMapper.insert(mat); rawStorageMatMapper.insert(mat);
} }
} }
} }
if ("2".equals(updateReqVO.getStatus())) {
saveStorageLog(updateObj);
}
} }
@Override @Override

View File

@ -101,6 +101,6 @@ public class RawStorageInventoryServiceImpl implements RawStorageInventoryServic
@Override @Override
public RawStorageInventoryDO selectByMatCodeAndBatchNo(RawStorageMatDO rawStorageMatDO) { public RawStorageInventoryDO selectByMatCodeAndBatchNo(RawStorageMatDO rawStorageMatDO) {
return rawStorageInventoryMapper.selectByMatCodeAndBatchNo(rawStorageMatDO.getMatCode(), return rawStorageInventoryMapper.selectByMatCodeAndBatchNo(rawStorageMatDO.getMatCode(),
rawStorageMatDO.getSpec(), rawStorageMatDO.getStoreHouseId(), rawStorageMatDO.getStoreAreaId()); rawStorageMatDO.getSpec(), rawStorageMatDO.getStoreHouseId(), rawStorageMatDO.getStoreAreaId(), rawStorageMatDO.getLotNo());
} }
} }

View File

@ -56,6 +56,8 @@ declare module 'vue' {
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow'] ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
@ -68,6 +70,7 @@ declare module 'vue' {
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload']
Error: typeof import('./../components/Error/src/Error.vue')['default'] Error: typeof import('./../components/Error/src/Error.vue')['default']
FlowCondition: typeof import('./../components/bpmnProcessDesigner/package/penal/flow-condition/FlowCondition.vue')['default'] FlowCondition: typeof import('./../components/bpmnProcessDesigner/package/penal/flow-condition/FlowCondition.vue')['default']
Form: typeof import('./../components/Form/src/Form.vue')['default'] Form: typeof import('./../components/Form/src/Form.vue')['default']
@ -88,6 +91,7 @@ declare module 'vue' {
PropertiesPanel: typeof import('./../components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue')['default'] PropertiesPanel: typeof import('./../components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue')['default']
Qrcode: typeof import('./../components/Qrcode/src/Qrcode.vue')['default'] Qrcode: typeof import('./../components/Qrcode/src/Qrcode.vue')['default']
ReceiveTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/ReceiveTask.vue')['default'] ReceiveTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/ReceiveTask.vue')['default']
Returnstorage: typeof import('./../api/biz/returnstorage/index.ts')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterSearch: typeof import('./../components/RouterSearch/index.vue')['default'] RouterSearch: typeof import('./../components/RouterSearch/index.vue')['default']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
@ -96,6 +100,7 @@ declare module 'vue' {
ShortcutDateRangePicker: typeof import('./../components/ShortcutDateRangePicker/index.vue')['default'] ShortcutDateRangePicker: typeof import('./../components/ShortcutDateRangePicker/index.vue')['default']
SignalAndMessage: typeof import('./../components/bpmnProcessDesigner/package/penal/signal-message/SignalAndMessage.vue')['default'] SignalAndMessage: typeof import('./../components/bpmnProcessDesigner/package/penal/signal-message/SignalAndMessage.vue')['default']
Sticky: typeof import('./../components/Sticky/src/Sticky.vue')['default'] Sticky: typeof import('./../components/Sticky/src/Sticky.vue')['default']
StorageSelectDialog: typeof import('./../views/biz/returnstorage/StorageSelectDialog.vue')['default']
SummaryCard: typeof import('./../components/SummaryCard/index.vue')['default'] SummaryCard: typeof import('./../components/SummaryCard/index.vue')['default']
Table: typeof import('./../components/Table/src/Table.vue')['default'] Table: typeof import('./../components/Table/src/Table.vue')['default']
Tooltip: typeof import('./../components/Tooltip/src/Tooltip.vue')['default'] Tooltip: typeof import('./../components/Tooltip/src/Tooltip.vue')['default']
@ -109,6 +114,7 @@ declare module 'vue' {
VerifyPoints: typeof import('./../components/Verifition/src/Verify/VerifyPoints.vue')['default'] VerifyPoints: typeof import('./../components/Verifition/src/Verify/VerifyPoints.vue')['default']
VerifySlide: typeof import('./../components/Verifition/src/Verify/VerifySlide.vue')['default'] VerifySlide: typeof import('./../components/Verifition/src/Verify/VerifySlide.vue')['default']
VerticalButtonGroup: typeof import('./../components/VerticalButtonGroup/index.vue')['default'] VerticalButtonGroup: typeof import('./../components/VerticalButtonGroup/index.vue')['default']
'Workspace.xml': typeof import('./../../.idea/workspace.xml.tmp')['default']
XButton: typeof import('./../components/XButton/src/XButton.vue')['default'] XButton: typeof import('./../components/XButton/src/XButton.vue')['default']
XTextButton: typeof import('./../components/XButton/src/XTextButton.vue')['default'] XTextButton: typeof import('./../components/XButton/src/XTextButton.vue')['default']
} }

View File

@ -20,13 +20,9 @@
:disabled="formType === 'detail'" :disabled="formType === 'detail'"
class="!w-full" class="!w-full"
> >
<el-option label="采购入库" value="10" /> <el-option label="其它入库" value="12" />
<el-option label="盘盈入库" value="11" /> <el-option label="盘盈入库" value="11" />
<el-option label="其它入库" value="12" />
<el-option label="生产领料" value="21" />
<el-option label="盘亏出库" value="22" />
<el-option label="采购退料" value="23" />
<el-option label="其它退料" value="24" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -80,10 +76,10 @@
<!-- 明细信息 --> <!-- 明细信息 -->
<div> <div>
<div style="font-weight: bold; margin-bottom: 15px; display: flex; justify-content: space-between; align-items: center;"> <div style="font-weight: bold; margin-bottom: 15px; display: flex; align-items: center;">
<span>明细信息</span> <span>明细信息</span>
<el-button type="primary" @click="openMaterialSelect" v-if="formType !== 'detail'"> <el-button type="primary" @click="openMaterialSelect" v-if="formType !== 'detail'">
<Icon icon="ep:plus" class="mr-1" /> 选择物料 <Icon icon="ep:plus" class="mr-5px" />新增
</el-button> </el-button>
</div> </div>
@ -110,18 +106,19 @@
<span>{{ scope.row.spec || '-' }}</span> <span>{{ scope.row.spec || '-' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="入库数量 (*)" min-width="100px" align="center"> <el-table-column label="入库数量 (*)" min-width="120px" align="center" >
<template #default="scope"> <template #default="scope" >
<MoneyInput <MoneyInput
v-model="scope.row.operatorQty" v-model="scope.row.operatorQty"
:decimal-places="2" :decimal-places="2"
:allow-negative="false" :allow-negative="false"
:show-prefix="false" :show-prefix="false"
placeholder="请输入" placeholder="请输入"
:disabled="formType === 'detail'"
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="仓储名称 (*)" min-width="120px" align="center"> <el-table-column label="仓储名称 (*)" min-width="150px" align="center">
<template #default="scope"> <template #default="scope">
<el-select <el-select
v-model="scope.row.storeHouseId" v-model="scope.row.storeHouseId"
@ -139,7 +136,7 @@
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="库区名称 (*)" min-width="120px" align="center"> <el-table-column label="库区名称 (*)" min-width="150px" align="center">
<template #default="scope"> <template #default="scope">
<el-select <el-select
v-model="scope.row.storeAreaId" v-model="scope.row.storeAreaId"
@ -161,28 +158,17 @@
<template #default="scope"> <template #default="scope">
<el-input <el-input
v-model="scope.row.lotNo" v-model="scope.row.lotNo"
placeholder="手动输入"
:disabled="formType === 'detail'" :disabled="formType === 'detail'"
class="!w-full" class="!w-full"
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="备注" min-width="120px" align="center"> <el-table-column label="单位" min-width="60px" align="center">
<template #default="scope">
<el-input
v-model="scope.row.description"
placeholder="请输入"
:disabled="formType === 'detail'"
class="!w-full"
/>
</template>
</el-table-column>
<el-table-column label="单位" min-width="60px" align="center">
<template #default="scope"> <template #default="scope">
<span>{{ getUnitName(scope.row.unit) }}</span> <span>{{ getUnitName(scope.row.unit) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" min-width="80px" align="center"> <el-table-column label="操作" min-width="70px" align="center">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link
@ -223,7 +209,6 @@
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted } from 'vue'
import Dialog from '@/components/Dialog/src/Dialog.vue' import Dialog from '@/components/Dialog/src/Dialog.vue'
import * as RawStorageApi from '@/api/biz/rawstorage' import * as RawStorageApi from '@/api/biz/rawstorage'
import * as RawStorageMatApi from '@/api/biz/rawstoragemat'
import * as WarehouseApi from '@/api/biz/storehouse' import * as WarehouseApi from '@/api/biz/storehouse'
import * as AreaApi from '@/api/biz/storearea' import * as AreaApi from '@/api/biz/storearea'
import { getUnitName } from '@/utils/dict' import { getUnitName } from '@/utils/dict'
@ -240,9 +225,8 @@ const formLoading = ref(false)
const formType = ref('') const formType = ref('')
const formRef = ref() const formRef = ref()
// //
const warehouseOptions = ref([]) const warehouseOptions = ref([])
const areaOptions = ref([])
const formData = reactive({ const formData = reactive({
id: undefined, id: undefined,
@ -280,10 +264,9 @@ const open = async (type: string, id?: number) => {
formType.value = type formType.value = type
resetForm() resetForm()
// //
await loadWarehouseList() await loadWarehouseList()
await loadAreaList()
if (id) { if (id) {
// //
formLoading.value = true formLoading.value = true
@ -291,9 +274,29 @@ const open = async (type: string, id?: number) => {
const data = await RawStorageApi.getRawStorage(id) const data = await RawStorageApi.getRawStorage(id)
Object.assign(formData, data) Object.assign(formData, data)
// //
const params = { stockId: id } detailList.value = data.items || []
const matData = await RawStorageMatApi.getRawStorageMatPage(params) //
detailList.value = matData.list || [] for (const item of detailList.value) {
// ID
if (item.storeHouseId) {
console.log('正在加载库区列表storeHouseId:', item.storeHouseId)
try {
const list = await AreaApi.getStoreAreaSelect(item.storeHouseId)
console.log('库区列表加载成功:', list)
// id
item.areaOptions = (list || []).map((area: any) => ({
...area,
id: Number(area.id)
}))
} catch (error) {
console.error('加载库区列表失败:', error)
item.areaOptions = []
}
} else {
console.log('storeHouseId为空不加载库区列表')
item.areaOptions = []
}
}
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@ -305,23 +308,16 @@ defineExpose({ open })
const loadWarehouseList = async () => { const loadWarehouseList = async () => {
try { try {
const list = await WarehouseApi.getStoreHouseSelect("1") const list = await WarehouseApi.getStoreHouseSelect("1")
warehouseOptions.value = list || [] // id
warehouseOptions.value = (list || []).map((item: any) => ({
...item,
id: Number(item.id)
}))
} catch (error) { } catch (error) {
console.error('加载仓储列表失败:', error) console.error('加载仓储列表失败:', error)
} }
} }
/** 加载库区列表 */
const loadAreaList = async (storeHouseId?: number) => {
try {
if (!storeHouseId) return
const list = await AreaApi.getStoreAreaSelect(storeHouseId)
areaOptions.value = list || []
} catch (error) {
console.error('加载库区列表失败:', error)
}
}
/** 打开物料选择弹窗 */ /** 打开物料选择弹窗 */
const openMaterialSelect = () => { const openMaterialSelect = () => {
materialSelectRef.value.open() materialSelectRef.value.open()
@ -381,7 +377,11 @@ const handleWarehouseChange = async (row: any) => {
try { try {
const list = await AreaApi.getStoreAreaSelect(row.storeHouseId) const list = await AreaApi.getStoreAreaSelect(row.storeHouseId)
row.areaOptions = list || [] // id
row.areaOptions = (list || []).map((area: any) => ({
...area,
id: Number(area.id)
}))
} catch (error) { } catch (error) {
console.error('加载库区列表失败:', error) console.error('加载库区列表失败:', error)
row.areaOptions = [] row.areaOptions = []
@ -543,6 +543,5 @@ const resetForm = () => {
/** 初始化 */ /** 初始化 */
onMounted(() => { onMounted(() => {
loadWarehouseList() loadWarehouseList()
loadAreaList()
}) })
</script> </script>

View File

@ -56,7 +56,7 @@
<ContentWrap class="!p-10px"> <ContentWrap class="!p-10px">
<div style="display: flex; flex-direction: column; height: calc(50vh - 180px);"> <div style="display: flex; flex-direction: column; height: calc(50vh - 180px);">
<div style="flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden;"> <div style="flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden;">
<div style="font-weight: bold; margin-bottom: 8px;">退料单信息</div> <div style="font-weight: bold; margin-bottom: 8px;">入库单信息</div>
<el-table <el-table
v-loading="loading" v-loading="loading"
:data="list" :data="list"
@ -76,7 +76,7 @@
<span v-else-if="scope.row.businessType === '12'">其它入库</span> <span v-else-if="scope.row.businessType === '12'">其它入库</span>
<span v-else-if="scope.row.businessType === '21'">生产领料</span> <span v-else-if="scope.row.businessType === '21'">生产领料</span>
<span v-else-if="scope.row.businessType === '22'">盘亏出库</span> <span v-else-if="scope.row.businessType === '22'">盘亏出库</span>
<span v-else-if="scope.row.businessType === '23'">采购退料</span> <span v-else-if="scope.row.businessType === '23'">标准采购退料</span>
<span v-else-if="scope.row.businessType === '24'">其它退料</span> <span v-else-if="scope.row.businessType === '24'">其它退料</span>
<span v-else>-</span> <span v-else>-</span>
</template> </template>
@ -135,7 +135,7 @@
<!-- 退料明细信息表格子表 --> <!-- 退料明细信息表格子表 -->
<ContentWrap class="!p-15px" style="height: calc(50vh - 60px);"> <ContentWrap class="!p-15px" style="height: calc(50vh - 60px);">
<div style="font-weight: bold; margin-bottom: 8px;">退料明细信息</div> <div style="font-weight: bold; margin-bottom: 8px;">入库明细信息</div>
<div style="height: calc(100% - 40px); overflow: auto;"> <div style="height: calc(100% - 40px); overflow: auto;">
<el-table <el-table
v-loading="detailLoading" v-loading="detailLoading"
@ -151,7 +151,7 @@
<el-table-column label="物料编码" align="center" prop="matCode" /> <el-table-column label="物料编码" align="center" prop="matCode" />
<el-table-column label="物料名称" align="center" prop="matName" /> <el-table-column label="物料名称" align="center" prop="matName" />
<el-table-column label="规格型号" align="center" prop="spec" /> <el-table-column label="规格型号" align="center" prop="spec" />
<el-table-column label="入库数量" align="center" prop="sourceQty" /> <el-table-column label="入库数量" align="center" prop="operatorQty" />
<el-table-column label="批次号" align="center" prop="lotNo" /> <el-table-column label="批次号" align="center" prop="lotNo" />
<el-table-column label="仓储名称" align="center" prop="storeHouseName" /> <el-table-column label="仓储名称" align="center" prop="storeHouseName" />
<el-table-column label="库区名称" align="center" prop="storeAreaName" /> <el-table-column label="库区名称" align="center" prop="storeAreaName" />

View File

@ -1,5 +1,5 @@
<template> <template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="800px"> <Dialog :title="dialogTitle" v-model="dialogVisible" width="70%">
<el-form <el-form
ref="formRef" ref="formRef"
:model="formData" :model="formData"
@ -7,104 +7,285 @@
label-width="110px" label-width="110px"
v-loading="formLoading" v-loading="formLoading"
> >
<el-form-item label="单据编号" prop="billNo"> <!-- 基本信息 -->
<el-input v-model="formData.billNo" placeholder="请输入单据编号" /> <div class="mb-6">
</el-form-item> <div style="font-weight: bold; margin-bottom: 15px;">基本信息</div>
<el-form-item label="操作类型 1为入库2为出库" prop="operatorType">
<el-radio-group v-model="formData.operatorType"> <el-row :gutter="20">
<el-radio label="1">请选择字典生成</el-radio> <el-col :span="8">
</el-radio-group> <el-form-item label="业务类型" prop="businessType">
</el-form-item> <el-select
<el-form-item label="业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料)" prop="businessType"> v-model="formData.businessType"
<el-select v-model="formData.businessType" placeholder="请选择业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料)"> placeholder="请选择"
<el-option label="请选择字典生成" value="" /> :disabled="formType === 'detail'"
</el-select> class="!w-full"
</el-form-item> >
<el-form-item label="备注" prop="remark"> <el-option label="标准采购退料" value="3" />
<el-input v-model="formData.remark" placeholder="请输入备注" /> <el-option label="设备采购退料" value="4" />
</el-form-item> </el-select>
<el-form-item label="状态1 已创建2 提交" prop="status"> </el-form-item>
<el-radio-group v-model="formData.status"> </el-col>
<el-radio label="1">请选择字典生成</el-radio> <el-col :span="8">
</el-radio-group> <el-form-item label="退料单号" prop="billNo">
</el-form-item> <el-input
<el-form-item label="供应商编码" prop="supplierNo"> v-model="formData.billNo"
<el-input v-model="formData.supplierNo" placeholder="请输入供应商编码" /> placeholder="保存时自动生成"
</el-form-item> disabled
<el-form-item label="供应商名称" prop="supplierName"> class="!w-full"
<el-input v-model="formData.supplierName" placeholder="请输入供应商名称" /> />
</el-form-item> </el-form-item>
<el-form-item label="供应商id" prop="supplierId"> </el-col>
<el-input v-model="formData.supplierId" placeholder="请输入供应商id" /> <el-col :span="8">
</el-form-item> <el-form-item label="退料日期" prop="billDate">
<el-form-item label="业务日期" prop="billDate"> <el-date-picker
<el-date-picker v-model="formData.billDate"
v-model="formData.billDate" type="date"
type="date" value-format="YYYY-MM-DD"
value-format="x" placeholder="请选择日期"
placeholder="选择业务日期" :disabled="formType === 'detail'"
/> class="!w-full"
</el-form-item> />
<el-form-item label="操作人id" prop="operatorId"> </el-form-item>
<el-input v-model="formData.operatorId" placeholder="请输入操作人id" /> </el-col>
</el-form-item> </el-row>
<el-form-item label="操作人" prop="operatorName">
<el-input v-model="formData.operatorName" placeholder="请输入操作人" /> <el-row :gutter="20">
</el-form-item> <el-col :span="8">
<el-form-item label="关联单号" prop="relarionNo"> <el-form-item label="单据状态" prop="status">
<el-input v-model="formData.relarionNo" placeholder="请输入关联单号" /> <el-select v-model="formData.status" disabled class="!w-full">
</el-form-item> <el-option label="已创建" value="1" />
<el-form-item label="关联单号id" prop="relarionId"> <el-option label="已提交" value="2" />
<el-input v-model="formData.relarionId" placeholder="请输入关联单号id" /> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="单据类型(1 标准采购申请 2设备采购申请 3 标准采购退料 4设备采购退料)" prop="billType"> </el-col>
<el-select v-model="formData.billType" placeholder="请选择单据类型(1 标准采购申请 2设备采购申请 3 标准采购退料 4设备采购退料)"> <el-col :span="8">
<el-option label="请选择字典生成" value="" /> <el-form-item label="供应商" prop="supplierName">
</el-select> <el-select
</el-form-item> v-model="formData.supplierName"
<el-form-item label="来源单号" prop="sourceNo"> placeholder="请选择"
<el-input v-model="formData.sourceNo" placeholder="请输入来源单号" /> :disabled="formType === 'detail'"
</el-form-item> class="!w-full"
<el-form-item label="来源单号id" prop="sourceId"> filterable
<el-input v-model="formData.sourceId" placeholder="请输入来源单号id" /> >
</el-form-item> <el-option
v-for="item in supplierOptions"
:key="item.id"
:label="item.supplierName"
:value="item.supplierName"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购入库单" prop="relarionNo">
<el-input
v-model="formData.relarionNo"
placeholder="点击选择入库单"
:disabled="formType === 'detail'"
class="!w-full"
@click="openStorageSelect"
readonly
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input
v-model="formData.remark"
placeholder="请输入"
:disabled="formType === 'detail'"
class="!w-full"
type="textarea"
:rows="2"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 明细信息 -->
<div>
<div style="font-weight: bold; margin-bottom: 15px; display: flex; align-items: center;">
<el-button type="primary" @click="openMaterialSelect" v-if="formType !== 'detail'">
<Icon icon="ep:plus" class="mr-1" /> 选择物料
</el-button>
<span style="margin-left: 10px;">明细信息</span>
</div>
<el-table
:data="detailList"
:stripe="true"
:show-overflow-tooltip="true"
border
style="width: 100%;"
>
<el-table-column label="序号" type="index" min-width="60px" align="center" />
<el-table-column label="物料编码" min-width="120px" align="center">
<template #default="scope">
<span>{{ scope.row.matCode || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="物料名称" min-width="150px" align="center">
<template #default="scope">
<span>{{ scope.row.matName || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="规格型号" min-width="100px" align="center">
<template #default="scope">
<span>{{ scope.row.spec || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="收货数量" min-width="100px" align="center">
<template #default="scope">
<span>{{ scope.row.sourceQty || '0' }}</span>
</template>
</el-table-column>
<el-table-column label="已退料数量" min-width="100px" align="center">
<template #default="scope">
<span>{{ scope.row.returnedQty || '0' }}</span>
</template>
</el-table-column>
<el-table-column label="*退料数量" min-width="120px" align="center" >
<template #default="scope" >
<MoneyInput
v-model="scope.row.returnQty"
:decimal-places="2"
:allow-negative="false"
:show-prefix="false"
placeholder="手动输入"
:disabled="formType === 'detail'"
/>
</template>
</el-table-column>
<el-table-column label="批次号" min-width="100px" align="center">
<template #default="scope">
<span>{{ scope.row.lotNo || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="仓储名称" min-width="120px" align="center">
<template #default="scope">
<span>{{ scope.row.storeHouseName || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="库区名称" min-width="120px" align="center">
<template #default="scope">
<span>{{ scope.row.storeAreaName || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="入库日期" min-width="110px" align="center">
<template #default="scope">
<span>{{ scope.row.inDate || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="单位" min-width="80px" align="center">
<template #default="scope">
<span>{{ getUnitName(scope.row.unit) }}</span>
</template>
</el-table-column>
<el-table-column label="存货账单号" min-width="120px" align="center">
<template #default="scope">
<span>{{ scope.row.inventBillNo || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="操作" min-width="80px" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="formType !== 'detail'"
type="danger"
link
@click="handleDeleteDetail(scope.$index)"
>
<Icon icon="ep:delete" class="mr-1" /> 删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button> <el-button @click="dialogVisible = false">取消</el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button
v-if="formType !== 'detail'"
type="primary"
@click="handleSubmit('save')"
:loading="formLoading"
>
保存
</el-button>
<el-button
v-if="formType !== 'detail'"
type="primary"
@click="handleSubmit('confirm')"
:loading="formLoading"
>
确认
</el-button>
</template> </template>
</Dialog> </Dialog>
<!-- 物料选择弹窗 -->
<MaterialSelectDialog ref="materialSelectRef" @confirm="handleMaterialConfirm" />
<!-- 入库单选择弹窗 -->
<StorageSelectDialog ref="storageSelectRef" @confirm="handleStorageConfirm" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import * as RawStorageApi from '@/api/biz/rawstorage' import { ref, reactive, onMounted } from 'vue'
import { watch } from 'vue' import Dialog from '@/components/Dialog/src/Dialog.vue'
import MoneyInput from '@/components/MoneyInput/src/MoneyInput.vue'
import MaterialSelectDialog from './MaterialSelectDialog.vue'
import StorageSelectDialog from './StorageSelectDialog.vue'
import * as ReturnStorageApi from '@/api/biz/returnstorage'
import { getUnitName } from '@/utils/dict'
const { t } = useI18n() // defineOptions({ name: 'ReturnStorageForm' })
const message = useMessage() //
const dialogVisible = ref(false) // const { t } = useI18n()
const dialogTitle = ref('') // const message = useMessage()
const formLoading = ref(false) // 12
const formType = ref('') // create - update - const dialogVisible = ref(false)
const formData = ref({ const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
const formRef = ref()
//
const formData = reactive({
id: undefined, id: undefined,
billNo: undefined, billNo: '保存时自动生成',
operatorType: undefined, businessType: "3",
businessType: undefined, billDate: new Date().toISOString().split('T')[0],
remark: undefined, status: '1',
status: undefined,
supplierNo: undefined,
supplierName: undefined, supplierName: undefined,
supplierId: undefined, supplierId: undefined,
billDate: undefined,
operatorId: undefined,
operatorName: undefined,
relarionNo: undefined, relarionNo: undefined,
relarionId: undefined, relarionId: undefined,
billType: undefined, remark: undefined,
sourceNo: undefined,
sourceId: undefined,
}) })
//
const formRules = reactive({
businessType: [{ required: true, message: '请选择业务类型', trigger: 'change' }],
billDate: [{ required: true, message: '请选择退料日期', trigger: 'change' }],
})
//
const detailList = ref<any[]>([])
//
const warehouseOptions = ref([])
//
const supplierOptions = ref([])
// Ref
const materialSelectRef = ref()
const storageSelectRef = ref()
/** 弹窗关闭时通知父组件 */ /** 弹窗关闭时通知父组件 */
watch(dialogVisible, (val) => { watch(dialogVisible, (val) => {
if (!val) { if (!val) {
@ -112,49 +293,237 @@ watch(dialogVisible, (val) => {
} }
}) })
const formRules = reactive({
billNo: [{ required: true, message: '单据编号不能为空', trigger: 'blur' }],
operatorType: [{ required: true, message: '操作类型 1为入库2为出库不能为空', trigger: 'blur' }],
})
const formRef = ref() // Ref
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (type: string, id?: number) => { const open = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
dialogTitle.value = t('action.' + type) dialogTitle.value = type === 'create' ? '新增' : type === 'update' ? '编辑' : '详情'
formType.value = type formType.value = type
resetForm() resetForm()
//
await loadWarehouseList()
if (id) { if (id) {
formLoading.value = true formLoading.value = true
try { try {
formData.value = await RawStorageApi.getRawStorage(id) const data = await ReturnStorageApi.getReturnStorage(id)
Object.assign(formData, data)
detailList.value = data.items || []
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
} }
} }
defineExpose({ open }) // open defineExpose({ open })
/** 加载仓储列表 */
const loadWarehouseList = async () => {
try {
const data = await ReturnStorageApi.getWarehouseSelect()
warehouseOptions.value = data.list || []
} catch (error) {
console.error('加载仓储列表失败:', error)
}
}
/** 加载供应商列表 */
const loadSupplierList = async () => {
try {
const data = await ReturnStorageApi.getSupplierSelect()
supplierOptions.value = data.list || []
} catch (error) {
console.error('加载供应商列表失败:', error)
}
}
/** 打开物料选择弹窗 */
const openMaterialSelect = () => {
materialSelectRef.value.open()
}
/** 打开入库单选择弹窗 */
const openStorageSelect = () => {
storageSelectRef.value.open()
}
/** 处理物料确认选择 */
const handleMaterialConfirm = (selectedMaterials: any[]) => {
selectedMaterials.forEach((material) => {
const exists = detailList.value.some(
(item) => item.materialId === material.id,
)
if (!exists) {
detailList.value.push({
id: undefined,
description: undefined,
storeHouseId: undefined,
storeAreaId: undefined,
storeHouseCd: undefined,
storeHouseName: undefined,
storeAreCd: undefined,
storeAreaName: undefined,
materialId: material.id,
matName: material.matName,
matCode: material.matCode,
spec: material.spec,
unit: material.unit,
lotNo: undefined,
returnQty: undefined,
sourceQty: material.purQty || 0,
returnedQty: 0,
inDate: material.inDate,
inventBillNo: material.inventBillNo,
sourceId: undefined,
relarionId: undefined,
areaOptions: [],
})
}
})
}
/** 处理入库单确认选择 */
const handleStorageConfirm = (storages: any[]) => {
//
detailList.value = []
//
formData.relarionNo = storages[0]?.billNo || ''
formData.relarionId = storages[0]?.stockId || ''
//
storages.forEach((storage) => {
detailList.value.push({
id: storage.id,
description: undefined,
storeHouseId: storage.storeHouseId,
storeAreaId: storage.storeAreaId,
storeHouseCd: storage.storeHouseCd,
storeHouseName: storage.storeHouseName,
storeAreCd: storage.storeAreCd,
storeAreaName: storage.storeAreaName,
materialId: storage.materialId,
matName: storage.matName,
matCode: storage.matCode,
spec: storage.spec,
unit: storage.unit,
lotNo: storage.lotNo,
returnQty: undefined,
sourceQty: storage.operatorQty || 0,
returnedQty: storage.returnedQty || 0,
inDate: storage.billDate,
inventBillNo: storage.inventBillNo,
sourceId: storage.stockId,
relarionId: storage.stockId,
areaOptions: [],
})
})
}
/** 删除明细 */
const handleDeleteDetail = (index: number) => {
detailList.value.splice(index, 1)
}
/** 处理仓储变化,重新加载库区 */
const handleWarehouseChange = async (row: any) => {
row.storeAreaId = undefined
row.storeAreaName = undefined
row.storeAreCd = undefined
if (row.storeHouseId) {
const warehouse = warehouseOptions.value.find((w: any) => w.id === row.storeHouseId)
if (warehouse) {
row.storeHouseCd = warehouse.storeHouseCd
row.storeHouseName = warehouse.storeHouseName
}
try {
const list = await AreaApi.getStoreArea(row.storeHouseId)
row.areaOptions = (list || []).map((area: any) => ({
...area,
id: Number(area.id)
}))
} catch (error) {
console.error('加载库区列表失败:', error)
row.areaOptions = []
}
} else {
row.areaOptions = []
row.storeHouseCd = undefined
row.storeHouseName = undefined
}
}
/** 处理库区变化 */
const handleAreaChange = (row: any) => {
const area = row.areaOptions?.find((a: any) => a.id === row.storeAreaId)
if (area) {
row.storeAreCd = area.storeAreCd
row.storeAreaName = area.storeAreaName
}
}
/** 提交表单 */ /** 提交表单 */
const emit = defineEmits(['success', 'close']) // success const emit = defineEmits(['success', 'close'])
const submitForm = async () => {
const handleSubmit = async (action: string) => {
// //
await formRef.value.validate() await formRef.value.validate()
//
//
if (detailList.value.length === 0) {
message.error('请至少添加一条明细')
return
}
// 退
for (const item of detailList.value) {
if (!item.returnQty || item.returnQty <= 0) {
message.error('请完善退料数量')
return
}
// 退 + 退 <=
const totalReturn = (item.returnQty || 0) + (item.returnedQty || 0)
if (totalReturn > (item.sourceQty || 0)) {
message.error(`退料数量 + 已退料数量不能大于入库数量(${item.matName}`)
return
}
}
formLoading.value = true formLoading.value = true
try { try {
const data = formData.value as unknown as RawStorageApi.RawStorageVO const submitData = {
if (formType.value === 'create') { ...formData,
await RawStorageApi.createRawStorage(data) items: detailList.value.map(item => ({
message.success(t('common.createSuccess')) ...item,
} else { areaOptions: undefined //
await RawStorageApi.updateRawStorage(data) }))
message.success(t('common.updateSuccess'))
} }
if (action === 'save') {
if (formType.value === 'create') {
await ReturnStorageApi.createReturnStorage(submitData)
message.success(t('common.createSuccess'))
} else {
await ReturnStorageApi.updateReturnStorage(submitData)
message.success(t('common.updateSuccess'))
}
} else {
//
if (formType.value === 'create') {
await ReturnStorageApi.confirmReturnStorage(submitData)
message.success('确认成功')
} else {
await ReturnStorageApi.confirmReturnStorage(submitData)
message.success('确认成功')
}
}
dialogVisible.value = false dialogVisible.value = false
//
emit('success') emit('success')
} catch (error) {
console.error('提交失败:', error)
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@ -162,25 +531,25 @@ const submitForm = async () => {
/** 重置表单 */ /** 重置表单 */
const resetForm = () => { const resetForm = () => {
formData.value = { Object.assign(formData, {
id: undefined, id: undefined,
billNo: undefined, billNo: '保存时自动生成',
operatorType: undefined, businessType: "3",
businessType: undefined, billDate: new Date().toISOString().split('T')[0],
remark: undefined, status: '1',
status: undefined,
supplierNo: undefined,
supplierName: undefined, supplierName: undefined,
supplierId: undefined, supplierId: undefined,
billDate: undefined,
operatorId: undefined,
operatorName: undefined,
relarionNo: undefined, relarionNo: undefined,
relarionId: undefined, relarionId: undefined,
billType: undefined, remark: undefined,
sourceNo: undefined, })
sourceId: undefined, detailList.value = []
}
formRef.value?.resetFields() formRef.value?.resetFields()
} }
/** 初始化 */
onMounted(() => {
loadWarehouseList()
loadSupplierList()
})
</script> </script>

View File

@ -0,0 +1,150 @@
<template>
<Dialog :title="'选择入库单'" v-model="dialogVisible" width="90%">
<el-form :model="queryParams" inline label-width="80px">
<el-form-item label="入库单号">
<el-input
v-model="queryParams.billNo"
placeholder="请输入"
clearable
@keyup.enter="getList"
class="!w-200px"
/>
</el-form-item>
<el-form-item label="物料名称">
<el-input
v-model="queryParams.matName"
placeholder="请输入"
clearable
@keyup.enter="getList"
class="!w-200px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getList"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form>
<div style="max-height: 500px; overflow-y: auto; margin-top: 15px;">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
border
:highlight-current-row="true"
@selection-change="handleSelectionChange"
@row-dblclick="handleRowDoubleClick"
style="width: 100%;"
>
<el-table-column type="selection" width="45px" align="center" />
<el-table-column label="序号" type="index" width="60px" align="center" />
<el-table-column label="入库单号" align="center" prop="billNo" />
<el-table-column label="单据类型" align="center" prop="businessType" width="100px">
<template #default="scope">
<span v-if="scope.row.businessType === '10'">采购入库</span>
<span v-else-if="scope.row.businessType === '11'">盘盈入库</span>
<span v-else-if="scope.row.businessType === '12'">其它入库</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="入库日期" align="center" prop="billDate" width="110px" />
<el-table-column label="物料编码" align="center" prop="matCode" />
<el-table-column label="物料名称" align="center" prop="matName" />
<el-table-column label="入库数量" align="center" prop="operatorQty" />
<el-table-column label="已退货数量" align="center" prop="returnQty" />
<el-table-column label="规格型号" align="center" prop="spec" />
<el-table-column label="批次号" align="center" prop="lotNo" />
<el-table-column label="仓储名称" align="center" prop="storeHouseName" />
<el-table-column label="库区名称" align="center" prop="storeAreaName" />
<el-table-column label="存货账单号" align="center" prop="inventBillNo" />
</el-table>
</div>
<div style="display: flex; justify-content: flex-end; margin-top: 10px;">
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleConfirm" :disabled="selectedItems.length === 0">保存</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import Dialog from '@/components/Dialog/src/Dialog.vue'
import Pagination from '@/components/Pagination/index.vue'
import * as RawStorageMatApi from '@/api/biz/rawstoragemat'
const dialogVisible = ref(false)
const loading = ref(false)
const list = ref([])
const total = ref(0)
const selectedItems = ref([])
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
billNo: undefined,
matName: undefined,
})
const emit = defineEmits(['confirm'])
const open = () => {
dialogVisible.value = true
selectedItems.value = []
getList()
}
defineExpose({ open })
const getList = async () => {
loading.value = true
try {
const data = await RawStorageMatApi.getRawStorageMatPage(queryParams)
list.value = data.list || []
total.value = data.total || 0
} catch (error) {
console.error('获取入库物料明细列表失败:', error)
list.value = []
total.value = 0
} finally {
loading.value = false
}
}
const resetQuery = () => {
queryParams.billNo = undefined
queryParams.matName = undefined
queryParams.pageNo = 1
getList()
}
const handleSelectionChange = (val: any[]) => {
selectedItems.value = val
}
const handleRowDoubleClick = (row: any) => {
selectedItems.value = [row]
emit('confirm', [row])
dialogVisible.value = false
}
const handleConfirm = () => {
if (selectedItems.value.length > 0) {
emit('confirm', selectedItems.value)
dialogVisible.value = false
}
}
onMounted(() => {
getList()
})
</script>

View File

@ -21,7 +21,16 @@
<el-form-item label="退料单号" prop="billNo"> <el-form-item label="退料单号" prop="billNo">
<el-input <el-input
v-model="queryParams.billNo" v-model="queryParams.billNo"
placeholder="请输入退料单号" placeholder="请输入"
clearable
@keyup.enter="handleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item label="供应商" prop="supplierName">
<el-input
v-model="queryParams.supplierName"
placeholder="请输入"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
class="!w-200px" class="!w-200px"
@ -30,7 +39,7 @@
<el-form-item label="单据状态" prop="status"> <el-form-item label="单据状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="请选择单据状态" placeholder="请选择"
clearable clearable
class="!w-150px" class="!w-150px"
> >
@ -41,6 +50,8 @@
<el-form-item> <el-form-item>
<el-button type="primary" @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button type="primary" @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
<el-form-item>
<el-button <el-button
type="primary" type="primary"
@click="openForm('create')" @click="openForm('create')"
@ -69,13 +80,14 @@
max-height="100%" max-height="100%"
> >
<el-table-column label="序号" align="center" type="index" width="60px"/> <el-table-column label="序号" align="center" type="index" width="60px"/>
<el-table-column label="业务类型" align="center" prop="businessType" > <el-table-column label="单据类型" align="center" prop="businessType" >
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.businessType === '23'">标准采购退料</span> <span v-if="scope.row.businessType === '23'">标准采购退料</span>
<span v-else>-</span> <span v-else>-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="退料单号" align="center" prop="billNo" /> <el-table-column label="退料单号" align="center" prop="billNo" />
<el-table-column label="供应商" align="center" prop="supplierName" />
<el-table-column label="单据状态" align="center" prop="status" > <el-table-column label="单据状态" align="center" prop="status" >
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.status === '1'" class="text-blue">已创建</span> <span v-if="scope.row.status === '1'" class="text-blue">已创建</span>
@ -85,7 +97,7 @@
</el-table-column> </el-table-column>
<el-table-column label="退料日期" align="center" prop="billDate" /> <el-table-column label="退料日期" align="center" prop="billDate" />
<el-table-column label="退料人员" align="center" prop="operatorName" /> <el-table-column label="退料人员" align="center" prop="operatorName" />
<el-table-column label="其它入库单号" align="center" prop="relarionNo" /> <el-table-column label="采购入库单号" align="center" prop="relarionNo" />
<el-table-column label="操作" align="center" > <el-table-column label="操作" align="center" >
<template #default="scope"> <template #default="scope">
<el-button <el-button
@ -143,10 +155,10 @@
style="width: 100%;" style="width: 100%;"
> >
<el-table-column label="序号" align="center" type="index" width="60px"/> <el-table-column label="序号" align="center" type="index" width="60px"/>
<el-table-column label="物料编码" align="center" prop="materialCode" /> <el-table-column label="物料编码" align="center" prop="matCode" />
<el-table-column label="物料名称" align="center" prop="materialName" /> <el-table-column label="物料名称" align="center" prop="matName" />
<el-table-column label="规格型号" align="center" prop="spec" /> <el-table-column label="规格型号" align="center" prop="spec" />
<el-table-column label="来源数量" align="center" prop="sourceQty" /> <el-table-column label="收货数量" align="center" prop="sourceQty" />
<el-table-column label="已退料数量" align="center" prop="returnedQty" /> <el-table-column label="已退料数量" align="center" prop="returnedQty" />
<el-table-column label="退料数量" align="center" prop="returnQty" /> <el-table-column label="退料数量" align="center" prop="returnQty" />
<el-table-column label="批次号" align="center" prop="lotNo" /> <el-table-column label="批次号" align="center" prop="lotNo" />
@ -163,11 +175,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted } from 'vue'
import * as RawStorageApi from '@/api/biz/rawstorage' import * as ReturnStorageApi from '@/api/biz/returnstorage'
import RawStorageForm from './RawStorageForm.vue' import ReturnStorageForm from './ReturnStorageForm.vue'
import { getUnitName } from '@/utils/dict' import { getUnitName } from '@/utils/dict'
defineOptions({ name: 'RawStorage' }) defineOptions({ name: 'ReturnStorage' })
const message = useMessage() // const message = useMessage() //
const { t } = useI18n() // const { t } = useI18n() //
@ -191,7 +203,7 @@ const queryFormRef = ref() // 搜索的表单
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const data = await RawStorageApi.getRawStoragePage(queryParams) const data = await ReturnStorageApi.getReturnStoragePage(queryParams)
list.value = data.list list.value = data.list
total.value = data.total total.value = data.total
// //
@ -208,7 +220,7 @@ const getDetailList = async (id: number) => {
detailLoading.value = true detailLoading.value = true
try { try {
// 退ID // 退ID
const data = await RawStorageApi.getRawStorage(id) const data = await ReturnStorageApi.getReturnStorage(id)
// items // items
detailList.value = data?.items || [] detailList.value = data?.items || []
} catch (error) { } catch (error) {
@ -270,12 +282,12 @@ const getDetailSummary = (param: any) => {
columns.forEach((column: any, index: number) => { columns.forEach((column: any, index: number) => {
if (index === 0) { if (index === 0) {
sums[index] = '合计' sums[index] = '合计'
} else if (index === 4) { } else if (index === 5) {
// 5 // 6
const total = data.reduce((sum: number, item: any) => sum + (Number(item.sourceQty) || 0), 0) const total = data.reduce((sum: number, item: any) => sum + (Number(item.sourceQty) || 0), 0)
sums[index] = total sums[index] = total
} else if (index === 6) { } else if (index === 7) {
// 7退 // 8 退
const total = data.reduce((sum: number, item: any) => sum + (Number(item.returnQty) || 0), 0) const total = data.reduce((sum: number, item: any) => sum + (Number(item.returnQty) || 0), 0)
sums[index] = total sums[index] = total
} else { } else {