Files
mom-web/src/views/mes/quality/productquality/components/QualityDialog.vue
2026-03-05 16:52:12 +08:00

1247 lines
44 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-dialog
:title="title"
v-model="dialogVisible"
width="800px"
append-to-body
:close-on-click-modal="false"
@closed="handleClosed"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<!-- 批次信息 -->
<el-form-item label="批次编号" prop="workOrderCode">
<el-select
v-model="form.workOrderCode"
placeholder="请选择或输入批次编号"
filterable
allow-create
default-first-option
:disabled="type === 'view' || type === 'edit'"
@change="handleWorkOrderChange"
>
<el-option
v-for="item in workOrderOptions"
:key="item.id"
:label="`${item.code} - ${item.productName}`"
:value="item.code"
/>
</el-select>
</el-form-item>
<!-- 产品信息 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="产品编号" prop="productCode">
<el-input
v-model="form.productCode"
:disabled="type === 'view'"
placeholder="请输入产品编号"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="产品名称" prop="productName">
<el-input
v-model="form.productName"
:disabled="type === 'view'"
placeholder="请输入产品名称"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 质检信息 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="质检状态" prop="status">
<el-select
v-model="form.status"
placeholder="请选择质检状态"
:disabled="type === 'view'"
>
<el-option label="待检" :value="0" />
<el-option label="检验中" :value="1" />
<el-option label="已完成" :value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="质检时间" prop="inspectionTime">
<el-date-picker
v-model="form.inspectionTime"
type="datetime"
placeholder="选择质检时间"
:disabled="type === 'view'"
value-format="YYYY-MM-DDTHH:mm:ss"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 公共重量 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="重量" prop="weight">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.weight"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">kg</span>
</div>
</el-form-item>
</el-col>
</el-row>
<!-- 质检结果 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否合格" prop="qualified">
<el-radio-group v-model="form.qualified" :disabled="type === 'view'">
<el-radio :label="1">合格</el-radio>
<el-radio :label="0">不合格</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="质检员" prop="inspectorName">
<el-input v-model="form.inspectorName" :disabled="type === 'view'" />
</el-form-item>
</el-col>
</el-row>
<!-- 不合格原因 -->
<el-form-item label="不合格原因" prop="unqualifiedReason" v-if="!form.qualified">
<el-input
v-model="form.unqualifiedReason"
type="textarea"
:rows="3"
placeholder="请输入不合格原因"
:disabled="type === 'view'"
/>
</el-form-item>
<!-- 番茄类产品附加检验 -->
<template v-if="isTomatoProduct">
<el-divider>番茄类产品附加检验</el-divider>
<!-- 工艺冷破/热破 -->
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="工艺" prop="tomatoProcess">
<el-radio-group v-model="form.tomatoProcess" :disabled="type === 'view'">
<el-radio label="冷破">冷破</el-radio>
<el-radio label="热破">热破</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<!-- 浓度 -->
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="浓度">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.tomatoConcentration"
:min="0"
:step="0.1"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">%</span>
</div>
</el-form-item>
</el-col>
</el-row>
<!-- 数量 -->
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="数量">
<el-input-number
v-model="form.tomatoQuantity"
:min="0"
:step="1"
:precision="0"
:disabled="type === 'view'"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="感官">
<el-input
v-model="form.tomatoSensory"
type="textarea"
:rows="3"
:disabled="type === 'view'"
/>
</el-form-item>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="可溶性固形物">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.tomatoSolubleSolidsPercent"
:min="0"
:step="0.1"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">% (20阿贝折射仪)</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="粘稠度">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.tomatoViscosityCmPer"
:min="0"
:step="0.1"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">cm/30s (20固形物12.5%)</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="番茄红素">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.tomatoLycopeneMgPer"
:min="0"
:step="0.1"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">mg/100g</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="总酸">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.tomatoTotalAcidPercent"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">% (以无水柠檬酸计)</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="PH value">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.tomatoPhValue"
:min="0"
:max="14"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="色差 a/b">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.tomatoColorDifference"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">(固形物12.5%)</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="霉菌">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.tomatoMouldPositivePercent"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<span>% 阳性视野无致病菌及微生物作用引起的腐败现象</span>
</div>
</el-form-item>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="评定">
<el-radio-group v-model="form.tomatoAssessConformance" :disabled="type === 'view'">
<el-radio :label="1">品质符合</el-radio>
<el-radio :label="0">品质不符合</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="评定说明">
<el-input
v-model="form.tomatoAssessRemark"
placeholder="填写规定要求等说明"
:disabled="type === 'view'"
/>
</el-form-item>
</el-col>
</el-row>
</template>
<!-- 甜菊糖产品附加检验 -->
<template v-if="isSteviaProduct">
<el-divider>甜菊糖产品附加检验</el-divider>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="标签">
<div style="display: flex; align-items: center; gap: 8px">
<el-input
v-model="form.steviaLabel"
:disabled="type === 'view'"
type="textarea"
:autosize="{ minRows: 10, maxRows: 30 }"
style="flex: 1; min-width: 300px"
/>
<el-tooltip
content="应标注内容:添加剂名称,配料清单、净含量、制造商名称,地址、生产日期、储存说明、产品标准号、生产许可证号,产品介绍、使用方法和范围、用途、有添加剂字样"
placement="top"
>
<Icon icon="ep:warning-filled" />
</el-tooltip>
<el-checkbox v-model="form.steviaLabelOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="20">-->
<!-- <el-col :span="24">-->
<!-- <el-form-item label="色泽">-->
<!-- <div style="display: flex; align-items: center; gap: 8px">-->
<!-- <el-input v-model="form.steviaColor" :disabled="type === 'view'" />-->
<!-- <el-tooltip content="白色至浅黄色" placement="top">-->
<!-- <Icon icon="ep:warning-filled" />-->
<!-- </el-tooltip>-->
<!-- <el-checkbox v-model="form.steviaColorOk" :disabled="type === 'view'"-->
<!-- >合格</el-checkbox-->
<!-- >-->
<!-- </div>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- <el-row :gutter="20">-->
<!-- <el-col :span="24">-->
<!-- <el-form-item label="状态">-->
<!-- <div style="display: flex; align-items: center; gap: 8px">-->
<!-- <el-input v-model="form.steviaState" :disabled="type === 'view'" />-->
<!-- <el-tooltip content="粉末、晶体、颗粒或片状" placement="top">-->
<!-- <Icon icon="ep:warning-filled" />-->
<!-- </el-tooltip>-->
<!-- <el-checkbox v-model="form.steviaStateOk" :disabled="type === 'view'"-->
<!-- >合格</el-checkbox-->
<!-- >-->
<!-- </div>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- </el-row>-->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="甜菊糖苷含量">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaGlycosidesPercent"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">%</span>
<el-tooltip content="≥ 80.0" placement="top">
<Icon icon="ep:warning-filled" />
</el-tooltip>
<el-checkbox v-model="form.steviaGlycosidesPercentOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="灰分">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaAshPercent"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">%</span>
<el-tooltip content="≤ 1.0" placement="top">
<Icon icon="ep:warning-filled" />
</el-tooltip>
<el-checkbox v-model="form.steviaAshPercentOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="20">-->
<!-- <el-col :span="24">-->
<!-- <el-form-item label="干燥减重">-->
<!-- <div style="display: flex; align-items: center; gap: 8px">-->
<!-- <el-input-number-->
<!-- v-model="form.steviaLossOnDryingPercent"-->
<!-- :min="0"-->
<!-- :step="0.01"-->
<!-- :precision="4"-->
<!-- :disabled="type === 'view'"-->
<!-- />-->
<!-- <span style="white-space: nowrap">%</span>-->
<!-- <el-tooltip content="≤ 6.0" placement="top">-->
<!-- <Icon icon="ep:warning-filled" />-->
<!-- </el-tooltip>-->
<!-- <el-checkbox-->
<!-- v-model="form.steviaLossOnDryingPercentOk"-->
<!-- :disabled="type === 'view'"-->
<!-- >合格</el-checkbox-->
<!-- >-->
<!-- </div>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- <el-row :gutter="20">-->
<!-- <el-col :span="24">-->
<!-- <el-form-item label="甲醇">-->
<!-- <div style="display: flex; align-items: center; gap: 8px">-->
<!-- <el-input-number-->
<!-- v-model="form.steviaMethanolMgPerKg"-->
<!-- :min="0"-->
<!-- :step="0.01"-->
<!-- :precision="4"-->
<!-- :disabled="type === 'view'"-->
<!-- />-->
<!-- <span style="white-space: nowrap">mg/kg</span>-->
<!-- <el-tooltip content="≤ 200" placement="top">-->
<!-- <Icon icon="ep:warning-filled" />-->
<!-- </el-tooltip>-->
<!-- <el-checkbox v-model="form.steviaMethanolMgPerKgOk" :disabled="type === 'view'"-->
<!-- >合格</el-checkbox-->
<!-- >-->
<!-- </div>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- <el-row :gutter="20">-->
<!-- <el-col :span="24">-->
<!-- <el-form-item label="乙醇">-->
<!-- <div style="display: flex; align-items: center; gap: 8px">-->
<!-- <el-input-number-->
<!-- v-model="form.steviaEthanolMgPerKg"-->
<!-- :min="0"-->
<!-- :step="0.01"-->
<!-- :precision="4"-->
<!-- :disabled="type === 'view'"-->
<!-- />-->
<!-- <span style="white-space: nowrap">mg/kg</span>-->
<!-- <el-tooltip content="≤ 5000" placement="top">-->
<!-- <Icon icon="ep:warning-filled" />-->
<!-- </el-tooltip>-->
<!-- <el-checkbox v-model="form.steviaEthanolMgPerKgOk" :disabled="type === 'view'"-->
<!-- >合格</el-checkbox-->
<!-- >-->
<!-- </div>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- <el-row :gutter="20">-->
<!-- <el-col :span="24">-->
<!-- <el-form-item label="铅">-->
<!-- <div style="display: flex; align-items: center; gap: 8px">-->
<!-- <el-input-number-->
<!-- v-model="form.steviaLeadMgPerKg"-->
<!-- :min="0"-->
<!-- :step="0.01"-->
<!-- :precision="4"-->
<!-- :disabled="type === 'view'"-->
<!-- />-->
<!-- <span style="white-space: nowrap">mg/kg</span>-->
<!-- <el-tooltip content="≤ 1.0" placement="top">-->
<!-- <Icon icon="ep:warning-filled" />-->
<!-- </el-tooltip>-->
<!-- <el-checkbox v-model="form.steviaLeadMgPerKgOk" :disabled="type === 'view'"-->
<!-- >合格</el-checkbox-->
<!-- >-->
<!-- </div>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- <el-row :gutter="20">-->
<!-- <el-col :span="24">-->
<!-- <el-form-item label="总砷">-->
<!-- <div style="display: flex; align-items: center; gap: 8px">-->
<!-- <el-input-number-->
<!-- v-model="form.steviaTotalArsenicMgPerKg"-->
<!-- :min="0"-->
<!-- :step="0.01"-->
<!-- :precision="4"-->
<!-- :disabled="type === 'view'"-->
<!-- />-->
<!-- <span style="white-space: nowrap">mg/kg</span>-->
<!-- <el-tooltip content="≤ 1.0" placement="top">-->
<!-- <Icon icon="ep:warning-filled" />-->
<!-- </el-tooltip>-->
<!-- <el-checkbox-->
<!-- v-model="form.steviaTotalArsenicMgPerKgOk"-->
<!-- :disabled="type === 'view'"-->
<!-- >合格</el-checkbox-->
<!-- >-->
<!-- </div>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- 新增字段 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="RD">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaRd"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaRdOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="RA">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaRa"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaRaOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="STV">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaStv"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaStvOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="RF">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaRf"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaRfOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="RC">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaRc"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaRcOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="DA">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaDa"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaDaOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="RV">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaRv"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaRvOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="RB">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaRb"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaRbOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="SB">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaSb"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaSbOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="水分">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaMoisture"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">%</span>
<el-checkbox v-model="form.steviaMoistureOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="比吸光">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaSpecificAbsorbance"
:min="0"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-checkbox v-model="form.steviaSpecificAbsorbanceOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="透光率">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaTransmittance"
:min="0"
:max="100"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<span style="white-space: nowrap">%</span>
<el-checkbox v-model="form.steviaTransmittanceOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="PH value">
<div style="display: flex; align-items: center; gap: 8px">
<el-input-number
v-model="form.steviaPhValue"
:min="0"
:max="14"
:step="0.01"
:precision="4"
:disabled="type === 'view'"
/>
<el-tooltip content="4.5-7.0" placement="top">
<Icon icon="ep:warning-filled" />
</el-tooltip>
<el-checkbox v-model="form.steviaPhValueOk" :disabled="type === 'view'"
>合格</el-checkbox
>
</div>
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="20">-->
<!-- <el-col :span="12">-->
<!-- <el-form-item label="产量">-->
<!-- <div style="display: flex; align-items: center; gap: 8px">-->
<!-- <el-input-number-->
<!-- v-model="form.steviaYield"-->
<!-- :min="0"-->
<!-- :step="0.01"-->
<!-- :precision="4"-->
<!-- :disabled="type === 'view'"-->
<!-- />-->
<!-- <span style="white-space: nowrap">kg</span>-->
<!-- <el-checkbox v-model="form.steviaYieldOk" :disabled="type === 'view'"-->
<!-- >合格</el-checkbox-->
<!-- >-->
<!-- </div>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- </el-row>-->
<el-form-item label="甜菊糖备注">
<el-input
v-model="form.steviaRemark"
type="textarea"
:rows="3"
placeholder="请输入甜菊糖相关备注"
:disabled="type === 'view'"
/>
</el-form-item>
</template>
<!-- 备注 -->
<el-form-item label="备注" prop="remark">
<el-input
v-model="form.remark"
type="textarea"
:rows="3"
placeholder="请输入备注"
:disabled="type === 'view'"
/>
</el-form-item>
<!-- 附件 -->
<el-form-item label="附件" prop="attachmentUrls">
<UploadFile
v-model="form.attachmentUrls"
:disabled="type === 'view'"
:limit="1"
:file-size="10"
:file-type="['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xls', 'xlsx']"
:is-show-tip="true"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button v-if="type !== 'view'" type="primary" @click="submitForm"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch, defineProps, defineEmits, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { YVHgetWorkOrderSimpleList } from '@/api/mes/production/workorder'
import {
createFinishedProductQuality,
updateFinishedProductQuality
} from '@/api/mes/quality/productquality/index'
import UploadFile from '@/components/UploadFile/src/UploadFile.vue'
import { Icon } from '@/components/Icon'
import { useUserStore } from '@/store/modules/user'
const props = defineProps({
visible: {
type: Boolean,
default: false
},
type: {
type: String,
default: 'create'
},
title: {
type: String,
default: ''
},
data: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['update:visible', 'submit', 'closed'])
// 用户store
const userStore = useUserStore()
// 批次选项
const workOrderOptions = ref<any[]>([])
// 获取当前时间字符串
const getCurrentTimeString = () => {
const now = new Date()
const y = now.getFullYear()
const m = String(now.getMonth() + 1).padStart(2, '0')
const d = String(now.getDate()).padStart(2, '0')
const hh = String(now.getHours()).padStart(2, '0')
const mm = String(now.getMinutes()).padStart(2, '0')
const ss = String(now.getSeconds()).padStart(2, '0')
return `${y}-${m}-${d}T${hh}:${mm}:${ss}`
}
// 获取中文日期YYYY 年 MM 月 DD 日)
const getCurrentDateCN = () => {
const now = new Date()
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0')
return `${year}${month}${day}`
}
// 番茄类默认值
const getTomatoDefaults = () => ({
tomatoProcess: '冷破',
tomatoConcentration: undefined as number | undefined,
tomatoQuantity: undefined as number | undefined,
tomatoSensory:
'色泽、气滋味、组织、形态均正常,无恶性杂质\n[sensory analysis: color and luster, flavor,tissue; form are normal, without impurity]',
tomatoSolubleSolidsPercent: undefined as number | undefined,
tomatoViscosityCmPer: undefined as number | undefined,
tomatoLycopeneMgPer: undefined as number | undefined,
tomatoTotalAcidPercent: undefined as number | undefined,
tomatoPhValue: undefined as number | undefined,
tomatoColorDifference: undefined as number | undefined,
tomatoMouldPositivePercent: undefined as number | undefined,
tomatoAssessConformance: 1 as 1 | 0,
tomatoAssessRemark: ''
})
// 甜菊糖默认值
const getSteviaDefaults = () => ({
steviaLabel: `食品添加剂名称: 甜菊糖苷\n配料清单: 从甜叶菊中天然提取\n净含量: 每袋 10kg\n生产商: 甘肃西域阳光管理平台食品有限公司\n地址: 甘肃金塔县金塔镇解放路42号\n储存说明: 常温保存 24 个月\n用途: 食品添加剂,使用方法和范围见国家标准规定\n生产许可证号: SC10962092100105\n产品标准: GB1886.355-2022\n生产日期: ${getCurrentDateCN()}`,
steviaColor: '',
steviaState: '',
steviaGlycosidesPercent: undefined as number | undefined,
steviaAshPercent: undefined as number | undefined,
steviaLossOnDryingPercent: undefined as number | undefined,
steviaMethanolMgPerKg: undefined as number | undefined,
steviaEthanolMgPerKg: undefined as number | undefined,
steviaLeadMgPerKg: undefined as number | undefined,
steviaTotalArsenicMgPerKg: undefined as number | undefined,
steviaPhValue: undefined as number | undefined,
// 合格勾选项默认值
steviaLabelOk: true,
steviaColorOk: true,
steviaStateOk: true,
steviaGlycosidesPercentOk: true,
steviaAshPercentOk: true,
steviaLossOnDryingPercentOk: true,
steviaMethanolMgPerKgOk: true,
steviaEthanolMgPerKgOk: true,
steviaLeadMgPerKgOk: true,
steviaTotalArsenicMgPerKgOk: true,
steviaPhValueOk: true,
steviaRd: undefined as number | undefined,
steviaRdOk: true,
steviaRa: undefined as number | undefined,
steviaRaOk: true,
steviaStv: undefined as number | undefined,
steviaStvOk: true,
steviaRf: undefined as number | undefined,
steviaRfOk: true,
steviaRc: undefined as number | undefined,
steviaRcOk: true,
steviaDa: undefined as number | undefined,
steviaDaOk: true,
steviaRv: undefined as number | undefined,
steviaRvOk: true,
steviaRb: undefined as number | undefined,
steviaRbOk: true,
steviaSb: undefined as number | undefined,
steviaSbOk: true,
steviaMoisture: undefined as number | undefined,
steviaMoistureOk: true,
steviaSpecificAbsorbance: undefined as number | undefined,
steviaSpecificAbsorbanceOk: true,
steviaTransmittance: undefined as number | undefined,
steviaTransmittanceOk: true,
steviaYield: undefined as number | undefined,
steviaYieldOk: true,
steviaRemark: ''
})
// 表单数据
const form = reactive({
code: '',
workOrderId: undefined as number | undefined,
workOrderCode: '',
productId: undefined as number | undefined,
productCode: '',
productName: '',
status: 0,
inspectionTime: getCurrentTimeString(),
weight: undefined as number | undefined,
qualified: 1,
unqualifiedReason: '',
inspectorName: userStore.getUser.nickname || '',
attachmentUrls: '',
remark: '',
...getTomatoDefaults(),
...getSteviaDefaults()
})
// 计算:是否番茄类产品
const isTomatoProduct = computed(() => {
const code = (form.workOrderCode || '').toString().toUpperCase()
return code.startsWith('X8')
})
// 计算是否甜菊糖产品X 开头但排除 X8
const isSteviaProduct = computed(() => {
const code = (form.workOrderCode || '').toString().toUpperCase()
return code.startsWith('X') && !code.startsWith('X8')
})
// 甜菊糖字段阈值配置
const steviaThresholds = {
steviaGlycosidesPercent: { min: 0, max: 1000, label: '甜菊糖苷含量' },
steviaAshPercent: { min: 0, max: 1000, label: '灰分' },
steviaPhValue: { min: 0, max: 1000, label: 'pH值' },
steviaStv: { min: 0, max: 1000, label: 'STV' },
steviaMoisture: { min: 0, max: 1000, label: '水分' },
steviaSpecificAbsorbance: { min: 0, max: 1000, label: '比吸光' },
steviaTransmittance: { min: 0, max: 1000, label: '透光率' }
} as const
// const steviaThresholds = {
// steviaGlycosidesPercent: { min: 80, max: 100, label: '甜菊糖苷含量' },
// steviaAshPercent: { min: 0.01, max: 0.1, label: '灰分' },
// steviaPhValue: { min: 5, max: 7, label: 'pH值' },
// steviaStv: { min: 10, max: 20, label: 'STV' },
// steviaMoisture: { min: 4, max: 6, label: '水分' },
// steviaSpecificAbsorbance: { min: 0.01, max: 0.2, label: '比吸光' },
// steviaTransmittance: { min: 96, max: 100, label: '透光率' }
// } as const
const autoUnqualifiedReasonPrefix = '以下指标超出阈值范围:'
// 检查甜菊糖字段是否在阈值范围内
const checkSteviaThreshold = (fieldName: keyof typeof steviaThresholds, value?: number) => {
if (value === undefined || value === null) return true // 空值不检查
const threshold = steviaThresholds[fieldName]
return value >= threshold.min && value <= threshold.max
}
const setSteviaOkFlag = (fieldName: keyof typeof steviaThresholds, pass: boolean) => {
const okFieldName = `${fieldName}Ok`
if (okFieldName in form) {
;(form as any)[okFieldName] = pass
}
}
// 获取所有不合格的甜菊糖指标
const getUnqualifiedSteviaFields = () => {
const unqualifiedFields: string[] = []
;(Object.keys(steviaThresholds) as Array<keyof typeof steviaThresholds>).forEach((fieldName) => {
const value = (form as any)[fieldName] as number | undefined
if (!checkSteviaThreshold(fieldName, value)) {
unqualifiedFields.push(steviaThresholds[fieldName].label)
}
})
return unqualifiedFields
}
const updateSteviaWarnings = () => {
;(Object.keys(steviaThresholds) as Array<keyof typeof steviaThresholds>).forEach((fieldName) => {
const value = (form as any)[fieldName] as number | undefined
const pass = checkSteviaThreshold(fieldName, value)
setSteviaOkFlag(fieldName, pass)
})
}
// 自动检查并更新合格状态
const autoCheckQualified = () => {
if (!isSteviaProduct.value) return
const unqualifiedFields = getUnqualifiedSteviaFields()
if (unqualifiedFields.length > 0) {
form.qualified = 0
form.unqualifiedReason = `${autoUnqualifiedReasonPrefix}${unqualifiedFields.join('、')}`
} else {
if (form.unqualifiedReason.startsWith(autoUnqualifiedReasonPrefix)) {
form.unqualifiedReason = ''
if (form.qualified === 0) {
form.qualified = 1
}
}
}
}
// 表单校验规则
const rules = {
workOrderCode: [{ required: true, message: '请选择批次', trigger: 'change' }],
weight: [{ required: true, message: '请输入重量', trigger: 'change' }],
status: [{ required: true, message: '请选择质检状态', trigger: 'change' }],
inspectionTime: [{ required: true, message: '请选择质检时间', trigger: 'change' }],
tomatoProcess: [{ required: true, message: '请选择工艺', trigger: 'change' }],
qualified: [{ required: true, message: '请选择是否合格', trigger: 'change' }],
inspectorName: [{ required: true, message: '请输入质检员姓名', trigger: 'blur' }],
unqualifiedReason: [
{
required: true,
message: '请输入不合格原因',
trigger: 'blur',
validator: (_rule: any, value: string, callback: Function) => {
if (!form.qualified && !value) {
callback(new Error('请输入不合格原因'))
} else {
callback()
}
}
}
]
}
// 表单引用
const formRef = ref()
// 对话框可见性
const dialogVisible = ref(false)
// 监听props.visible变化
watch(
() => props.visible,
(val) => {
dialogVisible.value = val
if (val) {
// 打开对话框时获取批次列表
getWorkOrderList()
// 如果是编辑或查看,则填充表单数据
if (props.type === 'edit' || props.type === 'view') {
Object.assign(form, getTomatoDefaults(), getSteviaDefaults(), props.data)
} else if (props.type === 'create') {
// 重置表单
Object.assign(form, {
code: '',
workOrderId: undefined,
workOrderCode: '',
productId: undefined,
productCode: '',
productName: '',
status: 0,
inspectionTime: getCurrentTimeString(),
weight: undefined,
qualified: 1,
unqualifiedReason: '',
inspectorName: userStore.getUser.nickname || '',
attachmentUrls: '',
remark: '',
...getTomatoDefaults(),
...getSteviaDefaults()
})
}
}
}
)
// 监听dialogVisible变化
watch(
() => dialogVisible.value,
(val) => {
emit('update:visible', val)
}
)
// 监听甜菊糖相关字段,超出阈值时自动预警
watch(
[
() => isSteviaProduct.value,
() => form.steviaGlycosidesPercent,
() => form.steviaAshPercent,
() => form.steviaPhValue,
() => form.steviaStv,
() => form.steviaMoisture,
() => form.steviaSpecificAbsorbance,
() => form.steviaTransmittance
],
() => {
updateSteviaWarnings()
if (isSteviaProduct.value) {
autoCheckQualified()
}
},
{ immediate: true }
)
// 获取批次列表
const getWorkOrderList = async () => {
try {
const res = await YVHgetWorkOrderSimpleList({ status: 4 }) // 只获取已完成的批次
// 由于axios响应拦截器的处理res直接就是data数组
if (Array.isArray(res)) {
workOrderOptions.value = res
} else {
console.error('获取批次列表返回格式错误:', res)
ElMessage.error('获取批次列表返回格式错误')
}
} catch (error) {
console.error('获取批次列表失败', error)
ElMessage.error('获取批次列表失败')
}
}
// 批次选择变更处理
const handleWorkOrderChange = (value: string) => {
const selectedWorkOrder = workOrderOptions.value.find((item) => item.code === value)
if (selectedWorkOrder) {
// 如果是从下拉列表中选择的批次
form.workOrderId = selectedWorkOrder.id
form.productId = selectedWorkOrder.productId
form.productCode = selectedWorkOrder.productCode
form.productName = selectedWorkOrder.productName
form.weight = selectedWorkOrder.producedQuantity
} else {
// 如果是手动输入的批次编号
form.workOrderId = undefined
form.productId = undefined
form.productCode = ''
form.productName = ''
}
}
// 提交表单
const submitForm = async () => {
if (!formRef.value) return
await formRef.value.validate(async (valid: boolean) => {
if (valid) {
try {
const submitData = { ...form }
// 确保日期是ISO格式
if (submitData.inspectionTime) {
const date = new Date(submitData.inspectionTime)
if (!isNaN(date.getTime())) {
submitData.inspectionTime = date.toISOString()
}
}
// 处理附件 URL后端要求字符串
if (submitData.attachmentUrls && typeof submitData.attachmentUrls !== 'string') {
try {
submitData.attachmentUrls = JSON.stringify(submitData.attachmentUrls)
} catch (e) {
submitData.attachmentUrls = ''
}
}
// 调用 API
const api =
props.type === 'create' ? createFinishedProductQuality : updateFinishedProductQuality
const res = await api(submitData)
// 统一处理成功情况
if (res) {
ElMessage.success('操作成功')
dialogVisible.value = false
emit('submit')
} else {
ElMessage.error(res.msg || '操作失败')
}
} catch (error: any) {
ElMessage.error(error.message || '操作失败')
}
}
})
}
// 对话框关闭事件
const handleClosed = () => {
emit('closed')
}
</script>