feat(mes):通过枚举和用户关联来重构缺陷处理流程,并增强内部质量控制功能

pull/871/MERGE
YunaiV 2026-02-20 22:49:14 +08:00
parent ccc58e9a74
commit e20122bd3c
6 changed files with 156 additions and 120 deletions

View File

@ -1,13 +1,12 @@
import request from '@/config/axios'
// TODO @AIdefect/index.ts
// MES 来料检验缺陷记录 VO
export interface QcIqcDefectVO {
id: number // 编号
iqcId: number // 来料检验单 ID
lineId: number // 来料检验行 ID
defectName: string // 缺陷描述
defectLevel: string // 缺陷等级
defectLevel: number // 缺陷等级
defectQuantity: number // 缺陷数量
remark: string // 备注
}

View File

@ -1,6 +1,5 @@
import request from '@/config/axios'
// TODO @AIline/index.ts
// MES 来料检验单行 VO
export interface QcIqcLineVO {
id: number // 编号

View File

@ -81,7 +81,7 @@
<el-form-item label="缺陷等级" prop="defectLevel">
<el-select v-model="formData.defectLevel" placeholder="请选择缺陷等级" class="!w-1/1">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.MES_DEFECT_LEVEL)"
v-for="dict in getIntDictOptions(DICT_TYPE.MES_DEFECT_LEVEL)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@ -110,13 +110,16 @@
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { QcIqcDefectApi, QcIqcDefectVO } from '@/api/mes/qc/iqc/defect'
import { QcIqcLineApi, QcIqcLineVO } from '@/api/mes/qc/iqc/line'
defineOptions({ name: 'IqcDefectList' })
const props = defineProps<{ iqcId: number }>()
const props = defineProps<{
iqcId: number
lineId?: number //
}>()
const message = useMessage()
const { t } = useI18n()
@ -133,7 +136,8 @@ const getList = async () => {
const data = await QcIqcDefectApi.getIqcDefectPage({
pageNo: 1,
pageSize: 100,
iqcId: props.iqcId
iqcId: props.iqcId,
lineId: props.lineId
})
list.value = data.list
} finally {
@ -161,7 +165,7 @@ const formRef = ref()
const formData = ref({
id: undefined,
iqcId: undefined as number | undefined,
lineId: undefined,
lineId: undefined as number | undefined,
defectName: undefined,
defectLevel: undefined,
defectQuantity: 1,
@ -180,6 +184,10 @@ const openForm = async (type: string, id?: number) => {
formType.value = type
resetForm()
formData.value.iqcId = props.iqcId
// lineId prop lineId
if (props.lineId) {
formData.value.lineId = props.lineId
}
//
await loadLineList()
//
@ -248,4 +256,10 @@ watch(
() => getList(),
{ immediate: true }
)
/** 监听 lineId 变化,重新加载列表 */
watch(
() => props.lineId,
() => getList()
)
</script>

View File

@ -2,9 +2,6 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1080px">
<!-- 基本信息表单 -->
<!-- TODO @AI分割线物料与供应商 -->
<!-- TODO @AI分割线检测情况 -->
<!-- TODO @AI分割线缺陷情况 -->
<el-form
ref="formRef"
:model="formData"
@ -42,6 +39,8 @@
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">物料与供应商</el-divider>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="供应商" prop="vendorId">
@ -49,15 +48,9 @@
v-model="formData.vendorId"
placeholder="请选择供应商"
class="!w-1/1"
@change="handleVendorChange"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="供应商简称">
<el-input :model-value="vendorNickname" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="供应商批次号" prop="vendorBatch">
<el-input v-model="formData.vendorBatch" placeholder="请输入供应商批次号" />
@ -86,6 +79,8 @@
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">检测情况</el-divider>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="接收数量" prop="receivedQuantity">
@ -153,15 +148,26 @@
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="检测结果" prop="checkResult">
<el-form-item label="检测人员" prop="inspectorUserId">
<UserSelect
v-model="formData.inspectorUserId"
placeholder="请选择检测人员"
class="!w-1/1"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="检测结论" prop="checkResult">
<el-select
v-model="formData.checkResult"
placeholder="请选择检测结果"
placeholder="请选择检测结"
clearable
class="!w-1/1"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.MES_QC_CHECK_RESULT)"
v-for="dict in getIntDictOptions(DICT_TYPE.MES_QC_CHECK_RESULT)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@ -169,71 +175,62 @@
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-col :span="16">
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<!-- 缺陷统计只读折叠 -->
<el-collapse v-if="formType === 'update' && formData.id">
<el-collapse-item title="缺陷统计" name="defectStats">
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="致命缺陷数">
<el-input :model-value="formData.criticalQuantity" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="严重缺陷数">
<el-input :model-value="formData.majorQuantity" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="轻微缺陷数">
<el-input :model-value="formData.minorQuantity" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="致命缺陷率">
<el-input :model-value="formData.criticalRate + '%'" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="严重缺陷率">
<el-input :model-value="formData.majorRate + '%'" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="轻微缺陷率">
<el-input :model-value="formData.minorRate + '%'" disabled />
</el-form-item>
</el-col>
</el-row>
</el-collapse-item>
</el-collapse>
<!-- 缺陷统计只读 -->
<template v-if="formType === 'update' && formData.id">
<el-divider content-position="left">缺陷情况</el-divider>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="致命缺陷数">
<el-input :model-value="formData.criticalQuantity" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="严重缺陷数">
<el-input :model-value="formData.majorQuantity" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="轻微缺陷数">
<el-input :model-value="formData.minorQuantity" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="致命缺陷率">
<el-input :model-value="formData.criticalRate + '%'" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="严重缺陷率">
<el-input :model-value="formData.majorRate + '%'" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="轻微缺陷率">
<el-input :model-value="formData.minorRate + '%'" disabled />
</el-form-item>
</el-col>
</el-row>
</template>
</el-form>
<!-- 子表标签页编辑模式下显示 -->
<template v-if="formType === 'update' && formData.id">
<el-divider />
<!-- TODO @AI检验项检测结果 -->
<el-tabs v-model="activeTab">
<el-tab-pane label="检验项" name="line">
<IqcLineList :iqc-id="formData.id" />
</el-tab-pane>
<el-tab-pane label="检测结果" name="defect">
<IqcDefectList :iqc-id="formData.id" /> <!-- TODO <--- 这个组件貌似是缺陷记录 -->
<!-- TODO @AI -->
<!-- TODO @AI样品编码生成操作 -->
<!-- TODO @AISN -->
<!-- TODO @AI备注 -->
<!-- TODO @AIel 风格符检测值检测项1检测值 -->
<el-tab-pane label="缺陷记录" name="defect">
<IqcDefectList :iqc-id="formData.id" />
</el-tab-pane>
</el-tabs>
</template>
@ -261,16 +258,15 @@
</template>
<script setup lang="ts">
import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { QcIqcApi, QcIqcVO } from '@/api/mes/qc/iqc'
import { QcTemplateApi } from '@/api/mes/qc/template'
import MdVendorSelect from '@/views/mes/md/vendor/components/MdVendorSelect.vue'
import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue'
import UserSelect from '@/views/system/user/components/UserSelect.vue'
import IqcLineList from './IqcLineList.vue'
import IqcDefectList from './IqcDefectList.vue'
// TODO @AI/Users/yunai/Java/yudao-all-in-one/yudao-ui-admin-vue3/src/views/mes/qc/indicator/IndicatorForm.vue
defineOptions({ name: 'IqcForm' })
const { t } = useI18n()
@ -283,8 +279,6 @@ const formType = ref('')
const activeTab = ref('line')
//
// TODO @AI
const vendorNickname = ref('')
const itemName = ref('')
const itemSpecification = ref('')
@ -312,7 +306,7 @@ const formData = ref({
checkResult: undefined,
receiveDate: undefined,
inspectDate: undefined,
inspector: undefined,
inspectorUserId: undefined,
remark: undefined,
status: 0,
//
@ -333,11 +327,6 @@ const formRules = reactive({
})
const formRef = ref()
/** 供应商变更回调 */
const handleVendorChange = (vendor: any) => {
vendorNickname.value = vendor?.nickname || ''
}
/** 物料变更回调 */
const handleItemChange = (item: any) => {
itemName.value = item?.name || ''
@ -360,7 +349,6 @@ const open = async (type: string, id?: number) => {
const data = await QcIqcApi.getIqc(id)
formData.value = data
//
vendorNickname.value = data.vendorNickname || ''
itemName.value = data.itemName || ''
itemSpecification.value = data.itemSpecification || ''
} finally {
@ -434,7 +422,7 @@ const resetForm = () => {
checkResult: undefined,
receiveDate: undefined,
inspectDate: undefined,
inspector: undefined,
inspectorUserId: undefined,
remark: undefined,
status: 0,
criticalRate: 0,
@ -444,7 +432,7 @@ const resetForm = () => {
majorQuantity: 0,
minorQuantity: 0
}
vendorNickname.value = ''
// TODO @AI item
itemName.value = ''
itemSpecification.value = ''
formRef.value?.resetFields()

View File

@ -3,7 +3,6 @@
<div>
<!-- 列表 -->
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<!-- TODO @AI检测项名称检测项类型检测工具检测要求标准值单位误差上限误差下限致命缺陷数严重缺陷数轻微缺陷数备注 -->
<el-table-column label="检测指标编码" align="center" prop="indicatorCode" width="140" />
<el-table-column label="检测指标名称" align="center" prop="indicatorName" min-width="150" />
<el-table-column label="检测指标类型" align="center" prop="indicatorType" width="120">
@ -20,14 +19,24 @@
<el-table-column label="致命缺陷数" align="center" prop="criticalQuantity" width="100" />
<el-table-column label="严重缺陷数" align="center" prop="majorQuantity" width="100" />
<el-table-column label="轻微缺陷数" align="center" prop="minorQuantity" width="100" />
<!-- TODO @AI操作缺陷记录弹窗 -->
<el-table-column label="操作" align="center" width="100" fixed="right">
<template #default="scope">
<el-button link type="primary" @click="openDefectDialog(scope.row)"> </el-button>
</template>
</el-table-column>
</el-table>
<!-- 缺陷记录弹窗 -->
<Dialog title="缺陷记录" v-model="defectDialogVisible" width="900px">
<IqcDefectList :iqc-id="props.iqcId" :line-id="currentLineId!" />
</Dialog>
</div>
</template>
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
import { QcIqcLineApi, QcIqcLineVO } from '@/api/mes/qc/iqc/line'
import IqcDefectList from './IqcDefectList.vue'
defineOptions({ name: 'IqcLineList' })
@ -36,6 +45,16 @@ const props = defineProps<{ iqcId: number }>()
const loading = ref(false)
const list = ref<QcIqcLineVO[]>([])
//
const defectDialogVisible = ref(false)
const currentLineId = ref<number>()
/** 打开缺陷记录弹窗 */
const openDefectDialog = (row: QcIqcLineVO) => {
currentLineId.value = row.id
defectDialogVisible.value = true
}
/** 查询列表 */
const getList = async () => {
if (!props.iqcId) return

View File

@ -43,28 +43,15 @@
class="!w-240px"
/>
</el-form-item>
<!-- TODO @AI检测结论 -->
<!-- TODO @AI字典只需要校验通过校验不通过 -->
<el-form-item label="检测结果" prop="checkResult">
<el-form-item label="检测结论" prop="checkResult">
<el-select
v-model="queryParams.checkResult"
placeholder="请选择检测结"
placeholder="请选择检测结"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.MES_QC_CHECK_RESULT)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<!-- TODO @AI单据状态去掉 -->
<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_QC_IQC_STATUS)"
v-for="dict in getIntDictOptions(DICT_TYPE.MES_QC_CHECK_RESULT)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@ -93,7 +80,14 @@
class="!w-240px"
/>
</el-form-item>
<!-- TODO @AI检测人员下拉选择 -->
<el-form-item label="检测人员" prop="inspectorUserId">
<UserSelect
v-model="queryParams.inspectorUserId"
placeholder="请选择检测人员"
clearable
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<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>
@ -121,18 +115,16 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<!-- TODO @AI来料检验单编号来料检验单名称 -->
<el-table-column label="检验单编号" align="center" prop="code" width="160" />
<el-table-column label="检验单名称" align="center" prop="name" min-width="180" />
<el-table-column label="来料检验单编号" align="center" prop="code" width="160" />
<el-table-column label="来料检验单名称" align="center" prop="name" min-width="180" />
<el-table-column label="供应商简称" align="center" prop="vendorNickname" width="120" />
<el-table-column label="供应商批次号" align="center" prop="vendorBatch" width="130" />
<!-- TODO @AI产品物料编码产品物料名称 -->
<el-table-column label="物料编码" align="center" prop="itemCode" width="130" />
<el-table-column label="物料名称" align="center" prop="itemName" min-width="150" />
<el-table-column label="产品物料编码" align="center" prop="itemCode" width="130" />
<el-table-column label="产品物料名称" align="center" prop="itemName" min-width="150" />
<el-table-column label="接收数量" align="center" prop="receivedQuantity" width="100" />
<el-table-column label="检测数量" align="center" prop="checkQuantity" width="100" />
<el-table-column label="不合格数" align="center" prop="unqualifiedQuantity" width="100" />
<el-table-column label="检测结" align="center" prop="checkResult" width="100">
<el-table-column label="检测结" align="center" prop="checkResult" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_QC_CHECK_RESULT" :value="scope.row.checkResult" />
</template>
@ -151,31 +143,38 @@
:formatter="dateFormatter2"
width="180px"
/>
<el-table-column label="检测人员" align="center" prop="inspector" width="100" />
<el-table-column label="检测人员" align="center" prop="inspectorNickname" width="100" />
<el-table-column label="单据状态" align="center" prop="status" width="80">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_QC_IQC_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="130" fixed="right">
<!-- TODO @AI完成是否完成来料检验单编制完成后将不能更改 -->
<el-table-column label="操作" align="center" width="180" fixed="right">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['mes:qc-iqc:update']"
v-if="scope.row.status === 0"
v-if="scope.row.status === QC_IQC_STATUS.PREPARE"
>
编辑
</el-button>
<!-- TODO @AIstatus 枚举值 -->
<el-button
link
type="success"
@click="handleComplete(scope.row.id)"
v-hasPermi="['mes:qc-iqc:update']"
v-if="scope.row.status === QC_IQC_STATUS.PREPARE"
>
完成
</el-button>
<!-- TODO @芋艿查看报表后续要搞下 -->
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-if="scope.row.status !== 0"
v-if="scope.row.status !== QC_IQC_STATUS.PREPARE"
>
查看报表
</el-button>
@ -184,7 +183,7 @@
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['mes:qc-iqc:delete']"
v-if="scope.row.status === 0"
v-if="scope.row.status === QC_IQC_STATUS.PREPARE"
>
删除
</el-button>
@ -209,12 +208,20 @@ import { dateFormatter2 } from '@/utils/formatTime'
import download from '@/utils/download'
import { QcIqcApi, QcIqcVO } from '@/api/mes/qc/iqc'
import IqcForm from './IqcForm.vue'
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import MdVendorSelect from '@/views/mes/md/vendor/components/MdVendorSelect.vue'
import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue'
import UserSelect from '@/views/system/user/components/UserSelect.vue'
defineOptions({ name: 'MesQcIqc' })
/** IQC 状态枚举 */
// TODO @AI constants
const QC_IQC_STATUS = {
PREPARE: 0,
FINISHED: 1
}
const message = useMessage()
const { t } = useI18n()
@ -229,9 +236,9 @@ const queryParams = reactive({
vendorBatch: undefined,
itemId: undefined,
checkResult: undefined,
status: undefined,
receiveDate: undefined,
inspectDate: undefined
inspectDate: undefined,
inspectorUserId: undefined
})
const queryFormRef = ref()
const exportLoading = ref(false)
@ -266,6 +273,16 @@ const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 完成操作 */
const handleComplete = async (id: number) => {
try {
await message.confirm('是否完成来料检验单编制?【完成后将不能更改】')
await QcIqcApi.completeIqc(id)
message.success('完成成功')
await getList()
} catch {}
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {