feat(mes): 新增物料批次属性配置前端组件

1. 新增 MdItemBatchConfigForm 组件,根据 itemOrProduct 区分 ITEM/PRODUCT 展示不同 checkbox
2. 嵌入 MdItemForm 的"批次属性"tab,仅 batchFlag 开启时显示
3. API 文件放置于 batchConfig/index.ts 子目录
4. 使用 MesItemOrProductEnum 常量替代硬编码字符串
5. MdItemForm 变量名语义优化:itemTypeList → itemTypeTree,itemTypeFlatList → itemTypeList
6. 布局优化:采用 CSS Grid 一行 5 个,checkbox label 模式(☑ 文字)
pull/871/MERGE
YunaiV 2026-02-16 01:28:10 +08:00
parent 3d103f1f46
commit 15dd4dce76
3 changed files with 173 additions and 7 deletions

View File

@ -0,0 +1,34 @@
import request from '@/config/axios'
// MES 物料批次属性配置 VO
export interface MdItemBatchConfigVO {
id?: number // 编号
itemId: number // 物料编号
produceDateFlag: boolean // 批次属性-生产日期
expireDateFlag: boolean // 批次属性-有效期
receiptDateFlag: boolean // 批次属性-入库日期
vendorFlag: boolean // 批次属性-供应商
clientFlag: boolean // 批次属性-客户
salesOrderCodeFlag: boolean // 批次属性-销售订单编号
purchaseOrderCodeFlag: boolean // 批次属性-采购订单编号
workorderFlag: boolean // 批次属性-生产工单
taskFlag: boolean // 批次属性-生产任务
workstationFlag: boolean // 批次属性-工位
toolFlag: boolean // 批次属性-工具
moldFlag: boolean // 批次属性-模具
lotNumberFlag: boolean // 批次属性-生产批号
qualityStatusFlag: boolean // 批次属性-质量状态
}
// MES 物料批次属性配置 API
export const MdItemBatchConfigApi = {
// 根据物料编号获取批次属性配置
getBatchConfigByItemId: async (itemId: number) => {
return await request.get({ url: `/mes/md/item-batch-config/get-by-item-id?itemId=` + itemId })
},
// 保存批次属性配置(新增或更新)
saveBatchConfig: async (data: MdItemBatchConfigVO) => {
return await request.post({ url: `/mes/md/item-batch-config/save`, data })
}
}

View File

@ -0,0 +1,122 @@
<!-- MES 物料批次属性配置 -->
<template>
<el-form ref="formRef" :model="formData" v-loading="loading">
<div class="flex justify-end mb-10px">
<el-button type="primary" size="small" @click="handleSave" :loading="loading">保存批次属性</el-button>
</div>
<div class="batch-config-grid">
<!-- 通用属性ITEM PRODUCT 都可见 -->
<el-checkbox v-model="formData.produceDateFlag"></el-checkbox>
<el-checkbox v-model="formData.qualityStatusFlag"></el-checkbox>
<!-- ITEM原材料特有属性 -->
<template v-if="itemOrProduct === MesItemOrProductEnum.ITEM.value">
<el-checkbox v-model="formData.vendorFlag"></el-checkbox>
<el-checkbox v-model="formData.purchaseOrderCodeFlag"></el-checkbox>
<el-checkbox v-model="formData.lotNumberFlag"></el-checkbox>
<el-checkbox v-model="formData.expireDateFlag"></el-checkbox>
<el-checkbox v-model="formData.receiptDateFlag"></el-checkbox>
</template>
<!-- PRODUCT产品特有属性 -->
<template v-if="itemOrProduct === MesItemOrProductEnum.PRODUCT.value">
<el-checkbox v-model="formData.clientFlag"></el-checkbox>
<el-checkbox v-model="formData.salesOrderCodeFlag"></el-checkbox>
<el-checkbox v-model="formData.workorderFlag"></el-checkbox>
<el-checkbox v-model="formData.taskFlag"></el-checkbox>
<el-checkbox v-model="formData.workstationFlag"></el-checkbox>
<el-checkbox v-model="formData.toolFlag"></el-checkbox>
<el-checkbox v-model="formData.moldFlag"></el-checkbox>
</template>
</div>
</el-form>
</template>
<script setup lang="ts">
import { MdItemBatchConfigApi, MdItemBatchConfigVO } from '@/api/mes/md/item/batchConfig'
import { MesItemOrProductEnum } from '@/views/mes/utils/constants'
defineOptions({ name: 'MdItemBatchConfigForm' })
const props = defineProps<{
itemId: number
itemOrProduct: string // 'ITEM' | 'PRODUCT'
}>()
const message = useMessage()
const loading = ref(false)
const formRef = ref()
const formData = ref<MdItemBatchConfigVO>({
itemId: props.itemId,
produceDateFlag: false,
expireDateFlag: false,
receiptDateFlag: false,
vendorFlag: false,
clientFlag: false,
salesOrderCodeFlag: false,
purchaseOrderCodeFlag: false,
workorderFlag: false,
taskFlag: false,
workstationFlag: false,
toolFlag: false,
moldFlag: false,
lotNumberFlag: false,
qualityStatusFlag: false
})
/** 加载已有配置 */
const loadData = async () => {
loading.value = true
try {
const data = await MdItemBatchConfigApi.getBatchConfigByItemId(props.itemId)
if (data) {
formData.value = { ...formData.value, ...data }
}
} finally {
loading.value = false
}
}
/** 保存 */
const handleSave = async () => {
//
const hasAny =
formData.value.produceDateFlag ||
formData.value.expireDateFlag ||
formData.value.receiptDateFlag ||
formData.value.vendorFlag ||
formData.value.clientFlag ||
formData.value.salesOrderCodeFlag ||
formData.value.purchaseOrderCodeFlag ||
formData.value.workorderFlag ||
formData.value.taskFlag ||
formData.value.workstationFlag ||
formData.value.toolFlag ||
formData.value.moldFlag ||
formData.value.lotNumberFlag ||
formData.value.qualityStatusFlag
if (!hasAny) {
message.warning('至少选择一个批次属性')
return
}
loading.value = true
try {
formData.value.itemId = props.itemId
await MdItemBatchConfigApi.saveBatchConfig(formData.value)
message.success('保存成功')
} finally {
loading.value = false
}
}
onMounted(() => loadData())
</script>
<style lang="scss" scoped>
.batch-config-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 0 20px;
}
</style>

View File

@ -46,7 +46,7 @@
<el-form-item label="物料分类" prop="itemTypeId">
<el-tree-select
v-model="formData.itemTypeId"
:data="itemTypeList"
:data="itemTypeTree"
:props="defaultProps"
check-strictly
default-expand-all
@ -118,9 +118,8 @@
<el-tab-pane label="BOM 组成" name="bom" lazy>
<el-empty description="BOM 组成(待实现)" />
</el-tab-pane>
<!-- TODO @芋艿批次属性等批次模块实现后对接 -->
<el-tab-pane label="批次属性" name="batch" lazy>
<el-empty description="批次属性(待实现)" />
<el-tab-pane label="批次属性" name="batch" lazy v-if="formData.batchFlag">
<MdItemBatchConfigForm :itemId="formData.id!" :itemOrProduct="currentItemOrProduct" />
</el-tab-pane>
<!-- TODO @芋艿替代品等替代品模块实现后对接 -->
<el-tab-pane label="替代品" name="substitute" lazy>
@ -145,6 +144,7 @@ import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { generateRandomStr } from '@/utils'
import { MdItemApi, MdItemVO } from '@/api/mes/md/item'
import { MdItemTypeApi, MdItemTypeVO } from '@/api/mes/md/item/type'
import MdItemBatchConfigForm from './MdItemBatchConfigForm.vue'
import { MdUnitMeasureApi, MdUnitMeasureVO } from '@/api/mes/md/unitmeasure'
import { CommonStatusEnum } from '@/utils/constants'
import { defaultProps, handleTree } from '@/utils/tree'
@ -183,9 +183,19 @@ const formRules = reactive({
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
const itemTypeList = ref<MdItemTypeVO[]>([]) //
const itemTypeTree = ref<MdItemTypeVO[]>([]) //
const itemTypeList = ref<MdItemTypeVO[]>([]) //
const unitMeasureList = ref<MdUnitMeasureVO[]>([]) //
/** 当前物料的「物料/产品」标识 */
const currentItemOrProduct = computed(() => {
if (!formData.value.itemTypeId) {
return ''
}
const itemType = itemTypeList.value.find((t) => t.id === formData.value.itemTypeId)
return itemType?.itemOrProduct || ''
})
/** 生成物料编码 */
const generateCode = () => {
// TODO @
@ -209,8 +219,8 @@ const open = async (type: string, id?: number) => {
}
}
//
const categoryData = await MdItemTypeApi.getItemTypeSimpleList()
itemTypeList.value = handleTree(categoryData, 'id', 'parentId')
itemTypeList.value = await MdItemTypeApi.getItemTypeSimpleList()
itemTypeTree.value = handleTree(itemTypeList.value)
//
unitMeasureList.value = await MdUnitMeasureApi.getUnitMeasureSimpleList()
}