| | |
| | | <script setup lang="ts"> |
| | | import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | import { message, Modal } from 'ant-design-vue'; |
| | | import { IconifyIcon } from '@vben/icons'; |
| | | import { gsap } from 'gsap'; |
| | | |
| | | import MdItemSelect from '#/views/mes/md/item/components/select.vue'; |
| | | |
| | | import { |
| | | submitSeedQuality, |
| | |
| | | |
| | | async function submit() { |
| | | if (!code.value.trim() || !itemId.value) { |
| | | message.warning('请填写袋码和物料 ID'); |
| | | message.warning('请填写袋码并选择物料'); |
| | | return; |
| | | } |
| | | if (!allEntered.value) { |
| | |
| | | if (!overallPassed.value && !reason.value.trim()) { |
| | | message.warning('检验不合格时必须填写不合格原因'); |
| | | return; |
| | | } |
| | | |
| | | if (!overallPassed.value) { |
| | | const confirmed = await new Promise<boolean>((resolve) => { |
| | | Modal.confirm({ |
| | | title: '确认提交不合格结果?', |
| | | content: '不合格品将由后端从暂存库存中清除,并保留不合格原因用于质量分析。', |
| | | okText: '确认提交', |
| | | cancelText: '返回修改', |
| | | okButtonProps: { danger: true }, |
| | | onOk: () => resolve(true), |
| | | onCancel: () => resolve(false), |
| | | }); |
| | | }); |
| | | if (!confirmed) return; |
| | | } |
| | | |
| | | loading.value = true; |
| | |
| | | <template #title><div class="card-title"><IconifyIcon icon="ep:edit-pen" />质检信息</div></template> |
| | | <a-form layout="vertical"> |
| | | <div class="base-grid"> |
| | | <a-form-item label="袋码" required><a-input v-model:value="code" size="large" placeholder="请输入或扫描袋码" /></a-form-item> |
| | | <a-form-item label="物料 ID" required><a-input-number v-model:value="itemId" class="full-width" size="large" :min="1" placeholder="请输入物料编号" /></a-form-item> |
| | | <a-form-item label="生产批次"><a-input v-model:value="batchCode" size="large" placeholder="请输入批次号(选填)" /></a-form-item> |
| | | <a-form-item label="袋码" required><a-input v-model:value="code" size="large" :disabled="loading" placeholder="请输入或扫描袋码" /></a-form-item> |
| | | <a-form-item label="物料" required> |
| | | <MdItemSelect v-model="itemId" :disabled="loading" size="large" placeholder="请选择物料" /> |
| | | </a-form-item> |
| | | <a-form-item label="生产批次"><a-input v-model:value="batchCode" size="large" :disabled="loading" placeholder="请输入批次号(选填)" /></a-form-item> |
| | | </div> |
| | | |
| | | <a-divider orientation="left">指标结果</a-divider> |
| | | <div class="indicator-list"> |
| | | <div v-for="item in indicators" :key="item.code" class="indicator-row" :class="{ failed: !isPassed(item) }"> |
| | | <div class="indicator-name"><span class="indicator-dot" :class="isPassed(item) ? 'pass' : 'fail'" /><strong>{{ item.label }}</strong><small>{{ item.unit }}</small></div> |
| | | <a-input-number v-model:value="item.value" class="indicator-input" :min="0" :precision="3" placeholder="实测值" /> |
| | | <a-input-number v-model:value="item.value" class="indicator-input" :disabled="loading" :min="0" :precision="3" placeholder="实测值" /> |
| | | <span class="range-separator">范围</span> |
| | | <a-input-number v-model:value="item.minValue" class="range-input" :min="0" :precision="3" placeholder="下限" /> |
| | | <a-input-number v-model:value="item.minValue" class="range-input" :disabled="loading" :min="0" :precision="3" placeholder="下限" /> |
| | | <span>—</span> |
| | | <a-input-number v-model:value="item.maxValue" class="range-input" :min="0" :precision="3" placeholder="上限" /> |
| | | <a-input-number v-model:value="item.maxValue" class="range-input" :disabled="loading" :min="0" :precision="3" placeholder="上限" /> |
| | | <a-tag :color="isPassed(item) ? 'success' : 'error'">{{ isPassed(item) ? '合格' : '超出范围' }}</a-tag> |
| | | </div> |
| | | </div> |
| | | |
| | | <a-form-item label="不合格原因" :required="!overallPassed" class="reason-item"><a-textarea v-model:value="reason" :rows="3" :maxlength="500" show-count :placeholder="overallPassed ? '合格结果无需填写' : '请说明不合格原因'" /></a-form-item> |
| | | <div class="form-actions"><a-button @click="resetForm">重置</a-button><a-button type="primary" size="large" :loading="loading" @click="submit"><IconifyIcon icon="ep:upload-filled" />提交质检</a-button></div> |
| | | <a-form-item label="不合格原因" :required="!overallPassed" class="reason-item"><a-textarea v-model:value="reason" :disabled="loading" :rows="3" :maxlength="500" show-count :placeholder="overallPassed ? '合格结果无需填写' : '请说明不合格原因'" /></a-form-item> |
| | | <div class="form-actions"><a-button :disabled="loading" @click="resetForm">重置</a-button><a-button type="primary" size="large" :loading="loading" @click="submit"><IconifyIcon icon="ep:upload-filled" />提交质检</a-button></div> |
| | | </a-form> |
| | | </a-card> |
| | | |
| | |
| | | <template #title><div class="card-title"><IconifyIcon icon="ep:data-analysis" />判定说明</div></template> |
| | | <div class="result-hero" :class="overallPassed ? 'passed' : allEntered ? 'failed-result' : 'pending-result'"><IconifyIcon :icon="overallPassed ? 'ep:circle-check-filled' : allEntered ? 'ep:warning-filled' : 'ep:edit-pen'" /><strong>{{ overallPassed ? '当前结果合格' : allEntered ? '当前存在不合格项' : '等待录入指标' }}</strong><span>{{ allEntered ? '实测值需处于最小值与最大值之间' : `已录入 ${enteredCount} / 4 项实测值` }}</span></div> |
| | | <div class="rule-list"><div><IconifyIcon icon="ep:check" /><span>四项指标必须全部提交</span></div><div><IconifyIcon icon="ep:check" /><span>边界值按合格处理</span></div><div><IconifyIcon icon="ep:check" /><span>不合格结果需保留原因</span></div><div><IconifyIcon icon="ep:check" /><span>质检员与检验时间由服务端记录</span></div></div> |
| | | <a-alert message="库存位置由后台配置解析" description="本页面只提交袋码、物料、批次和检验指标,不允许前端选择仓库、库区或库位。" type="info" show-icon /> |
| | | <a-alert message="库存流转由后端处理" description="合格品将从暂存库转入正式库存;不合格品将直接清除暂存库存并保留不合格原因。质检员和检验时间由服务端记录,本页面不选择仓库、库区或库位。" type="info" show-icon /> |
| | | <div v-if="submittedId" class="success-note"><IconifyIcon icon="ep:success-filled" /><span>最近提交质检编号:<strong>{{ submittedId }}</strong></span></div> |
| | | </a-card> |
| | | </section> |