From 0558f330f7e3781b91d00ed4a12e60d9fa469d87 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 17 九月 2026 13:11:12 +0800
Subject: [PATCH] feat(mes): 增加质检指标层级结构与多批次录入功能

---
 src/views/mes/qc/components/qc-report-print.vue      |  325 ++++++++++++++
 src/api/mes/qc/template/indicator/index.ts           |    2 
 src/views/mes/qc/template/data.ts                    |   43 +
 src/views/mes/qc/iqc/index.vue                       |   19 
 src/api/mes/qc/template/index.ts                     |    1 
 src/views/mes/qc/ipqc/data.ts                        |   51 ++
 src/packages/constants/src/biz-mes-enum.ts           |    6 
 src/views/mes/qc/iqc/data.ts                         |   51 ++
 src/views/mes/qc/indicator/data.ts                   |   95 ++++
 src/api/mes/qc/ipqc/index.ts                         |    7 
 src/views/mes/qc/indicatorresult/components/form.vue |  393 ++++++++++++++---
 src/views/mes/qc/oqc/data.ts                         |   51 ++
 src/api/mes/qc/rqc/index.ts                          |    7 
 src/views/mes/qc/ipqc/index.vue                      |   20 
 src/views/mes/qc/oqc/index.vue                       |   20 
 src/views/mes/qc/rqc/index.vue                       |   20 
 src/views/mes/qc/template/modules/indicator-list.vue |   24 +
 src/api/mes/qc/iqc/index.ts                          |    7 
 src/api/mes/qc/oqc/index.ts                          |    7 
 src/api/mes/qc/indicatorresult/index.ts              |   85 +++
 src/views/mes/qc/rqc/data.ts                         |   51 ++
 src/api/mes/qc/indicator/index.ts                    |   13 
 22 files changed, 1,214 insertions(+), 84 deletions(-)

diff --git a/src/api/mes/qc/indicator/index.ts b/src/api/mes/qc/indicator/index.ts
index 163f11d..3a0fb74 100644
--- a/src/api/mes/qc/indicator/index.ts
+++ b/src/api/mes/qc/indicator/index.ts
@@ -8,11 +8,17 @@
     id?: number; // 缂栧彿
     code?: string; // 妫�娴嬮」缂栫爜
     name?: string; // 妫�娴嬮」鍚嶇О
+    parentId?: number; // 鐖舵寚鏍囩紪鍙凤紙0=椤剁骇锛�
+    itemType?: number; // 鏉$洰绫诲瀷锛�1=褰曞叆椤癸紝2=鍒嗙粍椤�
+    formulaText?: string; // 鍏紡灞曠ず鏂囨湰锛堟墦鍗扮敤锛屼笉鍙備笌璁$畻锛�
+    unitText?: string; // 鍗曚綅鏂囨湰锛堝 kg/m鲁銆�/%锛�
+    sortOrder?: number; // 鍚岀骇鎺掑簭鍙�
     type?: number; // 妫�娴嬮」绫诲瀷
     tool?: string; // 妫�娴嬪伐鍏�
     resultType?: number; // 缁撴灉鍊肩被鍨�
     resultSpecification?: string; // 缁撴灉鍊煎睘鎬�
     remark?: string; // 澶囨敞
+    parentName?: string; // 鐖舵寚鏍囧悕绉帮紙鍒楄〃/璇︽儏鍥炲~锛�
     createTime?: Date; // 鍒涘缓鏃堕棿
   }
 }
@@ -47,6 +53,13 @@
   return requestClient.delete(`/mes/qc/indicator/delete?id=${id}`);
 }
 
+/** 鏌ヨ璐ㄦ鎸囨爣鍏ㄩ噺鍒楄〃锛堝惈鍒嗙粍灞傜骇锛屼緵鏍戣〃/涓嬫媺浣跨敤锛� */
+export function getIndicatorList() {
+  return requestClient.get<MesQcIndicatorApi.Indicator[]>(
+    '/mes/qc/indicator/list',
+  );
+}
+
 /** 瀵煎嚭璐ㄦ鎸囨爣 */
 export function exportIndicator(params: any) {
   return requestClient.download('/mes/qc/indicator/export-excel', { params });
diff --git a/src/api/mes/qc/indicatorresult/index.ts b/src/api/mes/qc/indicatorresult/index.ts
index dfa8a7f..6cc37f8 100644
--- a/src/api/mes/qc/indicatorresult/index.ts
+++ b/src/api/mes/qc/indicatorresult/index.ts
@@ -3,18 +3,35 @@
 import { requestClient } from '#/api/request';
 
 export namespace MesQcIndicatorResultApi {
-  /** MES 妫�楠岀粨鏋滄槑缁� */
+  /** 骞宠娴嬮噺鎵规鏄庣粏锛堝悓涓�鎸囨爣鐨勪竴娆℃祴閲忥級 */
+  export interface Measure {
+    detailId?: number; // 鏄庣粏缂栧彿
+    resultId?: number; // 鍏宠仈妫�楠岀粨鏋� ID
+    measureNo?: number; // 娴嬮噺鎵规鍙凤紙浠� 1 寮�濮嬶級
+    value?: string; // 妫�娴嬪��
+    remark?: string; // 澶囨敞
+  }
+
+  /** MES 妫�楠岀粨鏋滄槑缁嗭紙鏍戝舰锛氬垎缁勯」涓嬫寕瀛愰」锛涘钩琛屾祴閲忔斁鍏� measures锛� */
   export interface IndicatorResultDetail {
-    id?: number; // 缂栧彿
+    id?: number; // 缂栧彿锛堢涓�鎵规槑缁� ID锛屽吋瀹规棫瀛楁锛�
     resultId?: number; // 鍏宠仈妫�楠岀粨鏋� ID
     indicatorId?: number; // 妫�娴嬫寚鏍� ID
-    value?: string; // 妫�娴嬪�硷紙缁熶竴瀛樹负瀛楃涓诧級
+    value?: string; // 妫�娴嬪�硷紙绗竴鎵癸紝鍏煎鏃у瓧娈碉級
     valueNumber?: number; // UI 鏁板�肩粦瀹氾紙鎻愪氦鍓嶈浆瀛楃涓诧級
+    measureNo?: number; // 娴嬮噺鎵规鍙凤紙鎻愪氦鐢紝榛樿 1锛�
     remark?: string; // 澶囨敞
     // 鍏宠仈鏌ヨ瀛楁锛堟潵鑷� indicator锛�
     indicatorName?: string; // 妫�娴嬫寚鏍囧悕绉�
     valueType?: number; // 璐ㄦ鍊肩被鍨�
     valueSpecification?: string; // 鍊煎睘鎬�
+    parentId?: number; // 鐖舵寚鏍囩紪鍙凤紙0=椤剁骇锛�
+    itemType?: number; // 鏉$洰绫诲瀷锛�1=褰曞叆椤癸紝2=鍒嗙粍椤�
+    formulaText?: string; // 鍏紡灞曠ず鏂囨湰
+    unitText?: string; // 鍗曚綅鏂囨湰
+    sortOrder?: number; // 鍚岀骇鎺掑簭鍙�
+    measures?: Measure[]; // 骞宠娴嬮噺鎵规鍒楄〃锛堟寜 measureNo 鍗囧簭锛�
+    children?: IndicatorResultDetail[]; // 瀛愰」鍒楄〃锛堝垎缁勯」涓嬫寕锛�
   }
 
   /** MES 妫�楠岀粨鏋� */
@@ -71,3 +88,65 @@
 export function deleteIndicatorResult(id: number) {
   return requestClient.delete(`/mes/qc/indicator-result/delete?id=${id}`);
 }
+
+// ==================== 妫�楠屾姤鍛婂崟锛堟墦鍗版暟鎹級 ====================
+
+export namespace MesQcReportApi {
+  /** 鎶ュ憡娴嬮噺鍊� */
+  export interface ReportMeasure {
+    measureNo?: number; // 娴嬮噺鎵规鍙�
+    value?: string; // 妫�娴嬪��
+    remark?: string; // 澶囨敞
+  }
+
+  /** 鎶ュ憡妫�楠岄」锛堟爲褰級 */
+  export interface ReportItem {
+    indicatorId?: number;
+    indicatorCode?: string;
+    indicatorName?: string;
+    parentId?: number;
+    itemType?: number; // 1=褰曞叆椤癸紝2=鍒嗙粍椤�
+    formulaText?: string;
+    unitText?: string;
+    sortOrder?: number;
+    checkMethod?: string; // 妫�娴嬫柟娉�
+    standardValue?: string; // 鏍囧噯鍊�
+    thresholdMin?: string; // 闃堝�间笅闄�
+    thresholdMax?: string; // 闃堝�间笂闄�
+    measures?: ReportMeasure[];
+    children?: ReportItem[];
+  }
+
+  /** 妫�楠屾姤鍛婂崟 */
+  export interface QcReport {
+    qcType?: number;
+    docCode?: string;
+    docName?: string;
+    itemCode?: string;
+    itemName?: string;
+    itemSpecification?: string;
+    batchNo?: string;
+    samplingLocation?: string;
+    certificateNo?: string;
+    executeStandard?: string;
+    samplingTime?: Date;
+    batchQuantity?: number;
+    checkResult?: number;
+    inspectorUserId?: number;
+    inspectorName?: string;
+    auditUserId?: number;
+    auditName?: string;
+    approveUserId?: number;
+    approveName?: string;
+    remark?: string;
+    measureNos?: number[]; // 鍒楀ご锛氭祴閲忔壒娆″彿鍒楄〃
+    items?: ReportItem[];
+  }
+}
+
+/** 鏌ヨ妫�楠屾姤鍛婂崟鏁版嵁锛堟墦鍗扮敤锛� */
+export function getQcReport(qcId: number, qcType: number, resultId?: number) {
+  return requestClient.get<MesQcReportApi.QcReport>('/mes/qc/indicator-result/report', {
+    params: { qcId, qcType, resultId },
+  });
+}
diff --git a/src/api/mes/qc/ipqc/index.ts b/src/api/mes/qc/ipqc/index.ts
index 72c0e49..e25a440 100644
--- a/src/api/mes/qc/ipqc/index.ts
+++ b/src/api/mes/qc/ipqc/index.ts
@@ -43,6 +43,13 @@
     inspectDate?: number; // 妫�娴嬫棩鏈�
     inspectorUserId?: number; // 妫�娴嬩汉鍛樼敤鎴� ID
     inspectorNickname?: string; // 妫�娴嬩汉鍛樻樀绉帮紙鍏宠仈鏌ヨ锛�
+    auditUserId?: number; // 澶嶆牳浜� ID
+    auditNickname?: string; // 澶嶆牳浜烘樀绉帮紙鍏宠仈鏌ヨ锛�
+    approveUserId?: number; // 瀹℃牳浜� ID
+    approveNickname?: string; // 瀹℃牳浜烘樀绉帮紙鍏宠仈鏌ヨ锛�
+    samplingLocation?: string; // 閲囨牱鍦扮偣
+    certificateNo?: string; // 璇佷功缂栧彿/鍚堟牸璇佸彿
+    executeStandard?: string; // 鎵ц鏍囧噯
     status?: number; // 鐘舵��
     remark?: string; // 澶囨敞
   }
diff --git a/src/api/mes/qc/iqc/index.ts b/src/api/mes/qc/iqc/index.ts
index cdb04cb..94b2c3d 100644
--- a/src/api/mes/qc/iqc/index.ts
+++ b/src/api/mes/qc/iqc/index.ts
@@ -37,6 +37,13 @@
     inspector?: string; // 妫�娴嬩汉鍛橈紙鏄电О锛�
     inspectorUserId?: number; // 妫�娴嬩汉鍛� ID
     inspectorNickname?: string; // 妫�娴嬩汉鍛樻樀绉帮紙鍏宠仈鏌ヨ锛�
+    auditUserId?: number; // 澶嶆牳浜� ID
+    auditNickname?: string; // 澶嶆牳浜烘樀绉帮紙鍏宠仈鏌ヨ锛�
+    approveUserId?: number; // 瀹℃牳浜� ID
+    approveNickname?: string; // 瀹℃牳浜烘樀绉帮紙鍏宠仈鏌ヨ锛�
+    samplingLocation?: string; // 閲囨牱鍦扮偣
+    certificateNo?: string; // 璇佷功缂栧彿/鍚堟牸璇佸彿
+    executeStandard?: string; // 鎵ц鏍囧噯
     status?: number; // 鐘舵��
     remark?: string; // 澶囨敞
   }
diff --git a/src/api/mes/qc/oqc/index.ts b/src/api/mes/qc/oqc/index.ts
index 793f6db..28bfe5b 100644
--- a/src/api/mes/qc/oqc/index.ts
+++ b/src/api/mes/qc/oqc/index.ts
@@ -38,6 +38,13 @@
     inspectDate?: number; // 妫�娴嬫棩鏈�
     inspectorUserId?: number; // 妫�娴嬩汉鍛樼敤鎴� ID
     inspectorNickname?: string; // 妫�娴嬩汉鍛樻樀绉帮紙鍏宠仈鏌ヨ锛�
+    auditUserId?: number; // 澶嶆牳浜� ID
+    auditNickname?: string; // 澶嶆牳浜烘樀绉帮紙鍏宠仈鏌ヨ锛�
+    approveUserId?: number; // 瀹℃牳浜� ID
+    approveNickname?: string; // 瀹℃牳浜烘樀绉帮紙鍏宠仈鏌ヨ锛�
+    samplingLocation?: string; // 閲囨牱鍦扮偣
+    certificateNo?: string; // 璇佷功缂栧彿/鍚堟牸璇佸彿
+    executeStandard?: string; // 鎵ц鏍囧噯
     status?: number; // 鐘舵��
     remark?: string; // 澶囨敞
   }
diff --git a/src/api/mes/qc/rqc/index.ts b/src/api/mes/qc/rqc/index.ts
index 60b54da..207c610 100644
--- a/src/api/mes/qc/rqc/index.ts
+++ b/src/api/mes/qc/rqc/index.ts
@@ -27,6 +27,13 @@
     inspectDate?: number; // 妫�娴嬫棩鏈�
     inspectorUserId?: number; // 妫�娴嬩汉鍛樼敤鎴� ID
     inspectorNickname?: string; // 妫�娴嬩汉鍛樻樀绉帮紙鍏宠仈鏌ヨ锛�
+    auditUserId?: number; // 澶嶆牳浜� ID
+    auditNickname?: string; // 澶嶆牳浜烘樀绉帮紙鍏宠仈鏌ヨ锛�
+    approveUserId?: number; // 瀹℃牳浜� ID
+    approveNickname?: string; // 瀹℃牳浜烘樀绉帮紙鍏宠仈鏌ヨ锛�
+    samplingLocation?: string; // 閲囨牱鍦扮偣
+    certificateNo?: string; // 璇佷功缂栧彿/鍚堟牸璇佸彿
+    executeStandard?: string; // 鎵ц鏍囧噯
     status?: number; // 鐘舵��
     remark?: string; // 澶囨敞
     // 缂洪櫡缁熻
diff --git a/src/api/mes/qc/template/index.ts b/src/api/mes/qc/template/index.ts
index 7688644..06c8cd8 100644
--- a/src/api/mes/qc/template/index.ts
+++ b/src/api/mes/qc/template/index.ts
@@ -10,6 +10,7 @@
     name?: string; // 鏂规鍚嶇О
     types?: number[]; // 妫�娴嬬绫�
     status?: number; // 鐘舵��
+    defaultExecuteStandard?: string; // 榛樿鎵ц鏍囧噯锛堝缓鍗曟椂甯﹀叆涓昏〃锛�
     remark?: string; // 澶囨敞
     createTime?: Date; // 鍒涘缓鏃堕棿
   }
diff --git a/src/api/mes/qc/template/indicator/index.ts b/src/api/mes/qc/template/indicator/index.ts
index 519c86d..ff69124 100644
--- a/src/api/mes/qc/template/indicator/index.ts
+++ b/src/api/mes/qc/template/indicator/index.ts
@@ -14,6 +14,8 @@
     thresholdMax?: number; // 璇樊涓婇檺
     thresholdMin?: number; // 璇樊涓嬮檺
     docUrl?: string; // 璇存槑鍥綰RL
+    sortOrder?: number; // 鎺掑簭鍙凤紙鏂规鍐呭睍绀洪『搴忥級
+    judgeFlag?: boolean; // 鏄惁鍙備笌鍒ゅ畾鎻愮ず锛堝垎缁�/鍙傛暟琛�=false锛�
     remark?: string; // 澶囨敞
     indicatorCode?: string; // 妫�娴嬮」缂栫爜锛圝OIN锛�
     indicatorName?: string; // 妫�娴嬮」鍚嶇О锛圝OIN锛�
diff --git a/src/packages/constants/src/biz-mes-enum.ts b/src/packages/constants/src/biz-mes-enum.ts
index c84f3fc..3ad002f 100644
--- a/src/packages/constants/src/biz-mes-enum.ts
+++ b/src/packages/constants/src/biz-mes-enum.ts
@@ -476,6 +476,12 @@
   FILE: 5,
 } as const;
 
+/** MES 璐ㄦ鎸囨爣鏉$洰绫诲瀷鏋氫妇锛�1=褰曞叆椤癸紝2=鍒嗙粍椤癸紙瀵归綈鍚庣 MesQcIndicatorItemTypeEnum锛� */
+export const MesQcIndicatorItemType = {
+  RECORD: 1,
+  GROUP: 2,
+} as const;
+
 /** MES 涓氬姟绫诲瀷甯搁噺 */
 export const MesBizTypeEnum = {
   // WM 浠撳簱妯″潡 [100, 200)
diff --git a/src/views/mes/qc/components/qc-report-print.vue b/src/views/mes/qc/components/qc-report-print.vue
new file mode 100644
index 0000000..a3cfb4a
--- /dev/null
+++ b/src/views/mes/qc/components/qc-report-print.vue
@@ -0,0 +1,325 @@
+<script lang="ts" setup>
+import type { MesQcReportApi } from '#/api/mes/qc/indicatorresult';
+
+import { computed, nextTick, ref } from 'vue';
+
+import { DICT_TYPE } from '@vben/constants';
+import { getDictLabel } from '@vben/hooks';
+import { useUserStore } from '@vben/stores';
+import { formatDateTime } from '@vben/utils';
+
+import { getQcReport } from '#/api/mes/qc/indicatorresult';
+
+/**
+ * MES 妫�楠屾姤鍛婂崟鎵撳嵃缁勪欢锛堝寲宸ユ楠岃褰曠増寮忥細琛ㄥご + 妫�楠岄」鐭╅樀 + 骞宠娴嬮噺鍒� + 绛惧瓧鍖猴級
+ *
+ * 鎵撳嵃鏍峰紡鍙傝�� erp/sale/order/modules/print.vue锛圱eleport + body class + @media print锛夈��
+ */
+defineOptions({ name: 'MesQcReportPrint' });
+
+const userStore = useUserStore();
+
+/** 鎵佸钩鍖栧悗鐨勬姤鍛婅 */
+interface PrintRow {
+  kind: 'group' | 'record';
+  indicatorId?: number;
+  name?: string;
+  unit?: string;
+  method?: string; // 鍒嗙粍=鍏紡鏂囨湰锛屽綍鍏ラ」=妫�娴嬫柟娉�
+  standard?: string; // 鏍囧噯鍊硷紙鍚槇鍊煎尯闂达級
+  values: Record<number, string>; // measureNo -> 妫�娴嬪��
+  remarks: Record<number, string>; // measureNo -> 澶囨敞
+}
+
+const report = ref<MesQcReportApi.QcReport>({});
+const measureNos = ref<number[]>([1]);
+const printTime = ref('');
+
+/** 鏍囧噯鍊煎睍绀猴細鏍囧噯鍊� + 闃堝�煎尯闂� */
+function formatStandard(item: MesQcReportApi.ReportItem) {
+  const parts: string[] = [];
+  if (item.standardValue != null) {
+    parts.push(String(item.standardValue));
+  }
+  if (item.thresholdMin != null || item.thresholdMax != null) {
+    parts.push(`${item.thresholdMin ?? ''}~${item.thresholdMax ?? ''}`);
+  }
+  return parts.join(' ');
+}
+
+/** 灏嗘楠岄」鏍戞墎骞冲寲涓烘墦鍗拌锛堝垎缁勮 + 鍏跺瓙褰曞叆琛岋紱椤剁骇褰曞叆琛岀嫭绔嬫垚琛岋級 */
+const printRows = computed<PrintRow[]>(() => {
+  const rows: PrintRow[] = [];
+  const pushRecord = (item: MesQcReportApi.ReportItem, method: string) => {
+    const values: Record<number, string> = {};
+    const remarks: Record<number, string> = {};
+    (item.measures ?? []).forEach((m) => {
+      if (m.measureNo != null) {
+        values[m.measureNo] = m.value ?? '';
+        remarks[m.measureNo] = m.remark ?? '';
+      }
+    });
+    rows.push({
+      kind: 'record',
+      indicatorId: item.indicatorId,
+      name: item.indicatorName,
+      unit: item.unitText,
+      method,
+      standard: formatStandard(item),
+      values,
+      remarks,
+    });
+  };
+  const walk = (items: MesQcReportApi.ReportItem[] = []) => {
+    items.forEach((item) => {
+      if (item.itemType === 2) {
+        rows.push({
+          kind: 'group',
+          indicatorId: item.indicatorId,
+          name: item.indicatorName,
+          method: item.formulaText,
+          values: {},
+          remarks: {},
+        });
+        walk(item.children ?? []);
+      } else {
+        pushRecord(item, item.checkMethod ?? '');
+      }
+    });
+  };
+  walk(report.value.items ?? []);
+  return rows;
+});
+
+/** 妫�娴嬬粨鏋滄枃妗堬紙瀛楀吀 mes_qc_check_result锛� */
+const checkResultText = computed(() => {
+  if (report.value.checkResult == null) {
+    return '-';
+  }
+  return (
+    getDictLabel(DICT_TYPE.MES_QC_CHECK_RESULT, report.value.checkResult) || '-'
+  );
+});
+
+function waitForPaint() {
+  return new Promise<void>((resolve) => {
+    requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
+  });
+}
+
+function removePrintMode() {
+  document.body.classList.remove('mes-qc-report-printing');
+}
+
+/** 鎵撳嵃锛氬姞杞芥姤鍛婃暟鎹悗鍒囧埌鎵撳嵃妯″紡璋冪敤娴忚鍣ㄦ墦鍗� */
+async function print(qcId: number, qcType: number, resultId?: number) {
+  const data = await getQcReport(qcId, qcType, resultId);
+  report.value = data;
+  measureNos.value = data.measureNos?.length ? data.measureNos : [1];
+  printTime.value = formatDateTime(new Date());
+  await nextTick();
+  await waitForPaint();
+  document.body.classList.add('mes-qc-report-printing');
+  window.addEventListener('afterprint', removePrintMode, { once: true });
+  window.print();
+}
+
+defineExpose({ print });
+</script>
+
+<template>
+  <Teleport to="body">
+    <div
+      id="mesQcReportPrint"
+      class="mes-qc-report-print pointer-events-none fixed left-0 top-0 z-[-1] w-full bg-white text-[#303133] opacity-0"
+    >
+      <h2 class="m-0 mb-1 text-center text-[1.6em] font-bold leading-[1.2]">
+        {{ report.docName || '妫�楠屾姤鍛�' }}
+      </h2>
+      <div class="mb-2 text-center text-sm">
+        {{ report.itemName || '' }}
+        <span v-if="report.itemSpecification">锛弡{ report.itemSpecification }}</span>
+        <span v-if="report.executeStandard">銆�鎵ц鏍囧噯锛歿{ report.executeStandard }}</span>
+      </div>
+
+      <!-- 琛ㄥご淇℃伅鏍� -->
+      <div
+        class="mb-3 grid grid-cols-3 gap-x-6 gap-y-1 border border-solid border-[#dcdfe6] p-3 text-sm leading-[1.6]"
+      >
+        <div>妫�楠屽崟鍙凤細{{ report.docCode || '-' }}</div>
+        <div>鐗╂枡缂栫爜锛歿{ report.itemCode || '-' }}</div>
+        <div>鎵规鍙凤細{{ report.batchNo || '-' }}</div>
+        <div>閲囨牱鍦扮偣锛歿{ report.samplingLocation || '-' }}</div>
+        <div>璇佷功缂栧彿锛歿{ report.certificateNo || '-' }}</div>
+        <div>鎵归噺锛歿{ report.batchQuantity ?? '-' }}</div>
+        <div>
+          閲囨牱/妫�楠屾椂闂达細{{ formatDateTime(report.samplingTime) || '-' }}
+        </div>
+        <div>妫�娴嬬粨璁猴細{{ checkResultText }}</div>
+        <div>鎵撳嵃鏃堕棿锛歿{ printTime || '-' }}</div>
+      </div>
+
+      <!-- 妫�楠岄」鐭╅樀 -->
+      <table class="w-full border-collapse text-[13px] leading-[1.5]">
+        <thead>
+          <tr>
+            <th class="cell bg">妫�楠岄」鐩�</th>
+            <th class="cell w-16 bg">鍗曚綅</th>
+            <th class="cell bg">鏂规硶/鍏紡</th>
+            <th class="cell w-24 bg">鏍囧噯鍊�</th>
+            <th v-for="no in measureNos" :key="`h-${no}`" class="cell w-20 bg">
+              娴嬮噺{{ no }}
+            </th>
+            <th class="cell bg">澶囨敞</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(row, i) in printRows" :key="row.indicatorId ?? i">
+            <template v-if="row.kind === 'group'">
+              <td class="cell group-name" colspan="3">{{ row.name }}</td>
+              <td class="cell group-formula" :colspan="measureNos.length + 2">
+                {{ row.method || '' }}
+              </td>
+            </template>
+            <template v-else>
+              <td class="cell record-name">{{ row.name }}</td>
+              <td class="cell text-center">{{ row.unit || '-' }}</td>
+              <td class="cell">{{ row.method || '-' }}</td>
+              <td class="cell text-center">{{ row.standard || '-' }}</td>
+              <td
+                v-for="no in measureNos"
+                :key="`v-${row.indicatorId}-${no}`"
+                class="cell text-center"
+              >
+                {{ row.values[no] || '' }}
+              </td>
+              <td class="cell">
+                <template v-if="measureNos.length === 1">
+                  {{ row.remarks[measureNos[0]!] || '' }}
+                </template>
+                <template v-else>
+                  <div v-for="no in measureNos" :key="`r-${row.indicatorId}-${no}`">
+                    {{ no }}:{{ row.remarks[no] || '' }}
+                  </div>
+                </template>
+              </td>
+            </template>
+          </tr>
+          <tr v-if="printRows.length === 0">
+            <td class="cell text-center" :colspan="6 + measureNos.length">
+              鏆傛棤妫�楠岄」
+            </td>
+          </tr>
+        </tbody>
+      </table>
+
+      <!-- 澶囨敞 + 绛惧瓧鍖� -->
+      <div class="mt-3 border border-solid border-[#dcdfe6] p-3 text-sm leading-[1.6]">
+        澶囨敞锛歿{ report.remark || '-' }}
+      </div>
+      <div
+        class="mt-4 grid grid-cols-3 gap-x-10 gap-y-4 border border-dashed border-[#dcdfe6] p-4 text-sm leading-[1.8]"
+      >
+        <div>
+          鍒嗘瀽鑰咃細{{ report.inspectorName || '-' }}
+        </div>
+        <div>
+          澶嶆牳浜猴細{{ report.auditName || '-' }}
+        </div>
+        <div>
+          瀹℃牳浜猴細{{ report.approveName || '-' }}
+        </div>
+        <div>
+          绛惧瓧锛�<span class="sig"></span>
+        </div>
+        <div>
+          绛惧瓧锛�<span class="sig"></span>
+        </div>
+        <div>
+          绛惧瓧锛�<span class="sig"></span>
+        </div>
+      </div>
+
+      <div class="mt-4 flex justify-between text-xs text-[#909399]">
+        <div>鎵撳嵃浜哄憳锛歿{ userStore.userInfo?.nickname || '-' }}</div>
+        <div>鎵撳嵃鏃堕棿锛歿{ printTime || '-' }}</div>
+      </div>
+    </div>
+  </Teleport>
+</template>
+
+<style scoped>
+@page {
+  margin: 8mm 10mm;
+}
+
+.mes-qc-report-print {
+  .cell {
+    padding: 4px 6px;
+    text-align: left;
+    border: 1px solid #dcdfe6;
+  }
+
+  .cell.bg {
+    font-weight: bold;
+    background: #f5f7fa;
+    text-align: center;
+  }
+
+  .cell.text-center {
+    text-align: center;
+  }
+
+  .group-name {
+    font-weight: bold;
+    background: #fafafa;
+  }
+
+  .group-formula {
+    font-style: italic;
+    color: #555;
+    background: #fafafa;
+  }
+
+  .record-name {
+    padding-left: 20px;
+  }
+
+  .sig {
+    display: inline-block;
+    width: 90px;
+    border-bottom: 1px solid #303133;
+  }
+}
+
+@media print {
+  :global(body.mes-qc-report-printing) {
+    padding: 0 !important;
+    margin: 0 !important;
+    -webkit-print-color-adjust: exact;
+    print-color-adjust: exact;
+  }
+
+  :global(body.mes-qc-report-printing *) {
+    visibility: hidden !important;
+  }
+
+  :global(body.mes-qc-report-printing .mes-qc-report-print),
+  :global(body.mes-qc-report-printing .mes-qc-report-print *) {
+    visibility: visible !important;
+  }
+
+  :global(body.mes-qc-report-printing .mes-qc-report-print) {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: auto;
+    box-sizing: border-box;
+    width: 100%;
+    padding: 0 !important;
+    margin: 0 !important;
+    pointer-events: auto;
+    opacity: 1;
+  }
+}
+</style>
diff --git a/src/views/mes/qc/indicator/data.ts b/src/views/mes/qc/indicator/data.ts
index a20cc84..32c409e 100644
--- a/src/views/mes/qc/indicator/data.ts
+++ b/src/views/mes/qc/indicator/data.ts
@@ -7,12 +7,14 @@
 import {
   DICT_TYPE,
   MesAutoCodeRuleCode,
+  MesQcIndicatorItemType,
   MesQcResultValueType,
 } from '@vben/constants';
 import { getDictOptions } from '@vben/hooks';
 
 import { Button } from 'ant-design-vue';
 
+import { getIndicatorList } from '#/api/mes/qc/indicator';
 import { generateAutoCode } from '#/api/mes/md/autocode/record';
 
 import { QcIndicatorResultSpecificationInput } from './components';
@@ -63,6 +65,42 @@
       rules: 'required',
     },
     {
+      fieldName: 'itemType',
+      label: '鏉$洰绫诲瀷',
+      component: 'RadioGroup',
+      defaultValue: MesQcIndicatorItemType.RECORD,
+      componentProps: {
+        options: [
+          { label: '褰曞叆椤�', value: MesQcIndicatorItemType.RECORD },
+          { label: '鍒嗙粍椤�', value: MesQcIndicatorItemType.GROUP },
+        ],
+        optionType: 'button',
+      },
+      rules: 'required',
+    },
+    {
+      fieldName: 'parentId',
+      label: '鎵�灞炲垎缁�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: async () => {
+          const list = await getIndicatorList();
+          // 浠呭彲閫夋嫨鍒嗙粍椤逛綔涓虹埗绾э紝涓斿垎缁勯」鏈韩涓嶅彲鍐嶆寕鐖剁骇锛堜粎涓ょ骇锛�
+          return list
+            .filter((i) => i.itemType === MesQcIndicatorItemType.GROUP)
+            .map((i) => ({ label: i.name, value: i.id }));
+        },
+        placeholder: '涓嶉�夊垯涓洪《绾ч」',
+      },
+      dependencies: {
+        triggerFields: ['itemType'],
+        // 鍒嗙粍椤瑰繀椤讳负椤剁骇锛岄殣钘忓苟娓呯┖涓婄骇
+        show: (values) => values.itemType !== MesQcIndicatorItemType.GROUP,
+        if: (values) => values.itemType !== MesQcIndicatorItemType.GROUP,
+      },
+    },
+    {
       fieldName: 'type',
       label: '妫�娴嬮」绫诲瀷',
       component: 'Select',
@@ -74,12 +112,45 @@
       rules: 'required',
     },
     {
+      fieldName: 'formulaText',
+      label: '鍏紡鏂囨湰',
+      component: 'Input',
+      componentProps: {
+        maxlength: 500,
+        placeholder: '濡� w3 = c 脳 V 脳 0.06005 / m 脳 100%锛堜粎灞曠ず锛屼笉鍙備笌璁$畻锛�',
+      },
+      dependencies: {
+        triggerFields: ['itemType'],
+        if: (values) => values.itemType === MesQcIndicatorItemType.GROUP,
+      },
+    },
+    {
       fieldName: 'tool',
       label: '妫�娴嬪伐鍏�',
       component: 'Input',
       componentProps: {
         maxlength: 100,
         placeholder: '璇疯緭鍏ユ娴嬪伐鍏�',
+      },
+    },
+    {
+      fieldName: 'unitText',
+      label: '鍗曚綅鏂囨湰',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '濡� %銆乬銆佹棤锛屼粎灞曠ず涓嶅弬涓庤绠�',
+      },
+    },
+    {
+      fieldName: 'sortOrder',
+      label: '鎺掑簭鍙�',
+      component: 'InputNumber',
+      defaultValue: 0,
+      componentProps: {
+        min: 0,
+        precision: 0,
+        placeholder: '鍚岀骇鎺掑簭锛屾暟瀛楀皬鐨勫湪鍓�',
       },
     },
     {
@@ -95,6 +166,11 @@
         placeholder: '璇烽�夋嫨缁撴灉鍊肩被鍨�',
       },
       rules: 'required',
+      dependencies: {
+        triggerFields: ['itemType'],
+        // 鍒嗙粍椤逛笉褰曞叆缁撴灉鍊硷紝闅愯棌骞惰烦杩囨牎楠�
+        if: (values) => values.itemType !== MesQcIndicatorItemType.GROUP,
+      },
     },
     {
       fieldName: 'resultSpecification',
@@ -183,6 +259,19 @@
       minWidth: 160,
     },
     {
+      field: 'itemType',
+      title: '鏉$洰绫诲瀷',
+      width: 90,
+      formatter: ({ cellValue }) =>
+        cellValue === MesQcIndicatorItemType.GROUP ? '鍒嗙粍椤�' : '褰曞叆椤�',
+    },
+    {
+      field: 'parentName',
+      title: '鎵�灞炲垎缁�',
+      width: 120,
+      formatter: ({ cellValue }) => cellValue || '-',
+    },
+    {
       field: 'type',
       title: '妫�娴嬮」绫诲瀷',
       width: 120,
@@ -194,6 +283,12 @@
       width: 140,
     },
     {
+      field: 'unitText',
+      title: '鍗曚綅',
+      width: 80,
+      formatter: ({ cellValue }) => cellValue || '-',
+    },
+    {
       field: 'resultType',
       title: '缁撴灉鍊肩被鍨�',
       width: 120,
diff --git a/src/views/mes/qc/indicatorresult/components/form.vue b/src/views/mes/qc/indicatorresult/components/form.vue
index c6481b2..0dbd5a5 100644
--- a/src/views/mes/qc/indicatorresult/components/form.vue
+++ b/src/views/mes/qc/indicatorresult/components/form.vue
@@ -6,10 +6,11 @@
 import { computed, ref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
-import { MesQcResultValueType } from '@vben/constants';
+import { MesQcIndicatorItemType, MesQcResultValueType } from '@vben/constants';
 import { getDictOptions } from '@vben/hooks';
 
 import {
+  Button,
   Form as AForm,
   Divider,
   Input,
@@ -36,11 +37,36 @@
   qcType: number;
 }
 
+/** 鍙紪杈戞祴閲忔壒娆★紙鍦ㄦ帴鍙g粨鏋勪笂澧炲姞鏁板�肩粦瀹氬瓧娈碉級 */
+interface EditMeasure {
+  detailId?: number;
+  resultId?: number;
+  measureNo: number;
+  value?: string;
+  valueNumber?: number;
+  remark?: string;
+}
+
+/** 鍙紪杈戞楠岄」锛堟爲褰㈣妭鐐癸級 */
+interface EditItem {
+  indicatorId?: number;
+  indicatorName?: string;
+  valueType?: number;
+  valueSpecification?: string;
+  parentId?: number;
+  itemType?: number;
+  formulaText?: string;
+  unitText?: string;
+  sortOrder?: number;
+  measures: EditMeasure[];
+  children?: EditItem[];
+}
+
 defineOptions({ name: 'QcIndicatorResultForm' });
 
 const emit = defineEmits(['success']);
 const formType = ref<FormType>('create');
-const items = ref<MesQcIndicatorResultApi.IndicatorResultDetail[]>([]);
+const roots = ref<EditItem[]>([]);
 const ctxData = ref<CtxData>();
 
 const getTitle = computed(() =>
@@ -63,6 +89,19 @@
   wrapperClass: 'grid-cols-2',
 });
 
+/** 鏄惁鍒嗙粍椤癸紙鍒嗙粍椤逛笉褰曞叆鍊硷紝浠呮壙杞藉眰绾т笌鍏紡鏂囨湰锛� */
+function isGroup(item: EditItem) {
+  return item.itemType === MesQcIndicatorItemType.GROUP;
+}
+
+/** 鏄惁鏁板�煎瀷褰曞叆锛堝喅瀹� InputNumber 涓庢枃鏈帶浠讹級 */
+function isNumeric(item: EditItem) {
+  return (
+    item.valueType === MesQcResultValueType.FLOAT ||
+    item.valueType === MesQcResultValueType.INTEGER
+  );
+}
+
 /** 鑾峰彇瀛楀吀閫夐」锛坴alueSpecification 涓虹郴缁熷瓧鍏哥被鍨嬪悕锛� */
 function getValueOptions(dictType?: string) {
   return dictType
@@ -71,6 +110,75 @@
         value: String(value),
       }))
     : [];
+}
+
+/** 灏嗘帴鍙h繑鍥炵殑鏄庣粏鏍戣浆鎹负鍙紪杈戠粨鏋勶細鍒嗙粍閫掑綊銆佸綍鍏ラ」淇濊瘉鑷冲皯涓�涓祴閲忔壒娆� */
+function toEditItems(
+  items: MesQcIndicatorResultApi.IndicatorResultDetail[] = [],
+): EditItem[] {
+  return items.map((item) => {
+    const node: EditItem = {
+      indicatorId: item.indicatorId,
+      indicatorName: item.indicatorName,
+      valueType: item.valueType,
+      valueSpecification: item.valueSpecification,
+      parentId: item.parentId,
+      itemType: item.itemType,
+      formulaText: item.formulaText,
+      unitText: item.unitText,
+      sortOrder: item.sortOrder,
+      measures: [],
+      children: item.children ? toEditItems(item.children) : undefined,
+    };
+    if (isGroup(node)) {
+      return node;
+    }
+    const measures = (item.measures ?? []).map((m) => ({
+      detailId: m.detailId,
+      resultId: m.resultId,
+      measureNo: m.measureNo ?? 1,
+      value: m.value,
+      valueNumber:
+        isNumeric(node) && m.value !== null && m.value !== undefined
+          ? Number(m.value)
+          : undefined,
+      remark: m.remark,
+    }));
+    node.measures = measures.length > 0 ? measures : [{ measureNo: 1 }];
+    return node;
+  });
+}
+
+/** 鏀堕泦鎵�鏈夊綍鍏ラ」锛堝彾瀛愶級鐢ㄤ簬鎻愪氦涓庡睍绀虹粺璁� */
+function collectLeaves(nodes: EditItem[]): EditItem[] {
+  const leaves: EditItem[] = [];
+  const walk = (list: EditItem[]) => {
+    list.forEach((n) => {
+      if (isGroup(n)) {
+        walk(n.children ?? []);
+      } else {
+        leaves.push(n);
+      }
+    });
+  };
+  walk(nodes);
+  return leaves;
+}
+
+/** 鏂板涓�涓祴閲忔壒娆� */
+function addMeasure(item: EditItem) {
+  const nextNo =
+    item.measures.reduce((max, m) => Math.max(max, m.measureNo ?? 0), 0) + 1;
+  item.measures.push({ measureNo: nextNo });
+}
+
+/** 鍒犻櫎鎸囧畾娴嬮噺鎵规锛堣嚦灏戜繚鐣欎竴涓級 */
+function removeMeasure(item: EditItem, index: number) {
+  if (item.measures.length <= 1) {
+    message.warning('鑷冲皯淇濈暀涓�涓祴閲忔壒娆�');
+    return;
+  }
+  item.measures.splice(index, 1);
 }
 
 const [Modal, modalApi] = useVbenModal({
@@ -83,25 +191,26 @@
       return;
     }
     modalApi.lock();
-    // 鎻愪氦琛ㄥ崟
     const head =
       (await formApi.getValues()) as MesQcIndicatorResultApi.IndicatorResult;
-    const submitItems = items.value.map((item) => {
-      const submit: MesQcIndicatorResultApi.IndicatorResultDetail = {
-        id: item.id,
-        indicatorId: item.indicatorId,
-        remark: item.remark,
-      };
-      if (
-        item.valueType === MesQcResultValueType.FLOAT ||
-        item.valueType === MesQcResultValueType.INTEGER
-      ) {
-        submit.value =
-          item.valueNumber === null ? undefined : String(item.valueNumber);
-      } else {
-        submit.value = item.value;
-      }
-      return submit;
+    // 灞曞紑锛氭瘡涓綍鍏ラ」鐨勬瘡涓祴閲忔壒娆� 鈫� 涓�鏉℃槑缁�
+    const submitItems: MesQcIndicatorResultApi.IndicatorResultDetail[] = [];
+    collectLeaves(roots.value).forEach((item) => {
+      item.measures.forEach((measure) => {
+        const value = isNumeric(item)
+          ? measure.valueNumber === null || measure.valueNumber === undefined
+            ? undefined
+            : String(measure.valueNumber)
+          : measure.value;
+        submitItems.push({
+          id: measure.detailId,
+          resultId: measure.resultId,
+          indicatorId: item.indicatorId,
+          measureNo: measure.measureNo,
+          value,
+          remark: measure.remark,
+        });
+      });
     });
     const payload: MesQcIndicatorResultApi.IndicatorResult = {
       ...head,
@@ -117,7 +226,6 @@
         await createIndicatorResult(payload);
         message.success($t('common.createSuccess'));
       }
-      // 鍏抽棴骞舵彁绀�
       await modalApi.close();
       emit('success');
     } finally {
@@ -127,11 +235,10 @@
   async onOpenChange(isOpen: boolean) {
     if (!isOpen) {
       ctxData.value = undefined;
-      items.value = [];
+      roots.value = [];
       return;
     }
     formApi.setState({ schema: useQcIndicatorResultFormSchema(formApi) });
-    // 鍔犺浇鏁版嵁
     const data = modalApi.getData<CtxData>();
     ctxData.value = data;
     formType.value = data.formType;
@@ -142,17 +249,7 @@
         data.qcType,
         data.id,
       );
-      // 鍥炲~鏁板�煎瓧娈碉紙鐢ㄤ簬 InputNumber 缁戝畾锛�
-      items.value = (detail.items ?? []).map((item) => ({
-        ...item,
-        valueNumber:
-          (item.valueType === MesQcResultValueType.FLOAT ||
-            item.valueType === MesQcResultValueType.INTEGER) &&
-          item.value !== null
-            ? Number(item.value)
-            : undefined,
-      }));
-      // 璁剧疆鍒� values
+      roots.value = toEditItems(detail.items);
       await formApi.setValues({
         id: detail.id,
         code: detail.code,
@@ -164,6 +261,18 @@
     }
   },
 });
+
+/** 鍗曚釜娴嬮噺鍊艰緭鍏ユ帶浠剁粦瀹氾紙鏁板�煎瀷璧� valueNumber锛屽叾浣欒蛋 value锛� */
+function bindMeasure(item: EditItem, measure: EditMeasure) {
+  return isNumeric(item) ? measure.valueNumber : measure.value;
+}
+function onMeasureInput(item: EditItem, measure: EditMeasure, v: any) {
+  if (isNumeric(item)) {
+    measure.valueNumber = v === null ? undefined : Number(v);
+  } else {
+    measure.value = v;
+  }
+}
 </script>
 
 <template>
@@ -171,48 +280,182 @@
     <div class="px-4">
       <Form />
       <Divider>妫�娴嬪��</Divider>
-      <!-- 妫�娴嬪�兼帶浠剁敱姣忚 valueType 椹卞姩锛岄�愯娓叉煋锛欶LOAT/INTEGER 璧� InputNumber锛孌ICT 璧� Select 骞舵寜 valueSpecification 瑙f瀽閫夐」 -->
-      <AForm :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
-        <div
-          v-for="(item, index) in items"
-          :key="item.indicatorId ?? index"
-          class="mb-2"
-        >
-          <AForm.Item
-            :label="`妫�娴嬮」${index + 1}锛�${item.indicatorName ?? ''}`"
-          >
-            <InputNumber
-              v-if="
-                item.valueType === MesQcResultValueType.FLOAT ||
-                item.valueType === MesQcResultValueType.INTEGER
-              "
-              v-model:value="item.valueNumber"
-              :precision="item.valueType === MesQcResultValueType.FLOAT ? 4 : 0"
-              class="!w-full"
-              placeholder="璇疯緭鍏�"
-            />
-            <Textarea
-              v-else-if="item.valueType === MesQcResultValueType.TEXT"
-              v-model:value="item.value"
-              :rows="2"
-              placeholder="璇疯緭鍏ユ娴嬪��"
-            />
-            <Select
-              v-else-if="item.valueType === MesQcResultValueType.DICT"
-              v-model:value="item.value"
-              allow-clear
-              :options="getValueOptions(item.valueSpecification)"
-              placeholder="璇烽�夋嫨"
-            />
-            <Input
-              v-else-if="item.valueType === MesQcResultValueType.FILE"
-              v-model:value="item.value"
-              placeholder="璇疯緭鍏ユ枃浠跺湴鍧�"
-            />
-            <Input v-else v-model:value="item.value" placeholder="璇疯緭鍏�" />
-          </AForm.Item>
-        </div>
-      </AForm>
+      <div v-if="roots.length === 0" class="py-4 text-center text-gray-400">
+        璇ヨ川妫�鍗曟湭閰嶇疆妫�娴嬫寚鏍�
+      </div>
+      <div v-else class="qc-result-tree">
+        <template v-for="(node, ni) in roots" :key="node.indicatorId ?? ni">
+          <!-- 鍒嗙粍椤癸細鏍囬琛� + 鍏紡鏂囨湰锛屼笅鎸傚瓙褰曞叆椤� -->
+          <div v-if="isGroup(node)">
+            <div
+              class="mb-2 flex items-center justify-between rounded bg-gray-100 px-3 py-1.5 font-medium"
+            >
+              <span>{{ node.indicatorName }}</span>
+              <span v-if="node.formulaText" class="text-xs text-gray-500">
+                {{ node.formulaText }}
+              </span>
+            </div>
+            <div
+              v-for="(child, ci) in node.children ?? []"
+              :key="child.indicatorId ?? ci"
+              class="mb-3 ml-4"
+            >
+              <div class="mb-1 flex items-center justify-between">
+                <span class="font-medium">
+                  {{ child.indicatorName }}
+                  <span v-if="child.unitText" class="text-xs text-gray-500">
+                    锛坽{ child.unitText }}锛�
+                  </span>
+                </span>
+                <Button
+                  size="small"
+                  type="link"
+                  @click="addMeasure(child)"
+                >
+                  + 娴嬮噺鎵规
+                </Button>
+              </div>
+              <div
+                v-for="(measure, mi) in child.measures"
+                :key="mi"
+                class="mb-1 flex items-center gap-2"
+              >
+                <span class="w-16 shrink-0 text-right text-xs text-gray-500">
+                  绗� {{ measure.measureNo }} 娆�
+                </span>
+                <InputNumber
+                  v-if="child.valueType === MesQcResultValueType.FLOAT || child.valueType === MesQcResultValueType.INTEGER"
+                  :value="bindMeasure(child, measure)"
+                  :precision="child.valueType === MesQcResultValueType.FLOAT ? 4 : 0"
+                  class="!w-48"
+                  placeholder="璇疯緭鍏�"
+                  @update:value="(v) => onMeasureInput(child, measure, v)"
+                />
+                <Textarea
+                  v-else-if="child.valueType === MesQcResultValueType.TEXT"
+                  v-model:value="measure.value"
+                  :rows="1"
+                  class="!w-48"
+                  placeholder="璇疯緭鍏ユ娴嬪��"
+                />
+                <Select
+                  v-else-if="child.valueType === MesQcResultValueType.DICT"
+                  v-model:value="measure.value"
+                  allow-clear
+                  class="!w-48"
+                  :options="getValueOptions(child.valueSpecification)"
+                  placeholder="璇烽�夋嫨"
+                />
+                <Input
+                  v-else-if="child.valueType === MesQcResultValueType.FILE"
+                  v-model:value="measure.value"
+                  class="!w-48"
+                  placeholder="璇疯緭鍏ユ枃浠跺湴鍧�"
+                />
+                <Input
+                  v-else
+                  v-model:value="measure.value"
+                  class="!w-48"
+                  placeholder="璇疯緭鍏�"
+                />
+                <Input
+                  v-model:value="measure.remark"
+                  class="flex-1"
+                  placeholder="澶囨敞"
+                />
+                <Button
+                  size="small"
+                  type="text"
+                  danger
+                  :disabled="child.measures.length <= 1"
+                  @click="removeMeasure(child, mi)"
+                >
+                  鍒犻櫎
+                </Button>
+              </div>
+            </div>
+          </div>
+          <!-- 椤剁骇褰曞叆椤� -->
+          <div v-else class="mb-3">
+            <div class="mb-1 flex items-center justify-between">
+              <span class="font-medium">
+                {{ node.indicatorName }}
+                <span v-if="node.unitText" class="text-xs text-gray-500">
+                  锛坽{ node.unitText }}锛�
+                </span>
+              </span>
+              <Button size="small" type="link" @click="addMeasure(node)">
+                + 娴嬮噺鎵规
+              </Button>
+            </div>
+            <div
+              v-for="(measure, mi) in node.measures"
+              :key="mi"
+              class="mb-1 flex items-center gap-2"
+            >
+              <span class="w-16 shrink-0 text-right text-xs text-gray-500">
+                绗� {{ measure.measureNo }} 娆�
+              </span>
+              <InputNumber
+                v-if="node.valueType === MesQcResultValueType.FLOAT || node.valueType === MesQcResultValueType.INTEGER"
+                :value="bindMeasure(node, measure)"
+                :precision="node.valueType === MesQcResultValueType.FLOAT ? 4 : 0"
+                class="!w-48"
+                placeholder="璇疯緭鍏�"
+                @update:value="(v) => onMeasureInput(node, measure, v)"
+              />
+              <Textarea
+                v-else-if="node.valueType === MesQcResultValueType.TEXT"
+                v-model:value="measure.value"
+                :rows="1"
+                class="!w-48"
+                placeholder="璇疯緭鍏ユ娴嬪��"
+              />
+              <Select
+                v-else-if="node.valueType === MesQcResultValueType.DICT"
+                v-model:value="measure.value"
+                allow-clear
+                class="!w-48"
+                :options="getValueOptions(node.valueSpecification)"
+                placeholder="璇烽�夋嫨"
+              />
+              <Input
+                v-else-if="node.valueType === MesQcResultValueType.FILE"
+                v-model:value="measure.value"
+                class="!w-48"
+                placeholder="璇疯緭鍏ユ枃浠跺湴鍧�"
+              />
+              <Input
+                v-else
+                v-model:value="measure.value"
+                class="!w-48"
+                placeholder="璇疯緭鍏�"
+              />
+              <Input
+                v-model:value="measure.remark"
+                class="flex-1"
+                placeholder="澶囨敞"
+              />
+              <Button
+                size="small"
+                type="text"
+                danger
+                :disabled="node.measures.length <= 1"
+                @click="removeMeasure(node, mi)"
+              >
+                鍒犻櫎
+              </Button>
+            </div>
+          </div>
+        </template>
+      </div>
     </div>
   </Modal>
 </template>
+
+<style scoped>
+.qc-result-tree {
+  max-height: 60vh;
+  overflow-y: auto;
+}
+</style>
diff --git a/src/views/mes/qc/ipqc/data.ts b/src/views/mes/qc/ipqc/data.ts
index 86522b9..78363f1 100644
--- a/src/views/mes/qc/ipqc/data.ts
+++ b/src/views/mes/qc/ipqc/data.ts
@@ -369,6 +369,57 @@
       rules: 'required',
     },
     {
+      fieldName: 'samplingLocation',
+      label: '閲囨牱鍦扮偣',
+      component: 'Input',
+      componentProps: {
+        maxlength: 100,
+        placeholder: '璇疯緭鍏ラ噰鏍峰湴鐐�',
+      },
+    },
+    {
+      fieldName: 'certificateNo',
+      label: '璇佷功缂栧彿',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '璇疯緭鍏ヨ瘉涔︾紪鍙�',
+      },
+    },
+    {
+      fieldName: 'executeStandard',
+      label: '鎵ц鏍囧噯',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '濡� GB/T 6027锛岄�夋嫨璐ㄦ鏂规鍚庤嚜鍔ㄥ甫鍏�',
+      },
+    },
+    {
+      fieldName: 'auditUserId',
+      label: '澶嶆牳浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: getSimpleUserList,
+        labelField: 'nickname',
+        placeholder: '璇烽�夋嫨澶嶆牳浜�',
+        valueField: 'id',
+      },
+    },
+    {
+      fieldName: 'approveUserId',
+      label: '瀹℃牳浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: getSimpleUserList,
+        labelField: 'nickname',
+        placeholder: '璇烽�夋嫨瀹℃牳浜�',
+        valueField: 'id',
+      },
+    },
+    {
       fieldName: 'checkResult',
       label: '妫�娴嬬粨鏋�',
       component: 'Select',
diff --git a/src/views/mes/qc/ipqc/index.vue b/src/views/mes/qc/ipqc/index.vue
index 832a85a..58eda85 100644
--- a/src/views/mes/qc/ipqc/index.vue
+++ b/src/views/mes/qc/ipqc/index.vue
@@ -2,8 +2,10 @@
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesQcIpqcApi } from '#/api/mes/qc/ipqc';
 
+import { ref } from 'vue';
+
 import { Page, useVbenModal } from '@vben/common-ui';
-import { MesQcStatusEnum } from '@vben/constants';
+import { MesQcStatusEnum, MesQcTypeEnum } from '@vben/constants';
 
 import { Button, message } from 'ant-design-vue';
 
@@ -11,6 +13,7 @@
 import { deleteIpqc, exportIpqc, getIpqcPage } from '#/api/mes/qc/ipqc';
 import { $t } from '#/locales';
 import QcExportRangeModal from '#/views/mes/qc/components/export-range-modal.vue';
+import QcReportPrint from '#/views/mes/qc/components/qc-report-print.vue';
 
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
@@ -25,9 +28,16 @@
   destroyOnClose: true,
 });
 
+const printRef = ref<InstanceType<typeof QcReportPrint> | null>(null);
+
 /** 鍒锋柊琛ㄦ牸 */
 function handleRefresh() {
   gridApi.query();
+}
+
+/** 鎵撳嵃妫�楠屾姤鍛� */
+async function handlePrint(row: MesQcIpqcApi.Ipqc) {
+  await printRef.value?.print(row.id!, MesQcTypeEnum.IPQC);
 }
 
 /** 鍒涘缓杩囩▼妫�楠屽崟 */
@@ -106,6 +116,7 @@
   <Page auto-content-height>
     <FormModal @success="handleRefresh" />
     <ExportRangeModal />
+    <QcReportPrint ref="printRef" />
     <Grid table-title="杩囩▼妫�楠屽崟鍒楄〃">
       <template #toolbar-tools>
         <TableAction
@@ -156,6 +167,13 @@
               },
             },
             {
+              label: '鎵撳嵃鎶ュ憡',
+              type: 'link',
+              icon: 'ant-design:printer-outlined',
+              auth: ['mes:qc-ipqc:query'],
+              onClick: handlePrint.bind(null, row),
+            },
+            {
               label: $t('common.detail'),
               type: 'link',
               icon: ACTION_ICON.VIEW,
diff --git a/src/views/mes/qc/iqc/data.ts b/src/views/mes/qc/iqc/data.ts
index a59f777..4b85dab 100644
--- a/src/views/mes/qc/iqc/data.ts
+++ b/src/views/mes/qc/iqc/data.ts
@@ -274,6 +274,57 @@
       rules: 'required',
     },
     {
+      fieldName: 'samplingLocation',
+      label: '閲囨牱鍦扮偣',
+      component: 'Input',
+      componentProps: {
+        maxlength: 100,
+        placeholder: '璇疯緭鍏ラ噰鏍峰湴鐐�',
+      },
+    },
+    {
+      fieldName: 'certificateNo',
+      label: '璇佷功缂栧彿',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '璇疯緭鍏ヨ瘉涔︾紪鍙�',
+      },
+    },
+    {
+      fieldName: 'executeStandard',
+      label: '鎵ц鏍囧噯',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '濡� GB/T 6027锛岄�夋嫨璐ㄦ鏂规鍚庤嚜鍔ㄥ甫鍏�',
+      },
+    },
+    {
+      fieldName: 'auditUserId',
+      label: '澶嶆牳浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: getSimpleUserList,
+        labelField: 'nickname',
+        placeholder: '璇烽�夋嫨澶嶆牳浜�',
+        valueField: 'id',
+      },
+    },
+    {
+      fieldName: 'approveUserId',
+      label: '瀹℃牳浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: getSimpleUserList,
+        labelField: 'nickname',
+        placeholder: '璇烽�夋嫨瀹℃牳浜�',
+        valueField: 'id',
+      },
+    },
+    {
       fieldName: 'checkResult',
       label: '妫�娴嬬粨鏋�',
       component: 'Select',
diff --git a/src/views/mes/qc/iqc/index.vue b/src/views/mes/qc/iqc/index.vue
index 761305f..6a42897 100644
--- a/src/views/mes/qc/iqc/index.vue
+++ b/src/views/mes/qc/iqc/index.vue
@@ -2,11 +2,11 @@
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesQcIqcApi } from '#/api/mes/qc/iqc';
 
-import { onMounted } from 'vue';
+import { onMounted, ref } from 'vue';
 import { useRoute } from 'vue-router';
 
 import { Page, useVbenModal } from '@vben/common-ui';
-import { MesQcStatusEnum } from '@vben/constants';
+import { MesQcStatusEnum, MesQcTypeEnum } from '@vben/constants';
 
 import { Button, message } from 'ant-design-vue';
 
@@ -14,6 +14,7 @@
 import { deleteIqc, exportIqc, getIqcPage } from '#/api/mes/qc/iqc';
 import { $t } from '#/locales';
 import QcExportRangeModal from '#/views/mes/qc/components/export-range-modal.vue';
+import QcReportPrint from '#/views/mes/qc/components/qc-report-print.vue';
 
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
@@ -21,6 +22,7 @@
 defineOptions({ name: 'MesQcIqc' });
 
 const route = useRoute();
+const printRef = ref<InstanceType<typeof QcReportPrint> | null>(null);
 
 const [FormModal, formModalApi] = useVbenModal({
   connectedComponent: Form,
@@ -65,6 +67,11 @@
   } finally {
     hideLoading();
   }
+}
+
+/** 鎵撳嵃妫�楠屾姤鍛� */
+async function handlePrint(row: MesQcIqcApi.Iqc) {
+  await printRef.value?.print(row.id!, MesQcTypeEnum.IQC);
 }
 
 /** 瀵煎嚭琛ㄦ牸锛堝脊绐楅�夋楠屾椂闂磋寖鍥达級 */
@@ -120,6 +127,7 @@
   <Page auto-content-height>
     <FormModal @success="handleRefresh" />
     <ExportRangeModal />
+    <QcReportPrint ref="printRef" />
     <Grid table-title="鏉ユ枡妫�楠屽崟鍒楄〃">
       <template #toolbar-tools>
         <TableAction
@@ -170,6 +178,13 @@
               },
             },
             {
+              label: '鎵撳嵃鎶ュ憡',
+              type: 'link',
+              icon: 'ant-design:printer-outlined',
+              auth: ['mes:qc-iqc:query'],
+              onClick: handlePrint.bind(null, row),
+            },
+            {
               label: $t('common.detail'),
               type: 'link',
               icon: ACTION_ICON.VIEW,
diff --git a/src/views/mes/qc/oqc/data.ts b/src/views/mes/qc/oqc/data.ts
index 54b6766..c7d0af2 100644
--- a/src/views/mes/qc/oqc/data.ts
+++ b/src/views/mes/qc/oqc/data.ts
@@ -300,6 +300,57 @@
       rules: 'required',
     },
     {
+      fieldName: 'samplingLocation',
+      label: '閲囨牱鍦扮偣',
+      component: 'Input',
+      componentProps: {
+        maxlength: 100,
+        placeholder: '璇疯緭鍏ラ噰鏍峰湴鐐�',
+      },
+    },
+    {
+      fieldName: 'certificateNo',
+      label: '璇佷功缂栧彿',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '璇疯緭鍏ヨ瘉涔︾紪鍙�',
+      },
+    },
+    {
+      fieldName: 'executeStandard',
+      label: '鎵ц鏍囧噯',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '濡� GB/T 6027锛岄�夋嫨璐ㄦ鏂规鍚庤嚜鍔ㄥ甫鍏�',
+      },
+    },
+    {
+      fieldName: 'auditUserId',
+      label: '澶嶆牳浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: getSimpleUserList,
+        labelField: 'nickname',
+        placeholder: '璇烽�夋嫨澶嶆牳浜�',
+        valueField: 'id',
+      },
+    },
+    {
+      fieldName: 'approveUserId',
+      label: '瀹℃牳浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: getSimpleUserList,
+        labelField: 'nickname',
+        placeholder: '璇烽�夋嫨瀹℃牳浜�',
+        valueField: 'id',
+      },
+    },
+    {
       fieldName: 'checkResult',
       label: '妫�娴嬬粨鏋�',
       component: 'Select',
diff --git a/src/views/mes/qc/oqc/index.vue b/src/views/mes/qc/oqc/index.vue
index f9043b1..c687183 100644
--- a/src/views/mes/qc/oqc/index.vue
+++ b/src/views/mes/qc/oqc/index.vue
@@ -2,8 +2,10 @@
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesQcOqcApi } from '#/api/mes/qc/oqc';
 
+import { ref } from 'vue';
+
 import { Page, useVbenModal } from '@vben/common-ui';
-import { MesQcStatusEnum } from '@vben/constants';
+import { MesQcStatusEnum, MesQcTypeEnum } from '@vben/constants';
 
 import { Button, message } from 'ant-design-vue';
 
@@ -11,6 +13,7 @@
 import { deleteOqc, exportOqc, getOqcPage } from '#/api/mes/qc/oqc';
 import { $t } from '#/locales';
 import QcExportRangeModal from '#/views/mes/qc/components/export-range-modal.vue';
+import QcReportPrint from '#/views/mes/qc/components/qc-report-print.vue';
 
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
@@ -25,9 +28,16 @@
   destroyOnClose: true,
 });
 
+const printRef = ref<InstanceType<typeof QcReportPrint> | null>(null);
+
 /** 鍒锋柊琛ㄦ牸 */
 function handleRefresh() {
   gridApi.query();
+}
+
+/** 鎵撳嵃妫�楠屾姤鍛� */
+async function handlePrint(row: MesQcOqcApi.Oqc) {
+  await printRef.value?.print(row.id!, MesQcTypeEnum.OQC);
 }
 
 /** 鍒涘缓鍑鸿揣妫�楠屽崟 */
@@ -106,6 +116,7 @@
   <Page auto-content-height>
     <FormModal @success="handleRefresh" />
     <ExportRangeModal />
+    <QcReportPrint ref="printRef" />
     <Grid table-title="鍑鸿揣妫�楠屽崟鍒楄〃">
       <template #toolbar-tools>
         <TableAction
@@ -156,6 +167,13 @@
               },
             },
             {
+              label: '鎵撳嵃鎶ュ憡',
+              type: 'link',
+              icon: 'ant-design:printer-outlined',
+              auth: ['mes:qc-oqc:query'],
+              onClick: handlePrint.bind(null, row),
+            },
+            {
               label: $t('common.detail'),
               type: 'link',
               icon: ACTION_ICON.VIEW,
diff --git a/src/views/mes/qc/rqc/data.ts b/src/views/mes/qc/rqc/data.ts
index ab9af37..be672b5 100644
--- a/src/views/mes/qc/rqc/data.ts
+++ b/src/views/mes/qc/rqc/data.ts
@@ -267,6 +267,57 @@
       rules: 'selectRequired',
     },
     {
+      fieldName: 'samplingLocation',
+      label: '閲囨牱鍦扮偣',
+      component: 'Input',
+      componentProps: {
+        maxlength: 100,
+        placeholder: '璇疯緭鍏ラ噰鏍峰湴鐐�',
+      },
+    },
+    {
+      fieldName: 'certificateNo',
+      label: '璇佷功缂栧彿',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '璇疯緭鍏ヨ瘉涔︾紪鍙�',
+      },
+    },
+    {
+      fieldName: 'executeStandard',
+      label: '鎵ц鏍囧噯',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '濡� GB/T 6027锛岄�夋嫨璐ㄦ鏂规鍚庤嚜鍔ㄥ甫鍏�',
+      },
+    },
+    {
+      fieldName: 'auditUserId',
+      label: '澶嶆牳浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: getSimpleUserList,
+        labelField: 'nickname',
+        placeholder: '璇烽�夋嫨澶嶆牳浜�',
+        valueField: 'id',
+      },
+    },
+    {
+      fieldName: 'approveUserId',
+      label: '瀹℃牳浜�',
+      component: 'ApiSelect',
+      componentProps: {
+        allowClear: true,
+        api: getSimpleUserList,
+        labelField: 'nickname',
+        placeholder: '璇烽�夋嫨瀹℃牳浜�',
+        valueField: 'id',
+      },
+    },
+    {
       fieldName: 'checkResult',
       label: '妫�娴嬬粨鏋�',
       component: 'Select',
diff --git a/src/views/mes/qc/rqc/index.vue b/src/views/mes/qc/rqc/index.vue
index 2771b4c..bc1ea4e 100644
--- a/src/views/mes/qc/rqc/index.vue
+++ b/src/views/mes/qc/rqc/index.vue
@@ -2,8 +2,10 @@
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { MesQcRqcApi } from '#/api/mes/qc/rqc';
 
+import { ref } from 'vue';
+
 import { Page, useVbenModal } from '@vben/common-ui';
-import { MesQcStatusEnum } from '@vben/constants';
+import { MesQcStatusEnum, MesQcTypeEnum } from '@vben/constants';
 
 import { Button, message } from 'ant-design-vue';
 
@@ -11,6 +13,7 @@
 import { deleteRqc, exportRqc, getRqcPage } from '#/api/mes/qc/rqc';
 import { $t } from '#/locales';
 import QcExportRangeModal from '#/views/mes/qc/components/export-range-modal.vue';
+import QcReportPrint from '#/views/mes/qc/components/qc-report-print.vue';
 
 import { useGridColumns, useGridFormSchema } from './data';
 import Form from './modules/form.vue';
@@ -25,9 +28,16 @@
   destroyOnClose: true,
 });
 
+const printRef = ref<InstanceType<typeof QcReportPrint> | null>(null);
+
 /** 鍒锋柊琛ㄦ牸 */
 function handleRefresh() {
   gridApi.query();
+}
+
+/** 鎵撳嵃妫�楠屾姤鍛� */
+async function handlePrint(row: MesQcRqcApi.Rqc) {
+  await printRef.value?.print(row.id!, MesQcTypeEnum.RQC);
 }
 
 /** 鍒涘缓閫�璐ф楠屽崟 */
@@ -106,6 +116,7 @@
   <Page auto-content-height>
     <FormModal @success="handleRefresh" />
     <ExportRangeModal />
+    <QcReportPrint ref="printRef" />
     <Grid table-title="閫�璐ф楠屽崟鍒楄〃">
       <template #toolbar-tools>
         <TableAction
@@ -156,6 +167,13 @@
               },
             },
             {
+              label: '鎵撳嵃鎶ュ憡',
+              type: 'link',
+              icon: 'ant-design:printer-outlined',
+              auth: ['mes:qc-rqc:query'],
+              onClick: handlePrint.bind(null, row),
+            },
+            {
               label: $t('common.detail'),
               type: 'link',
               icon: ACTION_ICON.VIEW,
diff --git a/src/views/mes/qc/template/data.ts b/src/views/mes/qc/template/data.ts
index 2403139..0d3f941 100644
--- a/src/views/mes/qc/template/data.ts
+++ b/src/views/mes/qc/template/data.ts
@@ -91,6 +91,15 @@
       rules: z.array(z.number()).min(1, '妫�娴嬬绫讳笉鑳戒负绌�'),
     },
     {
+      fieldName: 'defaultExecuteStandard',
+      label: '榛樿鎵ц鏍囧噯',
+      component: 'Input',
+      componentProps: {
+        maxlength: 50,
+        placeholder: '濡� GB/T 6027锛屾柊寤烘楠屽崟閫夋嫨鏈柟妗堝悗鑷姩甯﹀叆鎵ц鏍囧噯',
+      },
+    },
+    {
       fieldName: 'remark',
       label: '澶囨敞',
       component: 'Textarea',
@@ -249,6 +258,17 @@
       width: 100,
     },
     {
+      field: 'sortOrder',
+      title: '鎺掑簭鍙�',
+      width: 80,
+    },
+    {
+      field: 'judgeFlag',
+      title: '鍙備笌鍒ゅ畾',
+      width: 90,
+      slots: { default: 'judgeFlag' },
+    },
+    {
       title: '鎿嶄綔',
       width: 130,
       fixed: 'right',
@@ -336,6 +356,29 @@
       },
     },
     {
+      fieldName: 'sortOrder',
+      label: '鎺掑簭鍙�',
+      component: 'InputNumber',
+      defaultValue: 0,
+      componentProps: {
+        class: '!w-full',
+        min: 0,
+        precision: 0,
+        placeholder: '鏂规鍐呭睍绀洪『搴忥紝灏忕殑鍦ㄥ墠',
+      },
+    },
+    {
+      fieldName: 'judgeFlag',
+      label: '鍙備笌鍒ゅ畾',
+      component: 'Switch',
+      defaultValue: true,
+      componentProps: {
+        checkedChildren: '鏄�',
+        unCheckedChildren: '鍚�',
+      },
+      help: '鍒嗙粍琛�/涓棿鍙傛暟琛岃涓哄惁锛屼粎鏈�缁堢粨鏋滈」鍙備笌鍚堟牸鍒ゅ畾鎻愮ず',
+    },
+    {
       fieldName: 'remark',
       label: '澶囨敞',
       component: 'Textarea',
diff --git a/src/views/mes/qc/template/modules/indicator-list.vue b/src/views/mes/qc/template/modules/indicator-list.vue
index 3b9790a..6ad5681 100644
--- a/src/views/mes/qc/template/modules/indicator-list.vue
+++ b/src/views/mes/qc/template/modules/indicator-list.vue
@@ -4,12 +4,13 @@
 
 import { useVbenModal } from '@vben/common-ui';
 
-import { message } from 'ant-design-vue';
+import { message, Switch } from 'ant-design-vue';
 
 import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
 import {
   deleteTemplateIndicator,
   getTemplateIndicatorPage,
+  updateTemplateIndicator,
 } from '#/api/mes/qc/template/indicator';
 import { $t } from '#/locales';
 
@@ -39,6 +40,16 @@
 /** 缂栬緫鎸囨爣椤� */
 function handleEdit(row: MesQcTemplateIndicatorApi.TemplateIndicator) {
   formModalApi.setData({ ...row, templateId: props.templateId }).open();
+}
+
+/** 鍒囨崲鏄惁鍙備笌鍒ゅ畾 */
+async function handleJudgeFlagChange(
+  row: MesQcTemplateIndicatorApi.TemplateIndicator,
+  checked: boolean,
+) {
+  await updateTemplateIndicator({ ...row, judgeFlag: checked });
+  message.success(`妫�娴嬮」[${row.indicatorName}]宸�${checked ? '鍙備笌' : '涓嶅弬涓�'}鍒ゅ畾`);
+  handleRefresh();
 }
 
 /** 鍒犻櫎鎸囨爣椤� */
@@ -100,6 +111,17 @@
           ]"
         />
       </template>
+      <template #judgeFlag="{ row }">
+        <Switch
+          :checked="row.judgeFlag !== false"
+          :disabled="readonly"
+          checked-children="鏄�"
+          un-checked-children="鍚�"
+          @change="
+            (checked: boolean) => handleJudgeFlagChange(row, checked)
+          "
+        />
+      </template>
       <template #actions="{ row }">
         <TableAction
           :actions="[

--
Gitblit v1.9.3