feat(saledelivery): 完善销售出库单功能实现
This commit is contained in:
parent
590b1c9189
commit
1154f82d65
@ -1,13 +1,19 @@
|
|||||||
package com.ningxia.yunxi.chemmes.module.biz.controller.admin.saledelivery.vo;
|
package com.ningxia.yunxi.chemmes.module.biz.controller.admin.saledelivery.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||||
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.saledeliverydetail.vo.SaleDeliveryDetailSaveReqVO;
|
import com.ningxia.yunxi.chemmes.module.biz.controller.admin.saledeliverydetail.vo.SaleDeliveryDetailSaveReqVO;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.ningxia.yunxi.chemmes.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 销售出库单主新增/修改 Request VO")
|
@Schema(description = "管理后台 - 销售出库单主新增/修改 Request VO")
|
||||||
@Data
|
@Data
|
||||||
public class SaleDeliverySaveReqVO {
|
public class SaleDeliverySaveReqVO {
|
||||||
@ -18,7 +24,10 @@ public class SaleDeliverySaveReqVO {
|
|||||||
@Schema(description = "销售出库单号(SC+年份+月份+3位流水号)")
|
@Schema(description = "销售出库单号(SC+年份+月份+3位流水号)")
|
||||||
private String saleDeliveryNo;
|
private String saleDeliveryNo;
|
||||||
|
|
||||||
@Schema(description = "单据日期")
|
@Schema(description = "单据日期", example = "2026-01-01")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||||
|
@JsonSerialize(using = LocalDateSerializer.class)
|
||||||
private LocalDate deliveryDate;
|
private LocalDate deliveryDate;
|
||||||
|
|
||||||
@Schema(description = "客户id", example = "11842")
|
@Schema(description = "客户id", example = "11842")
|
||||||
|
|||||||
@ -18,30 +18,14 @@ public interface SaleDeliveryMapper extends BaseMapperX<SaleDeliveryDO> {
|
|||||||
default PageResult<SaleDeliveryDO> selectPage(SaleDeliveryPageReqVO reqVO) {
|
default PageResult<SaleDeliveryDO> selectPage(SaleDeliveryPageReqVO reqVO) {
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<SaleDeliveryDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<SaleDeliveryDO>()
|
||||||
.betweenIfPresent(SaleDeliveryDO::getCreateTime, reqVO.getCreateTime())
|
.betweenIfPresent(SaleDeliveryDO::getCreateTime, reqVO.getCreateTime())
|
||||||
.eqIfPresent(SaleDeliveryDO::getSaleDeliveryNo, reqVO.getSaleDeliveryNo())
|
.likeIfPresent(SaleDeliveryDO::getSaleDeliveryNo, reqVO.getSaleDeliveryNo())
|
||||||
.betweenIfPresent(SaleDeliveryDO::getDeliveryDate, reqVO.getDeliveryDate())
|
.betweenIfPresent(SaleDeliveryDO::getDeliveryDate, reqVO.getDeliveryDate())
|
||||||
.eqIfPresent(SaleDeliveryDO::getCustId, reqVO.getCustId())
|
|
||||||
.likeIfPresent(SaleDeliveryDO::getCustName, reqVO.getCustName())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getContact, reqVO.getContact())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getConPhone, reqVO.getConPhone())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getConAddress, reqVO.getConAddress())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getDeliveryStatus, reqVO.getDeliveryStatus())
|
.eqIfPresent(SaleDeliveryDO::getDeliveryStatus, reqVO.getDeliveryStatus())
|
||||||
.eqIfPresent(SaleDeliveryDO::getDeliveryType, reqVO.getDeliveryType())
|
.eqIfPresent(SaleDeliveryDO::getDeliveryType, reqVO.getDeliveryType())
|
||||||
.eqIfPresent(SaleDeliveryDO::getRemark, reqVO.getRemark())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getSaleOrdId, reqVO.getSaleOrdId())
|
.eqIfPresent(SaleDeliveryDO::getSaleOrdId, reqVO.getSaleOrdId())
|
||||||
.eqIfPresent(SaleDeliveryDO::getSaleOrdNo, reqVO.getSaleOrdNo())
|
.likeIfPresent(SaleDeliveryDO::getSaleOrdNo, reqVO.getSaleOrdNo())
|
||||||
.eqIfPresent(SaleDeliveryDO::getDeliveryEmpId, reqVO.getDeliveryEmpId())
|
|
||||||
.likeIfPresent(SaleDeliveryDO::getDeliveryEmpName, reqVO.getDeliveryEmpName())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getTwmStorageId, reqVO.getTwmStorageId())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getMaterialId, reqVO.getMaterialId())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getMaterialCode, reqVO.getMaterialCode())
|
.eqIfPresent(SaleDeliveryDO::getMaterialCode, reqVO.getMaterialCode())
|
||||||
.likeIfPresent(SaleDeliveryDO::getMaterialName, reqVO.getMaterialName())
|
.likeIfPresent(SaleDeliveryDO::getMaterialName, reqVO.getMaterialName())
|
||||||
.eqIfPresent(SaleDeliveryDO::getSpec, reqVO.getSpec())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getUnit, reqVO.getUnit())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getOrdQty, reqVO.getOrdQty())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getRemaimQty, reqVO.getRemaimQty())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getSaleOrdDetailId, reqVO.getSaleOrdDetailId())
|
|
||||||
.eqIfPresent(SaleDeliveryDO::getDeliveriedQty, reqVO.getDeliveriedQty())
|
|
||||||
.orderByDesc(SaleDeliveryDO::getId));
|
.orderByDesc(SaleDeliveryDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -93,6 +93,7 @@ declare module 'vue' {
|
|||||||
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']
|
||||||
|
SaleDeliveryDetail: typeof import('./../views/biz/saledelivery/SaleDeliveryDetail.vue')['default']
|
||||||
ScriptTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/ScriptTask.vue')['default']
|
ScriptTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/ScriptTask.vue')['default']
|
||||||
Search: typeof import('./../components/Search/src/Search.vue')['default']
|
Search: typeof import('./../components/Search/src/Search.vue')['default']
|
||||||
ShortcutDateRangePicker: typeof import('./../components/ShortcutDateRangePicker/index.vue')['default']
|
ShortcutDateRangePicker: typeof import('./../components/ShortcutDateRangePicker/index.vue')['default']
|
||||||
|
|||||||
@ -225,6 +225,14 @@ const handleInput = (value: string) => {
|
|||||||
if (props.decimalPlaces === 0) {
|
if (props.decimalPlaces === 0) {
|
||||||
inputValue = inputValue.replace(/\./g, '')
|
inputValue = inputValue.replace(/\./g, '')
|
||||||
displayValue.value = inputValue
|
displayValue.value = inputValue
|
||||||
|
|
||||||
|
// 发出更新事件
|
||||||
|
if (inputValue === '') {
|
||||||
|
emit('update:modelValue', undefined)
|
||||||
|
} else {
|
||||||
|
const num = Number(inputValue)
|
||||||
|
emit('update:modelValue', isNaN(num) ? undefined : num)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -85,9 +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">
|
||||||
<el-input
|
<MoneyInput
|
||||||
v-model.number="formData.deliveriedQty"
|
v-model="formData.deliveriedQty"
|
||||||
type="number"
|
:decimal-places="2"
|
||||||
|
:allow-negative="false"
|
||||||
|
:show-prefix="false"
|
||||||
placeholder="请输入发货数量"
|
placeholder="请输入发货数量"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -171,12 +173,25 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="发货袋数(*)" prop="deliveriedBag" width="120px" align="center">
|
<el-table-column label="发货袋数(*)" prop="deliveriedBag" width="120px" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.deliveriedBag" placeholder="请输入" @input="refreshTable" />
|
<MoneyInput
|
||||||
|
v-model="scope.row.deliveriedBag"
|
||||||
|
:decimal-places="2"
|
||||||
|
:allow-negative="false"
|
||||||
|
:show-prefix="false"
|
||||||
|
placeholder="请输入"
|
||||||
|
@input="refreshTable"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="发货数量(*)" prop="deliveriedQty" width="120px" align="center">
|
<el-table-column label="发货数量(*)" prop="deliveriedQty" width="120px" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.deliveriedQty" placeholder="请输入" @input="refreshTable" />
|
<MoneyInput
|
||||||
|
v-model="scope.row.deliveriedQty"
|
||||||
|
:decimal-places="2"
|
||||||
|
:allow-negative="false"
|
||||||
|
:show-prefix="false"
|
||||||
|
placeholder="请输入"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="备注" prop="remark" width="120px" align="center">
|
<el-table-column label="备注" prop="remark" width="120px" align="center">
|
||||||
@ -220,6 +235,7 @@ import * as CustomerApi from '@/api/biz/customer'
|
|||||||
import { watch } from 'vue'
|
import { watch } from 'vue'
|
||||||
import OrderSelectDialog from './OrderSelectDialog.vue'
|
import OrderSelectDialog from './OrderSelectDialog.vue'
|
||||||
import ProStorageInventorySelectDialog from '../prostorageinventory/ProStorageInventorySelectDialog.vue'
|
import ProStorageInventorySelectDialog from '../prostorageinventory/ProStorageInventorySelectDialog.vue'
|
||||||
|
import MoneyInput from '@/views/biz/components/MoneyInput.vue'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
@ -252,7 +268,7 @@ const formData = reactive({
|
|||||||
saleDeliveryNo: '自动生成',
|
saleDeliveryNo: '自动生成',
|
||||||
deliveryDate: getToday(),
|
deliveryDate: getToday(),
|
||||||
deliveryStatus: '1',
|
deliveryStatus: '1',
|
||||||
deliveryType: undefined,
|
deliveryType: '1',
|
||||||
custId: undefined,
|
custId: undefined,
|
||||||
custName: undefined,
|
custName: undefined,
|
||||||
contact: undefined,
|
contact: undefined,
|
||||||
@ -339,7 +355,7 @@ watch(dialogVisible, (val) => {
|
|||||||
|
|
||||||
const formRules = reactive({
|
const formRules = reactive({
|
||||||
saleOrdId: [{ required: true, message: '销售订单不能为空', trigger: 'change' }],
|
saleOrdId: [{ required: true, message: '销售订单不能为空', trigger: 'change' }],
|
||||||
ordDate: [{ required: true, message: '单据日期不能为空', trigger: 'change' }],
|
deliveryDate: [{ required: true, message: '单据日期不能为空', trigger: 'change' }],
|
||||||
deliveryStatus: [{ required: true, message: '单据状态不能为空', trigger: 'change' }],
|
deliveryStatus: [{ required: true, message: '单据状态不能为空', trigger: 'change' }],
|
||||||
deliveriedQty: [
|
deliveriedQty: [
|
||||||
{ required: true, message: '发货数量不能为空', trigger: 'change' },
|
{ required: true, message: '发货数量不能为空', trigger: 'change' },
|
||||||
@ -597,10 +613,35 @@ const validateDeliveryQty = () => {
|
|||||||
const remaimQty = parseInt(formData.remaimQty) || 0
|
const remaimQty = parseInt(formData.remaimQty) || 0
|
||||||
const totalDeliveriedQty = totalQty.value
|
const totalDeliveriedQty = totalQty.value
|
||||||
|
|
||||||
|
// 验证每个产品项的发货袋数和发货数量不能为空且必须大于0
|
||||||
|
for (let i = 0; i < productList.value.length; i++) {
|
||||||
|
const item = productList.value[i]
|
||||||
|
const deliveriedBag = parseInt(item.deliveriedBag) || 0
|
||||||
|
const deliveriedQty = parseInt(item.deliveriedQty) || 0
|
||||||
|
|
||||||
|
if (!item.deliveriedBag || deliveriedBag <= 0) {
|
||||||
|
message.warning(`第${i + 1}行:发货袋数不能为空且必须大于0`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.deliveriedQty || deliveriedQty <= 0) {
|
||||||
|
message.warning(`第${i + 1}行:发货数量不能为空且必须大于0`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (totalDeliveriedQty > remaimQty) {
|
if (totalDeliveriedQty > remaimQty) {
|
||||||
message.warning(`发货总数量(${totalDeliveriedQty})不能超过剩余数量(${remaimQty})`)
|
message.warning(`发货总数量(${totalDeliveriedQty})不能超过剩余数量(${remaimQty})`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证明细表发货合计数量必须等于表单发货数量
|
||||||
|
const formDeliveriedQty = parseInt(formData.deliveriedQty) || 0
|
||||||
|
if (totalDeliveriedQty !== formDeliveriedQty) {
|
||||||
|
message.warning(`明细表发货合计(${totalDeliveriedQty})必须等于表单发货数量(${formDeliveriedQty})`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,7 +748,7 @@ const resetForm = () => {
|
|||||||
saleDeliveryNo: '自动生成',
|
saleDeliveryNo: '自动生成',
|
||||||
deliveryDate: getToday(),
|
deliveryDate: getToday(),
|
||||||
deliveryStatus: '1',
|
deliveryStatus: '1',
|
||||||
deliveryType: undefined,
|
deliveryType: '1',
|
||||||
custId: undefined,
|
custId: undefined,
|
||||||
custName: undefined,
|
custName: undefined,
|
||||||
contact: undefined,
|
contact: undefined,
|
||||||
@ -733,3 +774,9 @@ const resetForm = () => {
|
|||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.el-table__footer-wrapper td) {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -116,6 +116,7 @@
|
|||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
type="primary"
|
type="primary"
|
||||||
|
v-if="scope.row.deliveryStatus === '1'"
|
||||||
@click.stop="openForm('update', scope.row.id)"
|
@click.stop="openForm('update', scope.row.id)"
|
||||||
v-hasPermi="['tso:sale-delivery:update']"
|
v-hasPermi="['tso:sale-delivery:update']"
|
||||||
>
|
>
|
||||||
@ -124,6 +125,7 @@
|
|||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
type="danger"
|
type="danger"
|
||||||
|
v-if="scope.row.deliveryStatus === '1'"
|
||||||
@click.stop="handleDelete(scope.row.id)"
|
@click.stop="handleDelete(scope.row.id)"
|
||||||
v-hasPermi="['tso:sale-delivery:delete']"
|
v-hasPermi="['tso:sale-delivery:delete']"
|
||||||
>
|
>
|
||||||
@ -132,7 +134,7 @@
|
|||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
type="primary"
|
type="primary"
|
||||||
@click.stop="viewDetail(scope.row)"
|
@click.stop="openDetail(scope.row.id)"
|
||||||
v-hasPermi="['tso:sale-delivery:query']"
|
v-hasPermi="['tso:sale-delivery:query']"
|
||||||
>
|
>
|
||||||
详情
|
详情
|
||||||
@ -173,15 +175,19 @@
|
|||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<!-- 表单弹窗:添加/修改 -->
|
<!-- 表单弹窗:添加/修改 -->
|
||||||
<SaleDeliveryForm ref="formRef" @success="getList"/>
|
<SaleDeliveryForm ref="formRef" @success="getList" @close="handleQuery"/>
|
||||||
|
|
||||||
|
<!-- 详情弹窗 -->
|
||||||
|
<SaleDeliveryDetail ref="detailRef" @success="getList" @close="handleQuery"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { dateFormatter } from '@/utils/formatTime'
|
import { dateFormatter, getCurrentMonthRange } from '@/utils/formatTime'
|
||||||
import download from '@/utils/download'
|
import download from '@/utils/download'
|
||||||
import * as SaleDeliveryApi from '@/api/biz/saledelivery'
|
import * as SaleDeliveryApi from '@/api/biz/saledelivery'
|
||||||
import SaleDeliveryForm from './SaleDeliveryForm.vue'
|
import SaleDeliveryForm from './SaleDeliveryForm.vue'
|
||||||
|
import SaleDeliveryDetail from './SaleDeliveryDetail.vue'
|
||||||
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
||||||
|
|
||||||
defineOptions({ name: 'SaleDelivery' })
|
defineOptions({ name: 'SaleDelivery' })
|
||||||
@ -196,10 +202,18 @@ const selectedRow = ref(null)
|
|||||||
const detailLoading = ref(false)
|
const detailLoading = ref(false)
|
||||||
const detailList = ref([])
|
const detailList = ref([])
|
||||||
|
|
||||||
|
// 详情弹窗
|
||||||
|
const detailRef = ref()
|
||||||
|
|
||||||
|
/** 打开详情弹窗 */
|
||||||
|
const openDetail = (id: number) => {
|
||||||
|
detailRef.value?.open(id)
|
||||||
|
}
|
||||||
|
|
||||||
const queryParams = reactive({
|
const queryParams = reactive({
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
deliveryDate: [],
|
deliveryDate: getCurrentMonthRange(),
|
||||||
saleDeliveryNo: undefined,
|
saleDeliveryNo: undefined,
|
||||||
custName: undefined,
|
custName: undefined,
|
||||||
deliveryStatus: undefined,
|
deliveryStatus: undefined,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user