feat(mes): 新增库存物资记录编号字段及相关逻辑

pull/871/MERGE
YunaiV 2026-03-30 17:53:58 +08:00
parent e41d14bb67
commit 62f4c62e3d
3 changed files with 150 additions and 60 deletions

View File

@ -5,6 +5,7 @@ export interface WmSalesNoticeLineVO {
id: number id: number
noticeId: number noticeId: number
itemId: number itemId: number
materialStockId: number
itemCode: string itemCode: string
itemName: string itemName: string
specification: string specification: string

View File

@ -13,9 +13,7 @@
<el-form-item label="通知单编号" prop="noticeCode"> <el-form-item label="通知单编号" prop="noticeCode">
<el-input v-model="formData.noticeCode" placeholder="请输入通知单编号"> <el-input v-model="formData.noticeCode" placeholder="请输入通知单编号">
<template #append> <template #append>
<el-button @click="generateCode"> <el-button @click="generateCode"> </el-button>
生成
</el-button>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
@ -45,6 +43,7 @@
value-format="x" value-format="x"
placeholder="请选择发货日期" placeholder="请选择发货日期"
class="!w-1/1" class="!w-1/1"
:disabled="isDetail"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -74,16 +73,24 @@
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<!-- 编辑时展示物料信息 --> <!-- 非新建模式展示物料信息 -->
<template v-if="formType === 'update' && formData.id"> <template v-if="formData.id">
<el-divider content-position="center">物料信息</el-divider> <el-divider content-position="center">物料信息</el-divider>
<SalesNoticeLineList :notice-id="formData.id" /> <SalesNoticeLineList :notice-id="formData.id" :form-type="formType" />
</template> </template>
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!isDetail"> <el-button v-if="isEditable" @click="submitForm" type="primary" :disabled="formLoading">
</el-button> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button
v-if="isEditable && formData.status === MesWmSalesNoticeStatusEnum.PREPARE"
@click="handleSubmit"
type="warning"
:disabled="formLoading"
>
</el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template> </template>
</Dialog> </Dialog>
</template> </template>
@ -93,32 +100,34 @@ import { WmSalesNoticeApi, WmSalesNoticeVO } from '@/api/mes/wm/salesnotice'
import { AutoCodeRecordApi } from '@/api/mes/md/autocode/record' import { AutoCodeRecordApi } from '@/api/mes/md/autocode/record'
import SalesNoticeLineList from './SalesNoticeLineList.vue' import SalesNoticeLineList from './SalesNoticeLineList.vue'
import MdClientSelect from '@/views/mes/md/client/components/MdClientSelect.vue' import MdClientSelect from '@/views/mes/md/client/components/MdClientSelect.vue'
import { MesAutoCodeRuleCode } from '@/views/mes/utils/constants' import { MesAutoCodeRuleCode, MesWmSalesNoticeStatusEnum } from '@/views/mes/utils/constants'
defineOptions({ name: 'SalesNoticeForm' }) defineOptions({ name: 'SalesNoticeForm' })
const emit = defineEmits(['success'])
const { t } = useI18n() const message = useMessage() //
const message = useMessage()
const dialogVisible = ref(false) const dialogVisible = ref(false) //
const formLoading = ref(false) const formLoading = ref(false) //
const formType = ref('') const formType = ref<string>('create') // 表单的类型create / update / detail
const isDetail = computed(() => formType.value === 'detail') const isEditable = computed(() => ['create', 'update'].includes(formType.value)) //
const isDetail = computed(() => formType.value === 'detail') //
const dialogTitle = computed(() => { const dialogTitle = computed(() => {
const titles = { const titles: Record<string, string> = {
create: '新增发货通知单', create: '新增发货通知单',
update: '修改发货通知单', update: '修改发货通知单',
detail: '查看发货通知单' detail: '查看发货通知单'
} }
return titles[formType.value] || t('action.' + formType.value) return titles[formType.value] || formType.value
}) })
const formData = ref({ const formData = ref({
id: undefined, id: undefined as number | undefined,
noticeCode: undefined, noticeCode: undefined,
noticeName: undefined, noticeName: undefined,
salesOrderCode: undefined, salesOrderCode: undefined,
clientId: undefined, clientId: undefined,
salesDate: undefined, salesDate: undefined,
status: undefined as number | undefined,
recipientName: undefined, recipientName: undefined,
recipientTelephone: undefined, recipientTelephone: undefined,
recipientAddress: undefined, recipientAddress: undefined,
@ -130,7 +139,8 @@ const formRules = reactive({
clientId: [{ required: true, message: '请选择客户', trigger: 'change' }], clientId: [{ required: true, message: '请选择客户', trigger: 'change' }],
salesDate: [{ required: true, message: '请选择发货日期', trigger: 'change' }] salesDate: [{ required: true, message: '请选择发货日期', trigger: 'change' }]
}) })
const formRef = ref() const formRef = ref() // Ref
const originalFormData = ref<string>('') //
/** 生成通知单编号 */ /** 生成通知单编号 */
const generateCode = async () => { const generateCode = async () => {
@ -152,11 +162,11 @@ const open = async (type: string, id?: number) => {
formLoading.value = false formLoading.value = false
} }
} }
//
originalFormData.value = JSON.stringify(formData.value)
} }
defineExpose({ open })
/** 提交表单 */ /** 提交表单create/update 模式) */
const emit = defineEmits(['success'])
const submitForm = async () => { const submitForm = async () => {
await formRef.value.validate() await formRef.value.validate()
formLoading.value = true formLoading.value = true
@ -164,20 +174,44 @@ const submitForm = async () => {
const data = formData.value as unknown as WmSalesNoticeVO const data = formData.value as unknown as WmSalesNoticeVO
if (formType.value === 'create') { if (formType.value === 'create') {
const res = await WmSalesNoticeApi.createSalesNotice(data) const res = await WmSalesNoticeApi.createSalesNotice(data)
message.success(t('common.createSuccess')) message.success('新增成功')
formData.value.id = res formData.value.id = res
formData.value.status = MesWmSalesNoticeStatusEnum.PREPARE
formType.value = 'update' formType.value = 'update'
} else { } else {
await WmSalesNoticeApi.updateSalesNotice(data) await WmSalesNoticeApi.updateSalesNotice(data)
message.success(t('common.updateSuccess')) message.success('修改成功')
dialogVisible.value = false
} }
//
originalFormData.value = JSON.stringify(formData.value)
emit('success') emit('success')
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
} }
/** 提交操作:表单修改过则先保存,再提交 */
const handleSubmit = async () => {
await formRef.value.validate()
try {
await message.confirm('确认提交该发货通知单?【提交后将不能修改】')
formLoading.value = true
// 1.
if (JSON.stringify(formData.value) !== originalFormData.value) {
const data = formData.value as unknown as WmSalesNoticeVO
await WmSalesNoticeApi.updateSalesNotice(data)
}
// 2.
await WmSalesNoticeApi.submitSalesNotice(formData.value.id!)
message.success('提交成功')
dialogVisible.value = false
emit('success')
} catch {
} finally {
formLoading.value = false
}
}
/** 重置表单 */ /** 重置表单 */
const resetForm = () => { const resetForm = () => {
formData.value = { formData.value = {
@ -187,6 +221,7 @@ const resetForm = () => {
salesOrderCode: undefined, salesOrderCode: undefined,
clientId: undefined, clientId: undefined,
salesDate: undefined, salesDate: undefined,
status: undefined,
recipientName: undefined, recipientName: undefined,
recipientTelephone: undefined, recipientTelephone: undefined,
recipientAddress: undefined, recipientAddress: undefined,
@ -194,4 +229,6 @@ const resetForm = () => {
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }
defineExpose({ open })
</script> </script>

View File

@ -1,26 +1,43 @@
<!-- MES 发货通知单行列表子组件 --> <!-- MES 发货通知单行列表子组件 -->
<template> <template>
<div class="overflow-hidden"> <div class="overflow-hidden">
<el-button type="primary" plain @click="openForm('create')" class="mb-10px"> <el-button v-if="isUpdate" type="primary" plain @click="openForm('create')" class="mb-10px">
<Icon icon="ep:plus" class="mr-5px" /> 添加物料 <Icon icon="ep:plus" class="mr-5px" /> 添加物料
</el-button> </el-button>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" border> <el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
border
:row-key="(row: any) => row.id"
>
<el-table-column label="物料编码" align="center" prop="itemCode" min-width="120" /> <el-table-column label="物料编码" align="center" prop="itemCode" min-width="120" />
<el-table-column label="物料名称" align="center" prop="itemName" min-width="140" /> <el-table-column label="物料名称" align="center" prop="itemName" min-width="140" />
<el-table-column label="规格型号" align="center" prop="specification" min-width="120" /> <el-table-column label="规格型号" align="center" prop="specification" min-width="120" />
<el-table-column label="单位" align="center" prop="unitMeasureName" width="80" /> <el-table-column label="单位" align="center" prop="unitMeasureName" width="80" />
<el-table-column label="批次号" align="center" prop="batchCode" min-width="120" />
<el-table-column label="发货数量" align="center" prop="quantity" width="100" /> <el-table-column label="发货数量" align="center" prop="quantity" width="100" />
<el-table-column label="批次号" align="center" prop="batchCode" min-width="120" />
<el-table-column label="是否检验" align="center" prop="oqcCheckFlag" width="90"> <el-table-column label="是否检验" align="center" prop="oqcCheckFlag" width="90">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.oqcCheckFlag" /> <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.oqcCheckFlag" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="120" /> <el-table-column label="备注" align="center" prop="remark" min-width="120" />
<el-table-column label="操作" align="center" width="120"> <el-table-column
v-if="isUpdate"
label="操作"
align="center"
width="120"
fixed="right"
>
<template #default="scope"> <template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)">编辑</el-button> <el-button v-if="isUpdate" link type="primary" @click="openForm('update', scope.row.id)">
<el-button link type="danger" @click="handleDelete(scope.row.id)"></el-button> 编辑
</el-button>
<el-button v-if="isUpdate" link type="danger" @click="handleDelete(scope.row.id)">
删除
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -33,7 +50,7 @@
</div> </div>
<!-- 添加/编辑行弹窗 --> <!-- 添加/编辑行弹窗 -->
<Dialog :title="dialogTitle" v-model="dialogVisible" width="700px"> <Dialog :title="dialogTitle" v-model="dialogVisible" width="960px">
<el-form <el-form
ref="formRef" ref="formRef"
:model="formData" :model="formData"
@ -42,30 +59,41 @@
v-loading="formLoading" v-loading="formLoading"
> >
<el-row> <el-row>
<el-col :span="12"> <el-col :span="8">
<el-form-item label="物料" prop="itemId"> <el-form-item label="库存记录" prop="materialStockId">
<MdItemSelect v-model="formData.itemId" placeholder="请选择物料" /> <WmMaterialStockSelect
v-model="formData.materialStockId"
placeholder="请选择库存"
class="!w-1/1"
@change="handleStockChange"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="8">
<el-form-item label="批次号" prop="batchCode">
<el-input v-model="formData.batchCode" placeholder="请输入批次号" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="发货数量" prop="quantity"> <el-form-item label="发货数量" prop="quantity">
<el-input-number <el-input-number
v-model="formData.quantity" v-model="formData.quantity"
:precision="2" :precision="2"
:min="0.01" :min="0"
:max="quantityMax"
controls-position="right" controls-position="right"
class="!w-1/1" class="!w-1/1"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="8">
<el-form-item label="批次号">
<el-input :model-value="formData.batchCode" disabled placeholder="选择库存后自动带出" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="物料">
<MdItemSelect v-model="formData.itemId" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="是否检验" prop="oqcCheckFlag"> <el-form-item label="是否检验" prop="oqcCheckFlag">
<el-switch v-model="formData.oqcCheckFlag" /> <el-switch v-model="formData.oqcCheckFlag" />
</el-form-item> </el-form-item>
@ -89,17 +117,22 @@
<script setup lang="ts"> <script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { WmSalesNoticeLineApi, WmSalesNoticeLineVO } from '@/api/mes/wm/salesnotice/line' import { WmSalesNoticeLineApi, WmSalesNoticeLineVO } from '@/api/mes/wm/salesnotice/line'
import { WmMaterialStockVO } from '@/api/mes/wm/materialstock'
import WmMaterialStockSelect from '@/views/mes/wm/materialstock/components/WmMaterialStockSelect.vue'
import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue' import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue'
defineOptions({ name: 'SalesNoticeLineList' }) defineOptions({ name: 'SalesNoticeLineList' })
const props = defineProps<{ const props = defineProps<{
noticeId: number noticeId: number
formType: string
}>() }>()
const { t } = useI18n() const { t } = useI18n()
const message = useMessage() const message = useMessage()
const isUpdate = computed(() => ['create', 'update'].includes(props.formType))
// ==================== ==================== // ==================== ====================
const loading = ref(false) const loading = ref(false)
const list = ref<WmSalesNoticeLineVO[]>([]) const list = ref<WmSalesNoticeLineVO[]>([])
@ -137,31 +170,47 @@ const handleDelete = async (id: number) => {
const dialogVisible = ref(false) const dialogVisible = ref(false)
const dialogTitle = ref('') const dialogTitle = ref('')
const formLoading = ref(false) const formLoading = ref(false)
const formType = ref('') const lineFormType = ref('')
const quantityMax = ref<number | undefined>(undefined)
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
noticeId: undefined as number | undefined, noticeId: undefined as number | undefined,
itemId: undefined, materialStockId: undefined as number | undefined,
batchCode: undefined, itemId: undefined as number | undefined,
quantity: undefined, quantity: undefined as number | undefined,
batchId: undefined as number | undefined,
batchCode: undefined as string | undefined,
oqcCheckFlag: true, oqcCheckFlag: true,
remark: undefined remark: undefined
}) })
const formRules = reactive({ const formRules = reactive({
itemId: [{ required: true, message: '物料不能为空', trigger: 'change' }], materialStockId: [{ required: true, message: '请选择库存记录', trigger: 'change' }],
quantity: [ quantity: [{ required: true, message: '发货数量不能为空', trigger: 'blur' }]
{ required: true, message: '发货数量不能为空', trigger: 'blur' },
{ type: 'number', min: 0.01, message: '发货数量必须大于0', trigger: 'blur' }
],
oqcCheckFlag: [{ required: true, message: '是否检验不能为空', trigger: 'change' }]
}) })
const formRef = ref() const formRef = ref()
/** 库存选中回调 —— 自动回填物料ID/批次/数量上限 */
const handleStockChange = (stock: WmMaterialStockVO | undefined) => {
if (!stock) {
formData.value.itemId = undefined
formData.value.batchId = undefined
formData.value.batchCode = undefined
formData.value.quantity = undefined
quantityMax.value = undefined
return
}
formData.value.itemId = stock.itemId
formData.value.batchId = stock.batchId
formData.value.batchCode = stock.batchCode
formData.value.quantity = stock.quantity
quantityMax.value = stock.quantity
}
/** 打开表单弹窗 */ /** 打开表单弹窗 */
const openForm = async (type: string, id?: number) => { const openForm = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
dialogTitle.value = t('action.' + type) dialogTitle.value = type === 'create' ? '添加发货通知单行' : '修改发货通知单行'
formType.value = type lineFormType.value = type
resetForm() resetForm()
if (id) { if (id) {
formLoading.value = true formLoading.value = true
@ -179,7 +228,7 @@ const submitForm = async () => {
formLoading.value = true formLoading.value = true
try { try {
const data = { ...formData.value, noticeId: props.noticeId } as unknown as WmSalesNoticeLineVO const data = { ...formData.value, noticeId: props.noticeId } as unknown as WmSalesNoticeLineVO
if (formType.value === 'create') { if (lineFormType.value === 'create') {
await WmSalesNoticeLineApi.createSalesNoticeLine(data) await WmSalesNoticeLineApi.createSalesNoticeLine(data)
message.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
} else { } else {
@ -198,12 +247,15 @@ const resetForm = () => {
formData.value = { formData.value = {
id: undefined, id: undefined,
noticeId: undefined, noticeId: undefined,
materialStockId: undefined,
itemId: undefined, itemId: undefined,
batchCode: undefined,
quantity: undefined, quantity: undefined,
batchId: undefined,
batchCode: undefined,
oqcCheckFlag: true, oqcCheckFlag: true,
remark: undefined remark: undefined
} }
quantityMax.value = undefined
formRef.value?.resetFields() formRef.value?.resetFields()
} }