feat(mes): 增强到货通知单表单逻辑与交互

更新到货通知单表单,增加字段的只读状态控制,优化用户交互体验。新增表单数据快照功能以支持脏检查,确保用户在提交前确认修改。调整按钮逻辑以适应不同表单状态,提升整体可用性。
pull/871/MERGE
YunaiV 2026-03-29 19:36:59 +08:00
parent 32a830b595
commit 88dcf7f74f
4 changed files with 110 additions and 91 deletions

View File

@ -11,30 +11,40 @@
<el-row> <el-row>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="通知单编号" prop="code"> <el-form-item label="通知单编号" prop="code">
<el-input v-model="formData.code" placeholder="请输入通知单编号"> <el-input
v-model="formData.code"
placeholder="请输入通知单编号"
:disabled="isHeaderReadonly"
>
<template #append> <template #append>
<el-button @click="generateCode"> <el-button @click="generateCode" :disabled="isHeaderReadonly"> 生成 </el-button>
生成
</el-button>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="通知单名称" prop="name"> <el-form-item label="通知单名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入通知单名称" /> <el-input
v-model="formData.name"
placeholder="请输入通知单名称"
:disabled="isHeaderReadonly"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="采购订单编号" prop="purchaseOrderCode"> <el-form-item label="采购订单编号" prop="purchaseOrderCode">
<el-input v-model="formData.purchaseOrderCode" placeholder="请输入采购订单编号" /> <el-input
v-model="formData.purchaseOrderCode"
placeholder="请输入采购订单编号"
:disabled="isHeaderReadonly"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="供应商" prop="vendorId"> <el-form-item label="供应商" prop="vendorId">
<MdVendorSelect v-model="formData.vendorId" :disabled="isDetail" /> <MdVendorSelect v-model="formData.vendorId" :disabled="isHeaderReadonly" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
@ -45,6 +55,7 @@
value-format="x" value-format="x"
placeholder="请选择到货日期" placeholder="请选择到货日期"
class="!w-1/1" class="!w-1/1"
:disabled="isHeaderReadonly"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -52,65 +63,89 @@
<el-row> <el-row>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="联系人" prop="contactName"> <el-form-item label="联系人" prop="contactName">
<el-input v-model="formData.contactName" placeholder="请输入联系人" /> <el-input
v-model="formData.contactName"
placeholder="请输入联系人"
:disabled="isHeaderReadonly"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="联系方式" prop="contactTelephone"> <el-form-item label="联系方式" prop="contactTelephone">
<el-input v-model="formData.contactTelephone" placeholder="请输入联系方式" /> <el-input
v-model="formData.contactTelephone"
placeholder="请输入联系方式"
:disabled="isHeaderReadonly"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" /> <el-input
v-model="formData.remark"
type="textarea"
placeholder="请输入备注"
:disabled="isHeaderReadonly"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<!-- 编辑/详情时展示物料信息 --> <!-- 编辑/详情时展示物料信息 -->
<template v-if="['update', 'detail'].includes(formType) && formData.id"> <template v-if="formData.id">
<el-divider content-position="center">物料信息</el-divider> <el-divider content-position="center">物料信息</el-divider>
<ArrivalNoticeLineList :notice-id="formData.id" :form-type="formType" /> <ArrivalNoticeLineList :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 === MesWmArrivalNoticeStatusEnum.PREPARE"
@click="handleSubmit"
type="warning"
:disabled="formLoading"
>
</el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template> </template>
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { AutoCodeRecordApi } from '@/api/mes/md/autocode/record' import { AutoCodeRecordApi } from '@/api/mes/md/autocode/record'
import { MesAutoCodeRuleCode } from '@/views/mes/utils/constants' import { MesAutoCodeRuleCode, MesWmArrivalNoticeStatusEnum } from '@/views/mes/utils/constants'
import { WmArrivalNoticeApi, WmArrivalNoticeVO } from '@/api/mes/wm/arrivalnotice' import { WmArrivalNoticeApi, WmArrivalNoticeVO } from '@/api/mes/wm/arrivalnotice'
import ArrivalNoticeLineList from './ArrivalNoticeLineList.vue' import ArrivalNoticeLineList from './ArrivalNoticeLineList.vue'
import MdVendorSelect from '@/views/mes/md/vendor/components/MdVendorSelect.vue' import MdVendorSelect from '@/views/mes/md/vendor/components/MdVendorSelect.vue'
defineOptions({ name: 'ArrivalNoticeForm' }) defineOptions({ name: 'ArrivalNoticeForm' })
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('') // create - update - detail - const formType = ref<string>('create') // 表单的类型create / update / detail
const isEditable = computed(() => ['create', 'update'].includes(formType.value)) //
const isDetail = computed(() => formType.value === 'detail') // const isDetail = computed(() => formType.value === 'detail') //
const isHeaderReadonly = computed(() => formType.value === 'detail') //
const dialogTitle = computed(() => { const dialogTitle = computed(() => {
const titles = { const titles = {
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,
code: undefined, code: undefined,
name: undefined, name: undefined,
status: undefined as number | undefined,
purchaseOrderCode: undefined, purchaseOrderCode: undefined,
vendorId: undefined, vendorId: undefined,
arrivalDate: undefined, arrivalDate: undefined,
@ -118,6 +153,7 @@ const formData = ref({
contactTelephone: undefined, contactTelephone: undefined,
remark: undefined remark: undefined
}) })
const originalFormData = ref<string>('') //
const formRules = reactive({ const formRules = reactive({
code: [{ required: true, message: '通知单编号不能为空', trigger: 'blur' }], code: [{ required: true, message: '通知单编号不能为空', trigger: 'blur' }],
name: [{ required: true, message: '通知单名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '通知单名称不能为空', trigger: 'blur' }],
@ -128,7 +164,9 @@ const formRef = ref() // 表单 Ref
/** 生成通知单编号 */ /** 生成通知单编号 */
const generateCode = async () => { const generateCode = async () => {
formData.value.code = await AutoCodeRecordApi.generateAutoCode(MesAutoCodeRuleCode.WM_ARRIVAL_NOTICE_CODE) formData.value.code = await AutoCodeRecordApi.generateAutoCode(
MesAutoCodeRuleCode.WM_ARRIVAL_NOTICE_CODE
)
} }
/** 打开弹窗 */ /** 打开弹窗 */
@ -136,7 +174,6 @@ const open = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
formType.value = type formType.value = type
resetForm() resetForm()
// DONE @AI MdVendorSelect
if (id) { if (id) {
formLoading.value = true formLoading.value = true
try { try {
@ -145,11 +182,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
@ -157,16 +194,40 @@ const submitForm = async () => {
const data = formData.value as unknown as WmArrivalNoticeVO const data = formData.value as unknown as WmArrivalNoticeVO
if (formType.value === 'create') { if (formType.value === 'create') {
const res = await WmArrivalNoticeApi.createArrivalNotice(data) const res = await WmArrivalNoticeApi.createArrivalNotice(data)
message.success(t('common.createSuccess')) message.success('新增成功')
// id //
formData.value.id = res formData.value.id = res
formData.value.status = MesWmArrivalNoticeStatusEnum.PREPARE
formType.value = 'update' formType.value = 'update'
} else { } else {
await WmArrivalNoticeApi.updateArrivalNotice(data) await WmArrivalNoticeApi.updateArrivalNotice(data)
message.success(t('common.updateSuccess')) message.success('修改成功')
dialogVisible.value = false
emit('success')
} }
//
originalFormData.value = JSON.stringify(formData.value)
emit('success')
} finally {
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 WmArrivalNoticeVO
await WmArrivalNoticeApi.updateArrivalNotice(data)
}
// 2.
await WmArrivalNoticeApi.submitArrivalNotice(formData.value.id!)
message.success('提交成功')
dialogVisible.value = false
emit('success')
} catch {
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@ -178,6 +239,7 @@ const resetForm = () => {
id: undefined, id: undefined,
code: undefined, code: undefined,
name: undefined, name: undefined,
status: undefined,
purchaseOrderCode: undefined, purchaseOrderCode: undefined,
vendorId: undefined, vendorId: undefined,
arrivalDate: undefined, arrivalDate: undefined,
@ -187,4 +249,6 @@ const resetForm = () => {
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }
defineExpose({ open })
</script> </script>

View File

@ -16,6 +16,7 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="合格数量" align="center" prop="qualifiedQuantity" width="100" /> <el-table-column label="合格数量" align="center" prop="qualifiedQuantity" width="100" />
<!-- TODO @AI是不是按需读取下 -->
<el-table-column label="检验单号" align="center" prop="iqcCode" min-width="140" /> <el-table-column label="检验单号" align="center" prop="iqcCode" min-width="140" />
<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 v-if="isEditable" label="操作" align="center" width="120"> <el-table-column v-if="isEditable" label="操作" align="center" width="120">
@ -34,6 +35,7 @@
</div> </div>
<!-- 添加/编辑行弹窗 --> <!-- 添加/编辑行弹窗 -->
<!-- TODO @AI一行 3 -->
<Dialog :title="dialogTitle" v-model="dialogVisible" width="700px"> <Dialog :title="dialogTitle" v-model="dialogVisible" width="700px">
<el-form <el-form
ref="formRef" ref="formRef"
@ -45,6 +47,7 @@
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="物料" prop="itemId"> <el-form-item label="物料" prop="itemId">
<!-- TODO @AI换成选择器 -->
<el-select <el-select
v-model="formData.itemId" v-model="formData.itemId"
placeholder="请选择物料" placeholder="请选择物料"
@ -73,7 +76,6 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<!-- DONE @AI已移除合格数量字段该字段由 IQC 回调自动设置 -->
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="是否检验" prop="iqcCheckFlag"> <el-form-item label="是否检验" prop="iqcCheckFlag">

View File

@ -25,7 +25,6 @@
class="!w-240px" class="!w-240px"
/> />
</el-form-item> </el-form-item>
<!-- TODO @芋艿待确认先忽略这里的字段映射 -->
<el-form-item label="采购订单编号" prop="purchaseOrderCode"> <el-form-item label="采购订单编号" prop="purchaseOrderCode">
<el-input <el-input
v-model="queryParams.purchaseOrderCode" v-model="queryParams.purchaseOrderCode"
@ -36,19 +35,7 @@
/> />
</el-form-item> </el-form-item>
<el-form-item label="供应商" prop="vendorId"> <el-form-item label="供应商" prop="vendorId">
<el-select <MdVendorSelect v-model="queryParams.vendorId" class="!w-240px" />
v-model="queryParams.vendorId"
placeholder="请选择供应商"
clearable
class="!w-240px"
>
<el-option
v-for="vendor in vendorList"
:key="vendor.id"
:label="vendor.name"
:value="vendor.id"
/>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="到货日期" prop="arrivalDate"> <el-form-item label="到货日期" prop="arrivalDate">
<el-date-picker <el-date-picker
@ -61,21 +48,7 @@
class="!w-240px" class="!w-240px"
/> />
</el-form-item> </el-form-item>
<el-form-item label="单据状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择单据状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.MES_WM_ARRIVAL_NOTICE_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item> <el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button @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>
@ -104,9 +77,9 @@
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="通知单编号" align="center" prop="code" min-width="160"> <el-table-column label="通知单编号" align="center" prop="code" min-width="160">
<template #default="scope"> <template #default="scope">
<el-link type="primary" @click="openForm('detail', scope.row.id)"> <el-button link type="primary" @click="openForm('detail', scope.row.id)">
{{ scope.row.code }} {{ scope.row.code }}
</el-link> </el-button>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="通知单名称" align="center" prop="name" min-width="150" /> <el-table-column label="通知单名称" align="center" prop="name" min-width="150" />
@ -131,7 +104,7 @@
<dict-tag :type="DICT_TYPE.MES_WM_ARRIVAL_NOTICE_STATUS" :value="scope.row.status" /> <dict-tag :type="DICT_TYPE.MES_WM_ARRIVAL_NOTICE_STATUS" :value="scope.row.status" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="220" fixed="right"> <el-table-column label="操作" align="center" width="160" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link
@ -142,15 +115,6 @@
> >
编辑 编辑
</el-button> </el-button>
<el-button
link
type="warning"
@click="handleSubmit(scope.row.id)"
v-hasPermi="['mes:wm-arrival-notice:update']"
v-if="scope.row.status === MesWmArrivalNoticeStatusEnum.PREPARE"
>
提交
</el-button>
<el-button <el-button
link link
type="danger" type="danger"
@ -160,6 +124,7 @@
> >
删除 删除
</el-button> </el-button>
<!-- TODO @AI待入库需要前往哪里操作是不是得有个提示给用户 -->
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -176,10 +141,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { dateFormatter2 } from '@/utils/formatTime' import { dateFormatter2 } from '@/utils/formatTime'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import download from '@/utils/download' import download from '@/utils/download'
import { WmArrivalNoticeApi, WmArrivalNoticeVO } from '@/api/mes/wm/arrivalnotice' import { WmArrivalNoticeApi, WmArrivalNoticeVO } from '@/api/mes/wm/arrivalnotice'
import { MdVendorApi } from '@/api/mes/md/vendor' import MdVendorSelect from '@/views/mes/md/vendor/components/MdVendorSelect.vue'
import ArrivalNoticeForm from './ArrivalNoticeForm.vue' import ArrivalNoticeForm from './ArrivalNoticeForm.vue'
import { MesWmArrivalNoticeStatusEnum } from '@/views/mes/utils/constants' import { MesWmArrivalNoticeStatusEnum } from '@/views/mes/utils/constants'
@ -192,7 +157,6 @@ const loading = ref(true) // 列表的加载中
const list = ref<WmArrivalNoticeVO[]>([]) // const list = ref<WmArrivalNoticeVO[]>([]) //
const total = ref(0) // const total = ref(0) //
const exportLoading = ref(false) // const exportLoading = ref(false) //
const vendorList = ref<any[]>([]) //
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@ -200,8 +164,7 @@ const queryParams = reactive({
name: undefined, name: undefined,
purchaseOrderCode: undefined, purchaseOrderCode: undefined,
vendorId: undefined, vendorId: undefined,
arrivalDate: undefined, arrivalDate: undefined
status: undefined
}) })
const queryFormRef = ref() // const queryFormRef = ref() //
@ -235,16 +198,6 @@ const openForm = (type: string, id?: number) => {
formRef.value.open(type, id) formRef.value.open(type, id)
} }
/** 提交 */
const handleSubmit = async (id: number) => {
try {
await message.confirm('确认提交该到货通知单?')
await WmArrivalNoticeApi.submitArrivalNotice(id)
message.success('提交成功')
await getList()
} catch {}
}
/** 删除 */ /** 删除 */
const handleDelete = async (id: number) => { const handleDelete = async (id: number) => {
try { try {
@ -269,8 +222,7 @@ const handleExport = async () => {
} }
/** 初始化 */ /** 初始化 */
onMounted(async () => { onMounted(() => {
vendorList.value = await MdVendorApi.getVendorSimpleList() getList()
await getList()
}) })
</script> </script>

View File

@ -213,6 +213,7 @@ const submitForm = async () => {
if (formType.value === 'create') { if (formType.value === 'create') {
const res = await WmItemReceiptApi.createItemReceipt(data) const res = await WmItemReceiptApi.createItemReceipt(data)
message.success('新增成功') message.success('新增成功')
//
formData.value.id = res formData.value.id = res
formData.value.status = MesWmItemReceiptStatusEnum.PREPARE formData.value.status = MesWmItemReceiptStatusEnum.PREPARE
formType.value = 'update' formType.value = 'update'