feat(saledelivery): 完善销售出库单功能实现

This commit is contained in:
zxy 2026-05-18 10:23:16 +08:00
parent 3dcf935e1c
commit 4924139b89
7 changed files with 109 additions and 53 deletions

View File

@ -1,10 +1,8 @@
package com.ningxia.yunxi.chemmes.module.biz.controller.admin.saledeliverydetail.vo; package com.ningxia.yunxi.chemmes.module.biz.controller.admin.saledeliverydetail.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.Data;
import java.util.*;
import javax.validation.constraints.*;
import java.util.*;
import java.math.BigDecimal; import java.math.BigDecimal;
@Schema(description = "管理后台 - 销售出库单子新增/修改 Request VO") @Schema(description = "管理后台 - 销售出库单子新增/修改 Request VO")
@ -53,4 +51,6 @@ public class SaleDeliveryDetailSaveReqVO {
@Schema(description = "发货袋数") @Schema(description = "发货袋数")
private Integer deliveriedBagQty; private Integer deliveriedBagQty;
private String unit;
} }

View File

@ -80,7 +80,7 @@ public class SaleDeliveryDO extends BaseDO {
/** /**
* 出库人id * 出库人id
*/ */
private Integer deliveryEmpId; private String deliveryEmpId;
/** /**
* 出库人名称 * 出库人名称
*/ */

View File

@ -9,6 +9,8 @@ import com.ningxia.yunxi.chemmes.module.biz.dal.dataobject.saledelivery.SaleDeli
import com.ningxia.yunxi.chemmes.module.biz.dal.dataobject.saledeliverydetail.SaleDeliveryDetailDO; import com.ningxia.yunxi.chemmes.module.biz.dal.dataobject.saledeliverydetail.SaleDeliveryDetailDO;
import com.ningxia.yunxi.chemmes.module.biz.dal.mysql.saledelivery.SaleDeliveryMapper; import com.ningxia.yunxi.chemmes.module.biz.dal.mysql.saledelivery.SaleDeliveryMapper;
import com.ningxia.yunxi.chemmes.module.biz.dal.mysql.saledeliverydetail.SaleDeliveryDetailMapper; import com.ningxia.yunxi.chemmes.module.biz.dal.mysql.saledeliverydetail.SaleDeliveryDetailMapper;
import com.ningxia.yunxi.chemmes.module.system.dal.dataobject.user.AdminUserDO;
import com.ningxia.yunxi.chemmes.module.system.dal.mysql.user.AdminUserMapper;
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;
@ -19,6 +21,7 @@ import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import static com.ningxia.yunxi.chemmes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.ningxia.yunxi.chemmes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.ningxia.yunxi.chemmes.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/** /**
* 销售出库单主 Service 实现类 * 销售出库单主 Service 实现类
@ -35,6 +38,9 @@ public class SaleDeliveryServiceImpl implements SaleDeliveryService {
@Resource @Resource
private SaleDeliveryDetailMapper saleDeliveryDetailMapper; private SaleDeliveryDetailMapper saleDeliveryDetailMapper;
@Resource
private AdminUserMapper adminUserMapper;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -43,6 +49,14 @@ public class SaleDeliveryServiceImpl implements SaleDeliveryService {
createReqVO.setSaleDeliveryNo(saleDeliveryNo); createReqVO.setSaleDeliveryNo(saleDeliveryNo);
// 插入 // 插入
SaleDeliveryDO saleDelivery = BeanUtils.toBean(createReqVO, SaleDeliveryDO.class); SaleDeliveryDO saleDelivery = BeanUtils.toBean(createReqVO, SaleDeliveryDO.class);
//出库人
// 获取当前登录用户信息
Long userId = getLoginUserId();
AdminUserDO adminUserDO = adminUserMapper.selectById(userId);
saleDelivery.setDeliveryEmpId(String.valueOf(adminUserDO.getId()));
saleDelivery.setDeliveryEmpName(adminUserDO.getNickname());
saleDeliveryMapper.insert(saleDelivery); saleDeliveryMapper.insert(saleDelivery);
createSaleDeliveryDetailList(saleDelivery.getId(), createReqVO.getDetailList()); createSaleDeliveryDetailList(saleDelivery.getId(), createReqVO.getDetailList());

View File

@ -249,8 +249,10 @@ const handleSave = () => {
const selectData = selectedRows.map(row => ({ const selectData = selectedRows.map(row => ({
id: row.id, id: row.id,
storeHouseId: row.storeHouseId, storeHouseId: row.storeHouseId,
storeHouseCd: row.storeHouseCd,
storeHouseName: row.storeHouseName, storeHouseName: row.storeHouseName,
storeAreaId: row.storeAreaId, storeAreaId: row.storeAreaId,
storeAreCd: row.storeAreCd,
storeAreaName: row.storeAreaName, storeAreaName: row.storeAreaName,
lotNo: row.lotNo, lotNo: row.lotNo,
packQty: row.packQty, packQty: row.packQty,
@ -288,6 +290,6 @@ watch(dialogVisible, (val) => {
<style scoped> <style scoped>
.pagination-container { .pagination-container {
margin-bottom: 16px; margin-bottom: 60px;
} }
</style> </style>

View File

@ -263,7 +263,7 @@ watch(dialogVisible, (val) => {
<style scoped> <style scoped>
.pagination-container { .pagination-container {
margin-bottom: 16px; margin-bottom: 60px;
} }
.radio-btn { .radio-btn {

View File

@ -85,12 +85,11 @@
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="发货数量" prop="deliveriedQty"> <el-form-item label="发货数量" prop="deliveriedQty">
<MoneyInput <el-input
v-model="formData.deliveriedQty" v-model.number="formData.deliveriedQty"
:decimal-places="0" type="number"
:allow-negative="false" placeholder="请输入发货数量"
:show-prefix="false" />
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -361,34 +360,49 @@ const formRules = reactive({
saleDeliveryNo: [{ required: true, message: '出库单号不能为空', trigger: 'change' }], saleDeliveryNo: [{ required: true, message: '出库单号不能为空', trigger: 'change' }],
ordQty: [{ required: true, message: '订单数量不能为空', trigger: 'change' }], ordQty: [{ required: true, message: '订单数量不能为空', trigger: 'change' }],
remaimQty: [{ required: true, message: '剩余数量不能为空', trigger: 'change' }], remaimQty: [{ required: true, message: '剩余数量不能为空', trigger: 'change' }],
deliveriedQty: [{ required: true, message: '发货数量不能为空', trigger: 'change' }],
}) })
const formRef = ref() const formRef = ref()
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (type: string, id?: number) => { const open = async (type: string, id?: number) => {
dialogVisible.value = true //
resetForm()
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
resetForm()
// //
if (id) { if (id) {
formLoading.value = true formLoading.value = true
try { try {
const data = await SaleDeliveryApi.getSaleDelivery(id) const data = await SaleDeliveryApi.getSaleDelivery(id)
Object.assign(formData, data) Object.assign(formData, data)
// - // -
let itemsData = []
if (data.items && data.items.length > 0) { if (data.items && data.items.length > 0) {
productList.value = data.items itemsData = data.items
} else if (data.detailList && data.detailList.length > 0) { } else if (data.detailList && data.detailList.length > 0) {
productList.value = data.detailList itemsData = data.detailList
} else if (data.products && data.products.length > 0) { } else if (data.products && data.products.length > 0) {
productList.value = data.products itemsData = data.products
} else {
productList.value = []
} }
//
productList.value = itemsData.map((item: any) => ({
id: item.id,
storeHouseId: item.storeHouseId,
storeHouseCd: item.storeHouseCd || '',
storeAreaId: item.storeAreaId,
storeAreCd: item.storeAreCd || '',
warehouse: item.storeHouseName || '',
warehouseArea: item.storeAreaName || '',
batchNo: item.lotNo || '',
bagSpec: item.bagSpec || '',
deliveriedBag: item.deliveriedBagQty || '',
deliveriedQty: item.deliveriedQty || '',
remark: item.remark || '',
}))
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@ -396,6 +410,9 @@ const open = async (type: string, id?: number) => {
// //
await loadSaleOrderOptions() await loadSaleOrderOptions()
} }
//
dialogVisible.value = true
} }
defineExpose({ open }) defineExpose({ open })
@ -547,7 +564,9 @@ const handleInventorySelect = (data: any[]) => {
productList.value.push({ productList.value.push({
inventoryId: inventory.id, // ID inventoryId: inventory.id, // ID
storeHouseId: inventory.storeHouseId, // ID storeHouseId: inventory.storeHouseId, // ID
storeHouseCd: inventory.storeHouseCd, //
storeAreaId: inventory.storeAreaId, // ID storeAreaId: inventory.storeAreaId, // ID
storeAreCd: inventory.storeAreCd, //
warehouse: inventory.storeHouseName, // warehouse: inventory.storeHouseName, //
warehouseArea: inventory.storeAreaName, // warehouseArea: inventory.storeAreaName, //
batchNo: inventory.lotNo, // batchNo: inventory.lotNo, //
@ -597,19 +616,18 @@ const submitForm = async () => {
// //
formLoading.value = true formLoading.value = true
try { try {
// detailList // detailList
const detailList = productList.value.map(item => ({ const detailList = productList.value.map(item => ({
id: item.id, twmStorageDetailId: item.id,
inventoryId: item.inventoryId,
storeHouseId: item.storeHouseId, storeHouseId: item.storeHouseId,
storeHouseName: item.warehouse,
storeHouseCd: item.storeHouseCd,
storeAreaId: item.storeAreaId, storeAreaId: item.storeAreaId,
warehouse: item.warehouse, storeAreaName: item.warehouseArea,
warehouseArea: item.warehouseArea, storeAreCd: item.storeAreCd,
batchNo: item.batchNo, lotNo: item.batchNo,
stockQty: item.stockQty,
stockBag: item.stockBag,
bagSpec: item.bagSpec, bagSpec: item.bagSpec,
deliveriedBag: item.deliveriedBag, deliveriedBagQty: item.deliveriedBag,
deliveriedQty: item.deliveriedQty, deliveriedQty: item.deliveriedQty,
remark: item.remark, remark: item.remark,
})) }))
@ -646,19 +664,18 @@ const submitAudit = async () => {
// //
formLoading.value = true formLoading.value = true
try { try {
// detailList // detailList
const detailList = productList.value.map(item => ({ const detailList = productList.value.map(item => ({
id: item.id, id: item.id,
inventoryId: item.inventoryId,
storeHouseId: item.storeHouseId, storeHouseId: item.storeHouseId,
storeHouseName: item.warehouse,
storeHouseCd: item.storeHouseCd,
storeAreaId: item.storeAreaId, storeAreaId: item.storeAreaId,
warehouse: item.warehouse, storeAreCd: item.storeAreCd,
warehouseArea: item.warehouseArea, storeAreaName: item.warehouseArea,
batchNo: item.batchNo, lotNo: item.batchNo,
stockQty: item.stockQty,
stockBag: item.stockBag,
bagSpec: item.bagSpec, bagSpec: item.bagSpec,
deliveriedBag: item.deliveriedBag, deliveriedBagQty: item.deliveriedBag,
deliveriedQty: item.deliveriedQty, deliveriedQty: item.deliveriedQty,
remark: item.remark, remark: item.remark,
})) }))

View File

@ -89,19 +89,26 @@
<el-table-column label="订单数量" align="center" prop="ordQty" width="100px" /> <el-table-column label="订单数量" align="center" prop="ordQty" width="100px" />
<el-table-column label="剩余数量" align="center" prop="remaimQty" width="100px" /> <el-table-column label="剩余数量" align="center" prop="remaimQty" width="100px" />
<el-table-column label="发货数量" align="center" prop="deliveriedQty" width="100px" /> <el-table-column label="发货数量" align="center" prop="deliveriedQty" width="100px" />
<el-table-column label="单位" align="center" prop="unit" width="80px" /> <el-table-column label="单位" align="center" width="80px">
<template #default="scope">
<dict-tag v-if="scope.row.unit" :type="DICT_TYPE.UNIT" :value="scope.row.unit" />
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="出库人" align="center" prop="deliveryEmpName" width="100px" /> <el-table-column label="出库人" align="center" prop="deliveryEmpName" width="100px" />
<el-table-column label="交货方式" align="center" prop="deliveryType" width="100px"> <el-table-column label="交货方式" align="center" prop="deliveryType" width="100px">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.DELIVERY_METHOD" :value="scope.row.deliveryType" /> <span>{{ scope.row.deliveryType === '1' ? '发货' : (scope.row.deliveryType === '2' ? '自提' : '-') }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="联系人" align="center" prop="contact" width="100px" /> <el-table-column label="联系人" align="center" prop="contact" width="100px" />
<el-table-column label="联系电话" align="center" prop="conPhone" width="120px" /> <el-table-column label="联系电话" align="center" prop="conPhone" width="130px" />
<el-table-column label="联系地址" align="center" prop="conAddress" width="180px" /> <el-table-column label="联系地址" align="center" prop="conAddress" width="180px" />
<el-table-column label="单据状态" align="center" prop="deliveryStatus" width="100px" fixed="right"> <el-table-column label="单据状态" align="center" prop="deliveryStatus" width="100px" fixed="right">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.BILL_STATUS" :value="scope.row.deliveryStatus" /> <el-tag :type="scope.row.deliveryStatus === '1' ? 'info' : 'success'">
{{ scope.row.deliveryStatus === '1' ? '已创建' : (scope.row.deliveryStatus === '2' ? '已确认' : '-') }}
</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="170px" fixed="right"> <el-table-column label="操作" align="center" width="170px" fixed="right">
@ -109,7 +116,7 @@
<el-button <el-button
link link
type="primary" type="primary"
@click="openForm('update', scope.row.id)" @click.stop="openForm('update', scope.row.id)"
v-hasPermi="['tso:sale-delivery:update']" v-hasPermi="['tso:sale-delivery:update']"
> >
编辑 编辑
@ -117,7 +124,7 @@
<el-button <el-button
link link
type="danger" type="danger"
@click="handleDelete(scope.row.id)" @click.stop="handleDelete(scope.row.id)"
v-hasPermi="['tso:sale-delivery:delete']" v-hasPermi="['tso:sale-delivery:delete']"
> >
删除 删除
@ -125,7 +132,7 @@
<el-button <el-button
link link
type="primary" type="primary"
@click="viewDetail(scope.row)" @click.stop="viewDetail(scope.row)"
v-hasPermi="['tso:sale-delivery:query']" v-hasPermi="['tso:sale-delivery:query']"
> >
详情 详情
@ -145,15 +152,20 @@
<!-- 明细表格 --> <!-- 明细表格 -->
<div style="flex: 1; min-height: 0;" > <div style="flex: 1; min-height: 0;" >
<div style="font-weight: bold; margin-bottom: 8px;">出库单明细</div> <div style="font-weight: bold; margin-bottom: 8px;">出库单明细</div>
<el-table v-loading="detailLoading" :data="detailList" :stripe="true" :show-overflow-tooltip="true" border :summary-method="getDetailSummary" show-summary style="width: 50%"> <el-table v-loading="detailLoading" :data="detailList" :stripe="true" :show-overflow-tooltip="true" :summary-method="getDetailSummary" show-summary border style="width: 50%">
<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="warehouseArea" width="120px" /> <el-table-column label="库区" align="center" prop="warehouseArea" width="120px" />
<el-table-column label="库位" align="center" prop="warehouseLoc" width="120px" /> <el-table-column label="库位" align="center" prop="storeHouseName" width="120px" />
<el-table-column label="批次号" align="center" prop="batchNo" width="120px" /> <el-table-column label="批次号" align="center" prop="batchNo" width="120px" />
<el-table-column label="发货数量" align="center" prop="deliveriedQty" width="120px" /> <el-table-column label="发货数量" align="center" prop="deliveriedQty" width="120px" />
<el-table-column label="发货袋数" align="center" prop="deliveriedBag" width="120px" /> <el-table-column label="发货袋数" align="center" prop="deliveriedBag" width="120px" />
<el-table-column label="单据规格" align="center" prop="spec" width="120px" /> <el-table-column label="单据规格" align="center" prop="bagSpec" width="120px" />
<el-table-column label="单位" align="center" prop="unit" width="80px" /> <el-table-column label="单位" align="center" width="80px">
<template #default="scope">
<dict-tag v-if="scope.row.unit" :type="DICT_TYPE.UNIT" :value="scope.row.unit" />
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" /> <el-table-column label="备注" align="center" prop="remark" />
</el-table> </el-table>
</div> </div>
@ -283,8 +295,19 @@ const viewDetail = async (row: any) => {
try { try {
const data = await SaleDeliveryApi.getSaleDelivery(row.id) const data = await SaleDeliveryApi.getSaleDelivery(row.id)
selectedRow.value = data selectedRow.value = data
// 使 detailList // 使 detailList
detailList.value = data.items || data.detailList || [] const itemsData = data.items || data.detailList || []
const mainUnit = data.unit || '' //
detailList.value = itemsData.map((item: any) => ({
warehouseArea: item.storeAreaName || '',
storeHouseName: item.storeHouseName || '',
batchNo: item.lotNo || '',
deliveriedQty: item.deliveriedQty || '',
deliveriedBag: item.deliveriedBagQty || '',
bagSpec: item.bagSpec || '',
unit: mainUnit, // 使
remark: item.remark || '',
}))
} catch (e) { } catch (e) {
console.error('获取详情失败', e) console.error('获取详情失败', e)
detailList.value = [] detailList.value = []