|
|
@@ -1,17 +1,10 @@
|
|
|
<template>
|
|
|
<AidopDemoShell title="IPQC 检查单详情" subtitle="过程检验单(工序级)· 检验结果与审核流">
|
|
|
- <div class="page-head">
|
|
|
- <el-button size="small" @click="goBack">← 返回</el-button>
|
|
|
+ <div class="detail-topbar">
|
|
|
+ <el-button @click="goBack">← 返回</el-button>
|
|
|
<span class="bill-no">{{ headTitle }}</span>
|
|
|
- <el-tag v-if="review?.displayStatus" :type="flowTagType" size="small" effect="plain" disable-transitions>
|
|
|
- {{ review.displayStatus }}
|
|
|
- </el-tag>
|
|
|
- <el-tag v-if="review?.qualityText || detail?.overallResult" :type="judgeTag(detail?.overallResult)" size="small" disable-transitions>
|
|
|
- {{ review?.qualityText || detail?.overallResult }}
|
|
|
- </el-tag>
|
|
|
- <el-tag v-if="review?.currentNodeName" size="small" type="info" effect="plain" disable-transitions>
|
|
|
- 当前节点:{{ review.currentNodeName }}
|
|
|
- </el-tag>
|
|
|
+ <el-tag v-if="review?.displayStatus" :type="flowTagType" size="small" disable-transitions>{{ review.displayStatus }}</el-tag>
|
|
|
+ <el-tag v-if="review?.currentNodeName" size="small" disable-transitions>{{ review.currentNodeName }}</el-tag>
|
|
|
</div>
|
|
|
|
|
|
<div v-if="invalidId" class="detail-body">
|
|
|
@@ -21,36 +14,34 @@
|
|
|
</div>
|
|
|
|
|
|
<div v-else class="detail-body" v-loading="detailLoading">
|
|
|
- <el-descriptions :column="3" border size="small" title="基础信息">
|
|
|
- <el-descriptions-item label="工单编号">{{ dash(detail?.workOrderNo) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="批次号">{{ dash(detail?.lotSerial) }}</el-descriptions-item>
|
|
|
+ <el-descriptions title="基础信息" :column="2" border size="small">
|
|
|
+ <el-descriptions-item label="检验单号">{{ dash(detail?.billId) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="单据状态">{{ dash(detail?.inspectionStatus) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="物料编码">{{ dash(detail?.itemCode) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="物料名称">{{ dash(detail?.itemName) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="规格型号">{{ dash(detail?.specification) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="单据状态">{{ dash(detail?.inspectionStatus) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="生产批号">{{ dash(detail?.lotSerial) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="建单人">{{ dash(detail?.createdByName) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="建单时间">{{ fmtDateTime(detail?.createTime) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="检验单 id">{{ dash(detail?.billId) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="整单状态">{{ overallStatusText }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="整单结果">{{ overallResultText }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="检验项目数">{{ (detail?.lines || []).length }}</el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+
|
|
|
+ <el-descriptions title="生产信息" :column="2" border size="small" class="mt8">
|
|
|
+ <el-descriptions-item label="生产指令单">{{ dash(detail?.workOrderNo) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="指令单数量">{{ dash(workOrder?.orderQty) }}</el-descriptions-item>
|
|
|
+ <!-- SAP工单号:S6 过程检验单与生产指令单均无该字段,见 BACKEND FIELD GAP -->
|
|
|
+ <el-descriptions-item label="SAP工单号">-</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
- <el-descriptions class="mt8" :column="3" border size="small" title="检规信息(建单时冻结的快照)">
|
|
|
+ <el-descriptions title="检规信息" :column="2" border size="small" class="mt8">
|
|
|
<el-descriptions-item label="检规编号">{{ dash(detail?.specCode) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="检规版本">{{ dash(detail?.specVersion) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="生效日期">{{ fmtDate(detail?.effectiveDate) }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
- <el-descriptions class="mt8" :column="3" border size="small" title="检验结果">
|
|
|
- <el-descriptions-item label="整单状态">{{ overallStatusText }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="整单结果">
|
|
|
- <el-tag v-if="detail?.overallResult" :type="judgeTag(detail.overallResult)" size="small" disable-transitions>
|
|
|
- {{ review?.qualityText || detail.overallResult }}
|
|
|
- </el-tag>
|
|
|
- <span v-else>—</span>
|
|
|
- </el-descriptions-item>
|
|
|
- <el-descriptions-item label="检验项目数">{{ (detail?.lines || []).length }}</el-descriptions-item>
|
|
|
- </el-descriptions>
|
|
|
-
|
|
|
- <div class="mt12">
|
|
|
+ <div class="mt8">
|
|
|
<IpqcBillItemPanel
|
|
|
:lines="detail?.lines || []"
|
|
|
:can-edit="canEdit"
|
|
|
@@ -61,28 +52,66 @@
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- <el-descriptions class="mt12" :column="3" border size="small" title="流程信息" v-loading="reviewLoading">
|
|
|
+ <el-descriptions title="流程信息" :column="2" border size="small" class="mt8" v-loading="reviewLoading">
|
|
|
<el-descriptions-item label="流程状态">{{ dash(review?.displayStatus) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="当前节点">{{ dash(review?.currentNodeName) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="当前处理角色">{{ dash(review?.currentAssigneeRole) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="当前角色">{{ dash(review?.currentAssigneeRole) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="流程实例">{{ dash(review?.instanceId) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="说明" :span="2">{{ dash(review?.message) }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
- <el-descriptions v-if="review?.disposition" class="mt8" :column="3" border size="small" title="质量处置结论">
|
|
|
+ <!-- 操作区:位置跟随 FQC —— 紧接流程信息之后,按角色分块,不在页面别处再放一套 -->
|
|
|
+ <div v-if="review?.canSubmitReview" class="flow-op mt12">
|
|
|
+ <div class="flow-op-title">检验员提交检验结果(转检验主管审核)</div>
|
|
|
+ <el-button type="primary" :loading="flowSubmitting" @click="onSubmitReview">提交审核</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="review?.canSupervisorApprove || review?.canSupervisorReturn" class="flow-op mt12">
|
|
|
+ <div class="flow-op-title">检验主管审核</div>
|
|
|
+ <el-button v-if="review?.canSupervisorApprove" type="success" :loading="flowSubmitting" @click="onSupervisorApprove">通过</el-button>
|
|
|
+ <el-button v-if="review?.canSupervisorReturn" type="warning" :loading="flowSubmitting" @click="onSupervisorReturn">退回</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="review?.canSubmitDisposition" class="flow-op mt12">
|
|
|
+ <div class="flow-op-title">QE 质量处置(不合格)</div>
|
|
|
+ <el-form :model="qeForm" label-width="96px" size="small">
|
|
|
+ <el-form-item label="处置类型">
|
|
|
+ <el-select v-model="qeForm.dispositionType" style="width: 180px">
|
|
|
+ <el-option value="REWORK" label="返工" />
|
|
|
+ <el-option value="CONCESSION" label="让步接收" />
|
|
|
+ <el-option value="SCRAP" label="报废" />
|
|
|
+ <el-option value="OTHER" label="其它" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="处置数量">
|
|
|
+ <el-input-number v-model="qeForm.dispositionQty" :min="0" :controls="false" style="width: 180px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="责任部门"><el-input v-model="qeForm.responsibilityDept" style="width: 240px" /></el-form-item>
|
|
|
+ <el-form-item label="责任人"><el-input v-model="qeForm.responsibleUser" style="width: 180px" /></el-form-item>
|
|
|
+ <el-form-item label="处置意见">
|
|
|
+ <el-input v-model="qeForm.dispositionOpinion" type="textarea" :rows="2" style="width: 320px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" :loading="flowSubmitting" @click="onQeDisposition">提交 QE 处置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-descriptions v-if="review?.disposition" title="QE 处置结论(仅展示)" :column="2" border size="small" class="mt12">
|
|
|
<el-descriptions-item label="处置类型">
|
|
|
- <el-tag type="warning" size="small" disable-transitions>
|
|
|
- {{ review.disposition.dispositionTypeText || review.disposition.dispositionType }}
|
|
|
- </el-tag>
|
|
|
+ {{ dash(review.disposition.dispositionTypeText || review.disposition.dispositionType) }}
|
|
|
</el-descriptions-item>
|
|
|
- <el-descriptions-item label="处置人">{{ dash(review.disposition.operatorName) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="提交时间">{{ fmtDateTime(review.disposition.submittedAt) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="处置数量">{{ dash(review.disposition.dispositionQty) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="责任部门">{{ dash(review.disposition.responsibilityDept) }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="责任人">{{ dash(review.disposition.responsibleUser) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="处置数量">{{ dash(review.disposition.dispositionQty) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="处置意见" :span="3">{{ dash(review.disposition.dispositionOpinion) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="处置人">{{ dash(review.disposition.operatorName) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="提交时间">{{ fmtDateTime(review.disposition.submittedAt) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="处置意见" :span="2">
|
|
|
+ <span class="pre">{{ dash(review.disposition.dispositionOpinion) }}</span>
|
|
|
+ </el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
+ <!-- 审核历史:FQC 详情页没有这一区,是 S6 独有(正式 ApprovalFlow 时间线),置于末尾不打断 FQC 区块顺序 -->
|
|
|
<div class="mt12 hist-block">
|
|
|
<div class="hist-title">审核历史</div>
|
|
|
<el-timeline v-if="(review?.history || []).length">
|
|
|
@@ -102,35 +131,6 @@
|
|
|
</el-timeline>
|
|
|
<el-empty v-else description="暂无审核历史" :image-size="60" />
|
|
|
</div>
|
|
|
-
|
|
|
- <div class="mt12 flow-op" v-if="hasAnyAction">
|
|
|
- <div class="flow-op-title">操作</div>
|
|
|
- <div class="flow-op-row">
|
|
|
- <el-button v-if="review?.canSubmitReview" type="primary" :loading="flowSubmitting" @click="onSubmitReview">
|
|
|
- 提交审核
|
|
|
- </el-button>
|
|
|
- <el-button v-if="review?.canSupervisorApprove" type="success" :loading="flowSubmitting" @click="onSupervisorApprove">
|
|
|
- 主管通过
|
|
|
- </el-button>
|
|
|
- <el-button v-if="review?.canSupervisorReturn" :loading="flowSubmitting" @click="onSupervisorReturn">退回</el-button>
|
|
|
- </div>
|
|
|
- <div v-if="review?.canSubmitDisposition" class="flow-op-row mt8">
|
|
|
- <el-select v-model="dispType" size="small" style="width: 168px" placeholder="处置类型">
|
|
|
- <el-option label="返工 REWORK" value="REWORK" />
|
|
|
- <el-option label="让步 CONCESSION" value="CONCESSION" />
|
|
|
- <el-option label="报废 SCRAP" value="SCRAP" />
|
|
|
- <el-option label="其它 OTHER" value="OTHER" />
|
|
|
- </el-select>
|
|
|
- <el-input v-model="dispOpinion" size="small" style="width: 320px" placeholder="处置意见(必填)" />
|
|
|
- <el-button type="warning" :loading="flowSubmitting" @click="onQeDisposition">提交处置</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="mt12" v-if="review?.isCompleted">
|
|
|
- <el-tag :type="review?.flowStatus === 'Approved' ? 'success' : 'info'" size="small" disable-transitions>
|
|
|
- {{ review?.flowStatus === 'Approved' ? '审核已闭环(CLOSED)' : `流程已结束(${review?.flowStatus})` }}
|
|
|
- </el-tag>
|
|
|
- </div>
|
|
|
</div>
|
|
|
</AidopDemoShell>
|
|
|
</template>
|
|
|
@@ -144,14 +144,25 @@
|
|
|
* 另一条 `IpqcInspection*` 链(源 `qms_gcjyd`、单头级汇总、节点 N1_INSPECT/.../N3_QUALITY_DISPOSITION)
|
|
|
* 在 `process-quality/processInspectionList.vue`,与本页无共享代码 —— 改错文件会白做。
|
|
|
*
|
|
|
- * 信息架构对齐 S7 FQC 详情页(整页 + 顶部返回/单号/状态 + 区块化 descriptions + 项目明细 + 流程 + 操作),
|
|
|
- * 但业务模型、接口、字段、枚举全部沿用 S6 自己的,**不引入任何 FQC 语义**
|
|
|
- * (无 j1..j50、无 FQC DTO/表名/BizType、处置枚举用 S6 的 REWORK/CONCESSION/SCRAP/OTHER 字符串)。
|
|
|
+ * ── 布局基线(S6-IPQC-FQC-PARITY-1,2026-09-14)──
|
|
|
+ * 以 S7 `fqc/fqcInspResultDetail.vue` 为**页面模板**:topbar(返回/单号/状态 tag/节点 tag)→
|
|
|
+ * descriptions 区块(`:column="2" border size="small"`,`.mt8` 间距)→ 明细标题裸 div →
|
|
|
+ * 主表(含展开行)→ 流程信息 → **紧随其后的分角色 `.flow-op` 操作块** → QE 处置结论(仅展示)。
|
|
|
+ *
|
|
|
+ * 与 FQC 的三处有意差异(已知且刻意):
|
|
|
+ * - 区块标题用「基础信息 / 生产信息 / 检规信息 / 检验项目明细 / 流程信息 / 审核历史」,
|
|
|
+ * 而非 FQC 字面的「基本信息 / 成品信息 / 品检项目明细」—— 后两个是 FQC 域专有说法,
|
|
|
+ * S6 检的是工序在制品,不是成品;FQC 的「基本信息 + 成品信息」在此合为「基础信息」。
|
|
|
+ * - 流程信息多一行「流程实例」(FQC 无此行,但 S6 有真实 instanceId 且排障要用)。
|
|
|
+ * - 末尾多「审核历史」区(FQC 详情页完全没有这一区,S6 有正式 ApprovalFlow 时间线,不删)。
|
|
|
+ *
|
|
|
+ * 只对齐 UI,不引入任何 FQC 业务模型:接口、DTO、枚举、检规快照、处置类型
|
|
|
+ * (REWORK/CONCESSION/SCRAP/OTHER)全部沿用 S6 自己的,不调用任何 S7 接口。
|
|
|
*
|
|
|
* 刻意**不照抄** S7 的三处实现(改用 S5 IQC 已修正的做法):
|
|
|
* - 路由用 path param 且菜单 `IsKeepAlive=0`。详情页是强状态页(可录入 → 只读 → 退回 → 可录入),
|
|
|
* S7 的 `IsKeepAlive=1` + 只有 onMounted 会在换单时显示上一单数据;本页另加 `watch(route.params.id)` 兜底。
|
|
|
- * - 状态 tag 按流程状态配色(S7 硬写 type="info" 且直出英文枚举)。
|
|
|
+ * - 状态 tag 按流程状态配色,且显示后端拥有的中文 `displayStatus`(S7 硬写 type="info" 且直出英文枚举)。
|
|
|
* - 保存/动作失败不再叠加 ElMessage —— 交给 `request.ts` 拦截器统一弹后端真实 message,
|
|
|
* 避免同时弹出业务文案与 axios 技术文案。
|
|
|
*
|
|
|
@@ -159,13 +170,14 @@
|
|
|
* 上一版曾因后端无该字段而在本页本地推断(`flowStatus` 非 NotStarted 即锁录入),
|
|
|
* 导致主管退回回到 N1 后仍是只读 —— 已改为后端 Authority + 前端纯消费,详见 `canEdit` 处注释。
|
|
|
*/
|
|
|
-import { computed, onActivated, onMounted, ref, watch } from 'vue';
|
|
|
+import { computed, onActivated, onMounted, reactive, ref, watch } from 'vue';
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
import AidopDemoShell from '/@/views/aidop/components/AidopDemoShell.vue';
|
|
|
import IpqcBillItemPanel from './components/IpqcBillItemPanel.vue';
|
|
|
import {
|
|
|
fetchProcessInspectionDetail,
|
|
|
+ fetchProductionInstructionDetail,
|
|
|
saveProcessInspectionResult,
|
|
|
completeProcessInspection,
|
|
|
fetchReviewState,
|
|
|
@@ -174,6 +186,7 @@ import {
|
|
|
reviewSupervisorReturn,
|
|
|
reviewQeDisposition,
|
|
|
type ProcessInspectionDetail,
|
|
|
+ type ProductionInstructionRow,
|
|
|
type ReviewState,
|
|
|
type SaveResultSample,
|
|
|
} from '../api/productionInstruction';
|
|
|
@@ -185,13 +198,29 @@ const router = useRouter();
|
|
|
|
|
|
const detail = ref<ProcessInspectionDetail | null>(null);
|
|
|
const review = ref<ReviewState | null>(null);
|
|
|
+/** 生产指令单(只读):过程检验单详情不带指令单数量,从既有 S6 指令单接口取,取不到则「-」。 */
|
|
|
+const workOrder = ref<ProductionInstructionRow | null>(null);
|
|
|
const detailLoading = ref(false);
|
|
|
const reviewLoading = ref(false);
|
|
|
const saving = ref(false);
|
|
|
const completing = ref(false);
|
|
|
const flowSubmitting = ref(false);
|
|
|
-const dispType = ref('');
|
|
|
-const dispOpinion = ref('');
|
|
|
+
|
|
|
+const qeForm = reactive<{
|
|
|
+ dispositionType: string;
|
|
|
+ dispositionQty: number | null;
|
|
|
+ dispositionOpinion: string;
|
|
|
+ responsibilityDept: string;
|
|
|
+ responsibleUser: string;
|
|
|
+}>({ dispositionType: 'REWORK', dispositionQty: null, dispositionOpinion: '', responsibilityDept: '', responsibleUser: '' });
|
|
|
+
|
|
|
+function resetQeForm() {
|
|
|
+ qeForm.dispositionType = 'REWORK';
|
|
|
+ qeForm.dispositionQty = null;
|
|
|
+ qeForm.dispositionOpinion = '';
|
|
|
+ qeForm.responsibilityDept = '';
|
|
|
+ qeForm.responsibleUser = '';
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* 路由参数先按「正整数字符串」校验再转数字。
|
|
|
@@ -204,7 +233,7 @@ const billId = computed(() => (invalidId.value ? 0 : Number(billIdRaw.value)));
|
|
|
|
|
|
const headTitle = computed(() => {
|
|
|
const wo = detail.value?.workOrderNo;
|
|
|
- return wo ? `IPQC 检查单 · ${wo}` : `IPQC 检查单 #${billIdRaw.value || '—'}`;
|
|
|
+ return wo ? `IPQC 检查单 · ${wo}` : `IPQC 检查单 #${billIdRaw.value || '-'}`;
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
@@ -216,12 +245,6 @@ const headTitle = computed(() => {
|
|
|
*/
|
|
|
const canEdit = computed(() => review.value?.canEdit === true);
|
|
|
|
|
|
-const hasAnyAction = computed(
|
|
|
- () =>
|
|
|
- !!review.value &&
|
|
|
- (review.value.canSubmitReview || review.value.canSupervisorApprove || review.value.canSupervisorReturn || review.value.canSubmitDisposition)
|
|
|
-);
|
|
|
-
|
|
|
const flowTagType = computed<'success' | 'danger' | 'warning' | 'info'>(() => {
|
|
|
switch (review.value?.flowStatus) {
|
|
|
case 'Approved':
|
|
|
@@ -250,11 +273,28 @@ const overallStatusText = computed(() => {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+/** 整单结果文案优先用后端拥有的中文(qualityText),不在前端重新翻译枚举。 */
|
|
|
+const overallResultText = computed(() => {
|
|
|
+ if (review.value?.qualityText) return review.value.qualityText;
|
|
|
+ switch (detail.value?.overallResult) {
|
|
|
+ case 'PASS':
|
|
|
+ return '合格';
|
|
|
+ case 'FAIL':
|
|
|
+ return '不合格';
|
|
|
+ case 'PENDING':
|
|
|
+ return '检验中';
|
|
|
+ case 'INVALID':
|
|
|
+ return '无效';
|
|
|
+ default:
|
|
|
+ return dash(detail.value?.overallResult);
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
function resetPageState() {
|
|
|
detail.value = null;
|
|
|
review.value = null;
|
|
|
- dispType.value = '';
|
|
|
- dispOpinion.value = '';
|
|
|
+ workOrder.value = null;
|
|
|
+ resetQeForm();
|
|
|
}
|
|
|
|
|
|
async function loadReview() {
|
|
|
@@ -269,7 +309,20 @@ async function loadReview() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/** 详情与流程态可并发;两者都不依赖对方的结果。 */
|
|
|
+/** 指令单数量等生产信息取自既有指令单接口;失败只让「生产信息」退化为 '-',不影响本页其余部分。 */
|
|
|
+async function loadWorkOrder(workOrderNo?: string) {
|
|
|
+ if (!workOrderNo) {
|
|
|
+ workOrder.value = null;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ workOrder.value = await fetchProductionInstructionDetail(workOrderNo);
|
|
|
+ } catch {
|
|
|
+ workOrder.value = null;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 详情与流程态可并发;两者都不依赖对方的结果。生产指令单需要 workOrderNo,故在详情之后取。 */
|
|
|
async function loadPage() {
|
|
|
if (invalidId.value) {
|
|
|
resetPageState();
|
|
|
@@ -279,8 +332,10 @@ async function loadPage() {
|
|
|
try {
|
|
|
const [d] = await Promise.all([fetchProcessInspectionDetail(billId.value), loadReview()]);
|
|
|
detail.value = d;
|
|
|
+ await loadWorkOrder(d?.workOrderNo);
|
|
|
} catch {
|
|
|
detail.value = null;
|
|
|
+ workOrder.value = null;
|
|
|
} finally {
|
|
|
detailLoading.value = false;
|
|
|
}
|
|
|
@@ -317,7 +372,7 @@ async function onComplete(samples: SaveResultSample[]) {
|
|
|
await saveProcessInspectionResult(billId.value, samples);
|
|
|
const r = await completeProcessInspection(billId.value);
|
|
|
await reloadAfterAction();
|
|
|
- ElMessage.success(`已完成检验:整单 ${r?.overallResult || detail.value?.overallResult || '—'}`);
|
|
|
+ ElMessage.success(`已完成检验:整单 ${r?.overallResult || detail.value?.overallResult || '-'}`);
|
|
|
} catch (e: any) {
|
|
|
const msg = String(e?.response?.data?.message || e?.message || '');
|
|
|
if (msg.includes('INSPECTION_INCOMPLETE')) ElMessage.warning('尚有检验项未按频次录满,无法完成检验。');
|
|
|
@@ -377,18 +432,21 @@ async function onSupervisorReturn() {
|
|
|
|
|
|
async function onQeDisposition() {
|
|
|
if (!billId.value || flowSubmitting.value) return;
|
|
|
- if (!dispType.value) return ElMessage.warning('请选择处置类型');
|
|
|
- if (!dispOpinion.value.trim()) return ElMessage.warning('处置意见必填');
|
|
|
+ if (!qeForm.dispositionType) return ElMessage.warning('请选择处置类型');
|
|
|
+ if (!qeForm.dispositionOpinion.trim()) return ElMessage.warning('处置意见必填');
|
|
|
+ if (qeForm.dispositionQty !== null && qeForm.dispositionQty < 0) return ElMessage.warning('处置数量不能为负');
|
|
|
flowSubmitting.value = true;
|
|
|
try {
|
|
|
review.value = await reviewQeDisposition({
|
|
|
billId: billId.value,
|
|
|
- dispositionType: dispType.value,
|
|
|
- dispositionOpinion: dispOpinion.value.trim(),
|
|
|
+ dispositionType: qeForm.dispositionType,
|
|
|
+ dispositionQty: qeForm.dispositionQty,
|
|
|
+ dispositionOpinion: qeForm.dispositionOpinion.trim(),
|
|
|
+ responsibilityDept: qeForm.responsibilityDept.trim() || undefined,
|
|
|
+ responsibleUser: qeForm.responsibleUser.trim() || undefined,
|
|
|
});
|
|
|
ElMessage.success('已提交质量处置');
|
|
|
- dispType.value = '';
|
|
|
- dispOpinion.value = '';
|
|
|
+ resetQeForm();
|
|
|
await reloadAfterAction();
|
|
|
} catch {
|
|
|
await loadReview();
|
|
|
@@ -402,28 +460,22 @@ function goBack() {
|
|
|
else router.push(IPQC_LIST_PATH);
|
|
|
}
|
|
|
|
|
|
-function judgeTag(result?: string): 'success' | 'danger' | 'info' | 'warning' {
|
|
|
- if (result === 'PASS') return 'success';
|
|
|
- if (result === 'FAIL') return 'danger';
|
|
|
- if (result === 'INVALID') return 'warning';
|
|
|
- return 'info';
|
|
|
-}
|
|
|
-
|
|
|
+/** 缺字段一律显示 '-'(与 FQC 同款),不让 undefined / null / 字面量 'null' 漏到界面上。 */
|
|
|
function dash(v?: unknown) {
|
|
|
- if (v === null || v === undefined) return '—';
|
|
|
+ if (v === null || v === undefined) return '-';
|
|
|
const s = String(v).trim();
|
|
|
- if (s === '' || s === 'null' || s === 'undefined') return '—';
|
|
|
+ if (s === '' || s === 'null' || s === 'undefined') return '-';
|
|
|
return s;
|
|
|
}
|
|
|
|
|
|
function fmtDate(v?: string) {
|
|
|
- if (!v) return '—';
|
|
|
+ if (!v) return '-';
|
|
|
const s = String(v);
|
|
|
return s.length >= 10 ? s.slice(0, 10) : s;
|
|
|
}
|
|
|
|
|
|
function fmtDateTime(v?: string) {
|
|
|
- if (!v) return '—';
|
|
|
+ if (!v) return '-';
|
|
|
return String(v).replace('T', ' ').slice(0, 19);
|
|
|
}
|
|
|
|
|
|
@@ -441,16 +493,17 @@ watch(
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.page-head {
|
|
|
+/* topbar / 间距 / flow-op 与 S7 FQC 详情页同款 */
|
|
|
+.detail-topbar {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- gap: 12px;
|
|
|
+ gap: 10px;
|
|
|
flex-wrap: wrap;
|
|
|
margin-bottom: 12px;
|
|
|
}
|
|
|
.bill-no {
|
|
|
- font-weight: 600;
|
|
|
- font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 15px;
|
|
|
}
|
|
|
.detail-body {
|
|
|
min-height: 160px;
|
|
|
@@ -461,6 +514,20 @@ watch(
|
|
|
.mt12 {
|
|
|
margin-top: 12px;
|
|
|
}
|
|
|
+.flow-op {
|
|
|
+ padding: 12px;
|
|
|
+ border: 1px solid var(--el-border-color-lighter);
|
|
|
+ border-radius: 4px;
|
|
|
+ background: var(--el-fill-color-light);
|
|
|
+}
|
|
|
+.flow-op-title {
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+.pre {
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-break: break-word;
|
|
|
+}
|
|
|
.hist-block {
|
|
|
padding: 12px;
|
|
|
border: 1px solid var(--el-border-color-lighter);
|
|
|
@@ -468,7 +535,7 @@ watch(
|
|
|
background: var(--el-fill-color-light);
|
|
|
}
|
|
|
.hist-title {
|
|
|
- font-weight: 600;
|
|
|
+ font-weight: bold;
|
|
|
font-size: 14px;
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
@@ -484,20 +551,4 @@ watch(
|
|
|
font-size: 12px;
|
|
|
color: var(--el-text-color-secondary);
|
|
|
}
|
|
|
-.flow-op {
|
|
|
- padding: 12px;
|
|
|
- border: 1px solid var(--el-border-color-lighter);
|
|
|
- border-radius: 4px;
|
|
|
- background: var(--el-fill-color-light);
|
|
|
-}
|
|
|
-.flow-op-title {
|
|
|
- font-weight: 600;
|
|
|
- margin-bottom: 10px;
|
|
|
-}
|
|
|
-.flow-op-row {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 8px;
|
|
|
-}
|
|
|
</style>
|