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

This commit is contained in:
zxy 2026-06-01 17:11:19 +08:00
parent 8c0e19372c
commit cb588a8386
9 changed files with 155 additions and 193 deletions

View File

@ -74,8 +74,8 @@ public class RawStorageMatController {
@Operation(summary = "获得原料入/出库物料分页")
@PreAuthorize("@ss.hasPermission('twm:raw-storage-mat:query')")
public CommonResult<PageResult<RawStorageMatRespVO>> getRawStorageMatPage(@Valid RawStorageMatPageReqVO pageReqVO) {
PageResult<RawStorageMatDO> pageResult = rawStorageMatService.getRawStorageMatPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RawStorageMatRespVO.class));
PageResult<RawStorageMatRespVO> pageResult = rawStorageMatService.getRawStorageMatPage(pageReqVO);
return success(pageResult);
}
@GetMapping("/export-excel")
@ -85,7 +85,7 @@ public class RawStorageMatController {
public void exportRawStorageMatExcel(@Valid RawStorageMatPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<RawStorageMatDO> list = rawStorageMatService.getRawStorageMatPage(pageReqVO).getList();
List<RawStorageMatRespVO> list = rawStorageMatService.getRawStorageMatPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "原料入/出库物料.xls", "数据", RawStorageMatRespVO.class,
BeanUtils.toBean(list, RawStorageMatRespVO.class));

View File

@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 原料入/出库物料 Response VO")
@ -22,6 +23,23 @@ public class RawStorageMatRespVO {
@ExcelProperty("入/出库Id")
private Long stockId;
@Schema(description = "操作类型")
@ExcelProperty("操作类型")
private String operatorType;
@Schema(description = "业务类型")
@ExcelProperty("业务类型")
private String businessType;
@Schema(description = "单据编号")
@ExcelProperty("单据编号")
private String billNo;
@Schema(description = "单据日期")
@ExcelProperty("单据日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private LocalDate billDate;
@Schema(description = "备注", example = "你猜")
@ExcelProperty("备注")
private String description;
@ -103,4 +121,6 @@ public class RawStorageMatRespVO {
@ExcelProperty("存货账单号")
private String inventBillNo;
private BigDecimal returnQty;
}

View File

@ -1,10 +1,15 @@
package com.ningxia.yunxi.chemmes.module.biz.dal.mysql.rawstoragemat;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.ningxia.yunxi.chemmes.framework.common.pojo.PageResult;
import com.ningxia.yunxi.chemmes.framework.mybatis.core.mapper.BaseMapperX;
import com.ningxia.yunxi.chemmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.rawstoragemat.vo.RawStorageMatPageReqVO;
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.rawstoragemat.vo.RawStorageMatRespVO;
import com.ningxia.yunxi.chemmes.module.biz.dal.dataobject.rawstorage.RawStorageDO;
import com.ningxia.yunxi.chemmes.module.biz.dal.dataobject.rawstoragemat.RawStorageMatDO;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@ -17,30 +22,40 @@ import java.util.List;
@Mapper
public interface RawStorageMatMapper extends BaseMapperX<RawStorageMatDO> {
default PageResult<RawStorageMatDO> selectPage(RawStorageMatPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<RawStorageMatDO>()
.eqIfPresent(RawStorageMatDO::getStockId, reqVO.getStockId())
.eqIfPresent(RawStorageMatDO::getDescription, reqVO.getDescription())
.betweenIfPresent(RawStorageMatDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(RawStorageMatDO::getStoreHouseId, reqVO.getStoreHouseId())
.eqIfPresent(RawStorageMatDO::getStoreAreaId, reqVO.getStoreAreaId())
.eqIfPresent(RawStorageMatDO::getStoreHouseCd, reqVO.getStoreHouseCd())
.likeIfPresent(RawStorageMatDO::getStoreHouseName, reqVO.getStoreHouseName())
.eqIfPresent(RawStorageMatDO::getStoreAreCd, reqVO.getStoreAreCd())
.likeIfPresent(RawStorageMatDO::getStoreAreaName, reqVO.getStoreAreaName())
.eqIfPresent(RawStorageMatDO::getMaterialId, reqVO.getMaterialId())
.likeIfPresent(RawStorageMatDO::getMatName, reqVO.getMatName())
.eqIfPresent(RawStorageMatDO::getMatCode, reqVO.getMatCode())
.eqIfPresent(RawStorageMatDO::getSpec, reqVO.getSpec())
.eqIfPresent(RawStorageMatDO::getUnit, reqVO.getUnit())
.eqIfPresent(RawStorageMatDO::getLotNo, reqVO.getLotNo())
.eqIfPresent(RawStorageMatDO::getOperatorQty, reqVO.getOperatorQty())
.eqIfPresent(RawStorageMatDO::getPurQty, reqVO.getPurQty())
.eqIfPresent(RawStorageMatDO::getSourceQty, reqVO.getSourceQty())
.eqIfPresent(RawStorageMatDO::getSourceId, reqVO.getSourceId())
.eqIfPresent(RawStorageMatDO::getRelarionId, reqVO.getRelarionId())
.eqIfPresent(RawStorageMatDO::getInventBillNo, reqVO.getInventBillNo())
.orderByDesc(RawStorageMatDO::getId));
default PageResult<RawStorageMatRespVO> selectPage(RawStorageMatPageReqVO reqVO) {
MPJLambdaWrapper<RawStorageMatDO> wrapper = new MPJLambdaWrapper<RawStorageMatDO>()
// 选择子表字段
.selectAll(RawStorageMatDO.class)
// 选择主表字段
.selectAs(RawStorageDO::getBillNo, RawStorageMatRespVO::getBillNo)
.selectAs(RawStorageDO::getOperatorType, RawStorageMatRespVO::getOperatorType)
.selectAs(RawStorageDO::getBusinessType, RawStorageMatRespVO::getBusinessType)
.selectAs(RawStorageDO::getBillDate, RawStorageMatRespVO::getBillDate)
// LEFT JOIN 主表
.leftJoin(RawStorageDO.class, RawStorageDO::getId, RawStorageMatDO::getStockId)
// 查询条件 - 子表
.eq(reqVO.getStoreHouseId() != null, RawStorageMatDO::getStoreHouseId, reqVO.getStoreHouseId())
.eq(reqVO.getStoreAreaId() != null, RawStorageMatDO::getStoreAreaId, reqVO.getStoreAreaId())
.eq(StringUtils.isNotBlank(reqVO.getStoreHouseCd()), RawStorageMatDO::getStoreHouseCd, reqVO.getStoreHouseCd())
.like(StringUtils.isNotBlank(reqVO.getStoreHouseName()), RawStorageMatDO::getStoreHouseName, reqVO.getStoreHouseName())
.eq(StringUtils.isNotBlank(reqVO.getStoreAreCd()), RawStorageMatDO::getStoreAreCd, reqVO.getStoreAreCd())
.like(StringUtils.isNotBlank(reqVO.getStoreAreaName()), RawStorageMatDO::getStoreAreaName, reqVO.getStoreAreaName())
.like(StringUtils.isNotBlank(reqVO.getMatName()), RawStorageMatDO::getMatName, reqVO.getMatName())
.eq(StringUtils.isNotBlank(reqVO.getMatCode()), RawStorageMatDO::getMatCode, reqVO.getMatCode())
.eq(StringUtils.isNotBlank(reqVO.getInventBillNo()), RawStorageMatDO::getInventBillNo, reqVO.getInventBillNo())
// 查询条件 - 主表
.like(StringUtils.isNotBlank(reqVO.getBillNo()), RawStorageDO::getBillNo, reqVO.getBillNo())
.orderByDesc(RawStorageMatDO::getId);
return selectJoinPage(reqVO, RawStorageMatRespVO.class, wrapper);
}
/**
* 关联分页查询
*/
default <V> PageResult<V> selectJoinPage(RawStorageMatPageReqVO reqVO, Class<V> clazz, MPJLambdaWrapper<RawStorageMatDO> wrapper) {
Page<V> page = selectJoinPage(new Page<>(reqVO.getPageNo(), reqVO.getPageSize()), clazz, wrapper);
return new PageResult<>(page.getRecords(), page.getTotal());
}
default int deleteByStockId(Integer stockId) {

View File

@ -2,6 +2,7 @@ package com.ningxia.yunxi.chemmes.module.biz.service.rawstoragemat;
import com.ningxia.yunxi.chemmes.framework.common.pojo.PageResult;
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.rawstoragemat.vo.RawStorageMatPageReqVO;
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.rawstoragemat.vo.RawStorageMatRespVO;
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.rawstoragemat.vo.RawStorageMatSaveReqVO;
import com.ningxia.yunxi.chemmes.module.biz.dal.dataobject.rawstoragemat.RawStorageMatDO;
@ -50,6 +51,6 @@ public interface RawStorageMatService {
* @param pageReqVO 分页查询
* @return 原料入/出库物料分页
*/
PageResult<RawStorageMatDO> getRawStorageMatPage(RawStorageMatPageReqVO pageReqVO);
PageResult<RawStorageMatRespVO> getRawStorageMatPage(RawStorageMatPageReqVO pageReqVO);
}

View File

@ -3,6 +3,7 @@ package com.ningxia.yunxi.chemmes.module.biz.service.rawstoragemat;
import com.ningxia.yunxi.chemmes.framework.common.pojo.PageResult;
import com.ningxia.yunxi.chemmes.framework.common.util.object.BeanUtils;
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.rawstoragemat.vo.RawStorageMatPageReqVO;
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.rawstoragemat.vo.RawStorageMatRespVO;
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.rawstoragemat.vo.RawStorageMatSaveReqVO;
import com.ningxia.yunxi.chemmes.module.biz.dal.dataobject.rawstoragemat.RawStorageMatDO;
import com.ningxia.yunxi.chemmes.module.biz.dal.mysql.rawstoragemat.RawStorageMatMapper;
@ -63,7 +64,7 @@ public class RawStorageMatServiceImpl implements RawStorageMatService {
}
@Override
public PageResult<RawStorageMatDO> getRawStorageMatPage(RawStorageMatPageReqVO pageReqVO) {
public PageResult<RawStorageMatRespVO> getRawStorageMatPage(RawStorageMatPageReqVO pageReqVO) {
return rawStorageMatMapper.selectPage(pageReqVO);
}

View File

@ -1,51 +1,66 @@
import request from '@/config/axios'
export interface RawStorageVO {
id: number
billNo: string
operatorType: boolean
businessType: number
remark: string
status: boolean
supplierNo: string
supplierName: string
supplierId: number
billDate: localdate
operatorId: number
operatorName: string
relarionNo: string
relarionId: number
billType: string
sourceNo: string
sourceId: number
}
// 查询原料入/出库分页
export const getRawStoragePage = async (params) => {
return await request.get({ url: `/twm/raw-storage/page`, params })
}
// 查询原料入/出库详情
export const getRawStorage = async (id: number) => {
return await request.get({ url: `/twm/raw-storage/get?id=` + id })
}
// 新增原料入/出库
export const createRawStorage = async (data: RawStorageVO) => {
return await request.post({ url: `/twm/raw-storage/create`, data })
}
// 修改原料入/出库
export const updateRawStorage = async (data: RawStorageVO) => {
return await request.put({ url: `/twm/raw-storage/update`, data })
}
// 删除原料入/出库
export const deleteRawStorage = async (id: number) => {
return await request.delete({ url: `/twm/raw-storage/delete?id=` + id })
}
// 导出原料入/出库 Excel
export const exportRawStorage = async (params) => {
return await request.download({ url: `/twm/raw-storage/export-excel`, params })
}
import request from '@/config/axios'
export interface RawStorageVO {
id: number
billNo: string
operatorType: boolean
businessType: number
remark: string
status: boolean
supplierNo: string
supplierName: string
supplierId: number
billDate: localdate
operatorId: number
operatorName: string
relarionNo: string
relarionId: number
billType: string
sourceNo: string
sourceId: number
}
// 查询原料入/出库分页
export const getRawStoragePage = async (params) => {
return await request.get({ url: `/twm/raw-storage/page`, params })
}
// 查询原料入/出库详情
export const getRawStorage = async (id: number) => {
return await request.get({ url: `/twm/raw-storage/get?id=` + id })
}
// 新增原料入/出库
export const createRawStorage = async (data: RawStorageVO) => {
return await request.post({ url: `/twm/raw-storage/create`, data })
}
// 修改原料入/出库
export const updateRawStorage = async (data: RawStorageVO) => {
return await request.put({ url: `/twm/raw-storage/update`, data })
}
// 删除原料入/出库
export const deleteRawStorage = async (id: number) => {
return await request.delete({ url: `/twm/raw-storage/delete?id=` + id })
}
// 导出原料入/出库 Excel
export const exportRawStorage = async (params) => {
return await request.download({ url: `/twm/raw-storage/export-excel`, params })
}
// 确认原料入/出库
export const confirmRawStorage = async (data: RawStorageVO) => {
return await request.post({ url: `/twm/raw-storage/confirm`, data })
}
// 获取仓储下拉列表
export const getWarehouseSelect = async () => {
return await request.get({ url: `/twm/store-house/list`, params: { enabledStatus: 1 } })
}
// 获取供应商下拉列表
export const getSupplierSelect = async () => {
return await request.get({ url: `/ims/supplier/getPopupListByOsm`, params: { enabledStatus: 1 } })
}

View File

@ -31,6 +31,7 @@ declare module 'vue' {
DocAlert: typeof import('./../components/DocAlert/index.vue')['default']
Echart: typeof import('./../components/Echart/src/Echart.vue')['default']
Editor: typeof import('./../components/Editor/src/Editor.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
@ -53,10 +54,12 @@ declare module 'vue' {
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']

View File

@ -58,26 +58,8 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="供应商" prop="supplierName">
<el-select
v-model="formData.supplierName"
placeholder="请选择"
:disabled="formType === 'detail'"
class="!w-full"
filterable
>
<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-col :span="16">
<el-form-item label="其它入库单" prop="relarionNo">
<el-input
v-model="formData.relarionNo"
placeholder="点击选择入库单"
@ -108,12 +90,7 @@
<!-- 明细信息 -->
<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>
<div style="font-weight: bold; margin-bottom: 15px;">明细信息</div>
<el-table
:data="detailList"
@ -138,7 +115,7 @@
<span>{{ scope.row.spec || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="收货数量" min-width="100px" align="center">
<el-table-column label="入库数量" min-width="100px" align="center">
<template #default="scope">
<span>{{ scope.row.sourceQty || '0' }}</span>
</template>
@ -227,9 +204,6 @@
</template>
</Dialog>
<!-- 物料选择弹窗 -->
<MaterialSelectDialog ref="materialSelectRef" @confirm="handleMaterialConfirm" />
<!-- 入库单选择弹窗 -->
<StorageSelectDialog ref="storageSelectRef" @confirm="handleStorageConfirm" />
</template>
@ -237,10 +211,10 @@
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import Dialog from '@/components/Dialog/src/Dialog.vue'
import MoneyInput from '@/components/MoneyInput/src/MoneyInput.vue'
import MaterialSelectDialog from './MaterialSelectDialog.vue'
import MoneyInput from '@/views/biz/components/MoneyInput.vue'
import StorageSelectDialog from './StorageSelectDialog.vue'
import * as ReturnStorageApi from '@/api/biz/returnstorage'
import * as RawStorageApi from '@/api/biz/rawstorage'
import { getUnitName } from '@/utils/dict'
defineOptions({ name: 'ReturnStorageForm' })
@ -261,8 +235,6 @@ const formData = reactive({
businessType: "3",
billDate: new Date().toISOString().split('T')[0],
status: '1',
supplierName: undefined,
supplierId: undefined,
relarionNo: undefined,
relarionId: undefined,
remark: undefined,
@ -279,11 +251,8 @@ const detailList = ref<any[]>([])
//
const warehouseOptions = ref([])
//
const supplierOptions = ref([])
// Ref
const materialSelectRef = ref()
const storageSelectRef = ref()
/** 弹窗关闭时通知父组件 */
@ -305,7 +274,7 @@ const open = async (type: string, id?: number) => {
if (id) {
formLoading.value = true
try {
const data = await ReturnStorageApi.getReturnStorage(id)
const data = await RawStorageApi.getRawStorage(id)
Object.assign(formData, data)
detailList.value = data.items || []
} finally {
@ -318,69 +287,18 @@ defineExpose({ open })
/** 加载仓储列表 */
const loadWarehouseList = async () => {
try {
const data = await ReturnStorageApi.getWarehouseSelect()
const data = await RawStorageApi.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[]) => {
//
@ -503,19 +421,19 @@ const handleSubmit = async (action: string) => {
if (action === 'save') {
if (formType.value === 'create') {
await ReturnStorageApi.createReturnStorage(submitData)
await RawStorageApi.createRawStorage(submitData)
message.success(t('common.createSuccess'))
} else {
await ReturnStorageApi.updateReturnStorage(submitData)
await RawStorageApi.updateRawStorage(submitData)
message.success(t('common.updateSuccess'))
}
} else {
//
if (formType.value === 'create') {
await ReturnStorageApi.confirmReturnStorage(submitData)
await RawStorageApi.confirmRawStorage(submitData)
message.success('确认成功')
} else {
await ReturnStorageApi.confirmReturnStorage(submitData)
await RawStorageApi.confirmRawStorage(submitData)
message.success('确认成功')
}
}
@ -537,8 +455,6 @@ const resetForm = () => {
businessType: "3",
billDate: new Date().toISOString().split('T')[0],
status: '1',
supplierName: undefined,
supplierId: undefined,
relarionNo: undefined,
relarionId: undefined,
remark: undefined,
@ -549,7 +465,6 @@ const resetForm = () => {
/** 初始化 */
onMounted(() => {
loadWarehouseList()
loadSupplierList()
// loadWarehouseList()
})
</script>

View File

@ -27,15 +27,7 @@
class="!w-200px"
/>
</el-form-item>
<el-form-item label="供应商" prop="supplierName">
<el-input
v-model="queryParams.supplierName"
placeholder="请输入"
clearable
@keyup.enter="handleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item label="单据状态" prop="status">
<el-select
v-model="queryParams.status"
@ -170,16 +162,16 @@
</ContentWrap>
<!-- 表单弹窗添加/修改/详情 -->
<RawStorageForm ref="formRef" @success="getList" @close="handleQuery"/>
<ReturnStorageForm ref="formRef" @success="getList" @close="handleQuery"/>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import * as ReturnStorageApi from '@/api/biz/returnstorage'
import * as RawStorageApi from '@/api/biz/rawstorage'
import ReturnStorageForm from './ReturnStorageForm.vue'
import { getUnitName } from '@/utils/dict'
defineOptions({ name: 'ReturnStorage' })
defineOptions({ name: 'RawStorage' })
const message = useMessage() //
const { t } = useI18n() //
@ -203,7 +195,7 @@ const queryFormRef = ref() // 搜索的表单
const getList = async () => {
loading.value = true
try {
const data = await ReturnStorageApi.getReturnStoragePage(queryParams)
const data = await RawStorageApi.getRawStoragePage(queryParams)
list.value = data.list
total.value = data.total
//
@ -220,7 +212,7 @@ const getDetailList = async (id: number) => {
detailLoading.value = true
try {
// 退ID
const data = await ReturnStorageApi.getReturnStorage(id)
const data = await RawStorageApi.getRawStorage(id)
// items
detailList.value = data?.items || []
} catch (error) {