Bläddra i källkod

新增打印接口

695593266@qq.com 1 vecka sedan
förälder
incheckning
a40d8a33c3

+ 11 - 0
src/api/checklistrecord/index.js

@@ -22,6 +22,17 @@ export async function checklistByWorkOrderId(workOrderId) {
   return Promise.reject(new Error(res.data.message));
 }
 
+/**
+ * 放行单打印前查询
+ */
+export async function checklistrecordQueryPrint(ids) {
+  const res = await request.post('/mes/checklistrecord/queryPrint', ids);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
 // /mes/checklistrecord/save 保存
 export async function checklistrecordSave(data) {
   const res = await request.post('/mes/checklistrecord/save', data);

+ 9 - 0
src/api/producetaskrulerecord/index.js

@@ -45,6 +45,15 @@ export async function producetaskrulerecordPage(body) {
   return Promise.reject(new Error(res.data.message));
 }
 
+// 生产记录打印前查询 /mes/producetaskrulerecord/queryPrint
+export async function queryPrint(body) {
+  const res = await request.post('/mes/producetaskrulerecord/queryPrint', body);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
 // 新增或编辑,临时配置事项,不派单
 export async function tempSaveOrUpdate(body) {
   const res = await request.post(

+ 11 - 0
src/api/unacceptedProduct/index.js

@@ -12,6 +12,17 @@ export async function getList(data) {
   return Promise.reject(new Error(res.data.message));
 }
 
+/**
+ * 不合格品打印前查询
+ */
+export async function queryPrint(body) {
+  const res = await request.post('/qms/unqualifiedproducts/queryPrint', body);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
 /**
  * 不合格品台账列表详情
  */

+ 197 - 35
src/views/batchRecord/components/tables/batchRecordTable.vue

@@ -46,7 +46,10 @@
 <script>
   import dictMixins from '@/mixins/dictMixins';
   import tableColumnsMixin from '@/mixins/tableColumnsMixin';
-  import { producetaskrulerecordPage } from '@/api/producetaskrulerecord/index';
+  import {
+    producetaskrulerecordPage,
+    queryPrint
+  } from '@/api/producetaskrulerecord/index';
   import editModal from '../editModal.vue';
   import batchPecordPrint from './batchPecordPrint.vue';
   import exportButton from '@/components/upload/exportButton.vue';
@@ -185,11 +188,22 @@
         params: {},
         tableData: [],
         selection: [],
+        printTypeMap: {
+          cleaningRecord: 'CLEANING_RECORD',
+          labelPrintRecord: 'LABEL_PRINT_RECORD',
+          productLabelRecord: 'PRODUCT_LABELING_RECORD',
+          packagingRecord: 'PACKAGING_PROCESS_RECORD',
+          processInspectionRecord: 'PROCESS_INSPECTION_RECORD'
+        },
         printOptions: [
           { key: 'cleaningRecord', label: '清场清洁记录表', code: 'SC-033' },
           { key: 'labelPrintRecord', label: '标签打印记录', code: 'SC-102' },
           { key: 'productLabelRecord', label: '产品贴标记录', code: 'SC-050' },
-          { key: 'packagingRecord', label: '产品中外包装工序记录', code: 'SC-019' },
+          {
+            key: 'packagingRecord',
+            label: '产品中外包装工序记录',
+            code: 'SC-019'
+          },
           { key: 'processInspectionRecord', label: '过程检验记录', code: 'A0' }
         ]
       };
@@ -277,45 +291,193 @@
       openPrint(row) {
         this.$refs.batchPecordPrintRef.open(row);
       },
-      handlePrint(key) {
+      async handlePrint(key) {
         if (!this.selection.length) {
           this.$message.warning('请先勾选要打印的生产记录');
           return;
         }
-        const r = this.selection[0];
-        const today = this.$util?.toDateString
-          ? this.$util.toDateString(new Date(), 'yyyy-MM-dd')
-          : new Date().toISOString().slice(0, 10);
-        const data = {
-          batchNo: this.tableQuery.batchNo,
-          productCode: this.tableQuery.productCode,
-          productName: r.productName || '',
-          specification: r.specification || '',
-          processOrderCode: r.workOrderCode || '',
-          processOrderNo: r.workOrderCode || '',
-          moCode: r.workOrderCode || '',
-          code: r.code || '',
-          recorder: r.createUserName || '',
-          checker: r.checkerName || '',
-          reviewer: r.reviewerName || '',
-          inspector: r.inspectorName || '',
-          operator: r.createUserName || '',
-          date: r.createTime || today,
-          createDate: r.createTime || today,
-          operateYear: today.slice(0, 4),
-          operateMonth: today.slice(5, 7),
-          operateDay: today.slice(8, 10),
-          startHour: '08',
-          startMinute: '00',
-          endHour: '17',
-          endMinute: '30',
-          equipmentCode: r.equipmentCode || '',
-          equipmentName: r.equipmentName || '',
-          remark: r.remark || ''
+        const printType = this.printTypeMap[key];
+        if (!printType) {
+          this.$message.warning('暂不支持该打印单据');
+          return;
+        }
+        try {
+          const ids = this.selection.map((item) => item.id).filter(Boolean);
+          if (!ids.length) {
+            this.$message.warning('未获取到可打印数据的ID');
+            return;
+          }
+          const res = await queryPrint({ ids, printType });
+          const data = this.buildPrintData(key, res);
+          if (!data) {
+            this.$message.warning('未查询到可打印的生产记录数据');
+            return;
+          }
+          if (this.$refs[key]) {
+            this.$refs[key].open(data);
+          }
+        } catch (error) {
+          this.$message.error(error.message || '查询打印数据失败');
+        }
+      },
+      buildPrintData(key, res) {
+        const list = this.getPrintList(key, res);
+        const first = list[0];
+        if (!first) {
+          return null;
+        }
+        const fallback = this.selection[0] || {};
+        const today = this.formatPrintDate(new Date());
+        const base = this.buildBasePrintData(first, fallback, today);
+
+        if (key == 'cleaningRecord') {
+          return {
+            ...base,
+            area: first.workshopArea || fallback.workshopArea || '',
+            processName: first.processName || fallback.ruleName || '',
+            productModel: first.productModel || fallback.productModel || '',
+            completionTime:
+              first.cleaningFinishTime ||
+              fallback.createTime ||
+              `${today} 00:00`,
+            checkItems: this.buildCleaningDetails(first.cleaningDetails)
+          };
+        }
+
+        if (key == 'labelPrintRecord') {
+          return {
+            ...base,
+            productionDate: this.formatPrintDate(first.productionDate),
+            expiryDate: this.formatPrintDate(first.expiryDate),
+            printTargets: this.uniqueList(list.map((item) => item.printTarget)),
+            specs: this.uniqueList(list.map((item) => item.specification)),
+            records: list.map((item) => ({
+              ...item,
+              productModel: item.productModel || '',
+              printQuantity: item.printQuantity || ''
+            }))
+          };
+        }
+
+        if (key == 'productLabelRecord') {
+          const operateDate = this.formatPrintDate(
+            first.operateTime ||
+              first.createTime ||
+              fallback.createTime ||
+              today
+          );
+          return {
+            ...base,
+            specification: first.specModel || first.specification || '',
+            productQuantity: first.productQuantity || '',
+            equipmentCode: first.deviceCode || fallback.equipmentCode || '',
+            equipmentName: first.deviceName || fallback.equipmentName || '',
+            operateYear: operateDate.slice(0, 4),
+            operateMonth: operateDate.slice(5, 7),
+            operateDay: operateDate.slice(8, 10),
+            startHour: '08',
+            startMinute: '00',
+            endHour: '17',
+            endMinute: '30'
+          };
+        }
+
+        if (key == 'packagingRecord') {
+          return {
+            ...base,
+            batchNo: first.produceBatch || base.batchNo,
+            specification: first.specModel || first.specification || '',
+            batchQuantity: first.quantity || '',
+            startTime:
+              first.startTime || fallback.createTime || `${today} 08:00`,
+            endTime: first.endTime || fallback.updateTime || `${today} 17:30`
+          };
+        }
+
+        if (key == 'processInspectionRecord') {
+          return {
+            ...base,
+            batchNo: first.produceBatch || base.batchNo,
+            productionDate: this.formatPrintDate(first.productionDate),
+            specification: first.modelSpec || first.specification || ''
+          };
+        }
+
+        return base;
+      },
+      getPrintList(key, res) {
+        const listMap = {
+          cleaningRecord: 'cleaningRecordList',
+          labelPrintRecord: 'labelPrintRecordList',
+          productLabelRecord: 'productLabelingRecordList',
+          packagingRecord: 'packagingProcessRecordList',
+          processInspectionRecord: 'processInspectionRecordList'
         };
-        if (this.$refs[key]) {
-          this.$refs[key].open(data);
+        const listKey = listMap[key];
+        if (Array.isArray(res?.[listKey])) {
+          return res[listKey];
+        }
+        if (Array.isArray(res)) {
+          return res;
+        }
+        return [];
+      },
+      buildBasePrintData(row, fallback, today) {
+        return {
+          ...row,
+          batchNo:
+            row.batchNo || row.produceBatch || this.tableQuery.batchNo || '',
+          productCode:
+            row.productCode ||
+            this.tableQuery.productCode ||
+            fallback.productCode ||
+            '',
+          productName: row.productName || fallback.productName || '',
+          specification:
+            row.specification ||
+            row.specModel ||
+            row.modelSpec ||
+            fallback.specification ||
+            '',
+          processOrderCode: row.workOrderCode || fallback.workOrderCode || '',
+          processOrderNo: row.workOrderCode || fallback.workOrderCode || '',
+          moCode: row.workOrderCode || fallback.workOrderCode || '',
+          code: row.code || fallback.code || '',
+          recorder: row.createUserName || fallback.createUserName || '',
+          checker: row.checkerName || fallback.checkerName || '',
+          reviewer: row.reviewerName || fallback.reviewerName || '',
+          inspector: row.inspectorName || fallback.inspectorName || '',
+          operator: row.createUserName || fallback.createUserName || '',
+          date: row.createTime || fallback.createTime || today,
+          createDate: row.createTime || fallback.createTime || today,
+          remark: row.remark || fallback.remark || ''
+        };
+      },
+      buildCleaningDetails(details) {
+        const list = Array.isArray(details) ? details : [];
+        return list.map((item) => ({
+          ...item,
+          name: item.cleaningItem || '',
+          cleaner: item.cleaningPerson || '',
+          abnormalDesc: item.errorMsg || '',
+          cleaningStatus: item.cleaningStatus || '',
+          checkResult: item.checkResult || ''
+        }));
+      },
+      uniqueList(list) {
+        return [...new Set((list || []).filter(Boolean))];
+      },
+      formatPrintDate(value) {
+        if (!value) {
+          return '';
+        }
+        if (typeof value == 'string') {
+          return value.slice(0, 10);
+        }
+        if (this.$util?.toDateString) {
+          return this.$util.toDateString(value, 'yyyy-MM-dd');
         }
+        return new Date(value).toISOString().slice(0, 10);
       }
     }
   };

+ 124 - 39
src/views/batchRecord/components/tables/pendingBatchRecordTable.vue

@@ -29,13 +29,20 @@
   import printSelector from '../printSelector.vue';
   import unqualifiedProductReview from '../../print/electrodeBatchRecord/unqualifiedProductReview.vue';
   import productReleaseApproval from '../../print/electrodeBatchRecord/productReleaseApproval.vue';
-  import { checklistrecordPage } from '@/api/checklistrecord/index';
+  import {
+    checklistrecordPage,
+    checklistrecordQueryPrint
+  } from '@/api/checklistrecord/index';
   import { samplingRecordsPage } from '@/api/samplingRecords';
-  import { getList as unacceptedProductPage } from '@/api/unacceptedProduct/index';
+  import {
+    getList as unacceptedProductPage,
+    queryPrint as queryUnacceptedProductPrint
+  } from '@/api/unacceptedProduct/index';
   import { getByCode } from '@/api/system/dictionary-data';
   import { reviewStatus } from '@/enum/dict';
   import { recordingMethodList } from '@/utils/util.js';
   import dictMixins from '@/mixins/dictMixins';
+  import { buildReleaseOrderPrintData } from '../../utils/releaseOrderPrint';
 
   export default {
     name: 'pendingBatchRecordTable',
@@ -649,57 +656,135 @@
       search(where) {
         this.reload(where);
       },
-      handlePrint(key) {
+      async handlePrint(key) {
         if (!this.selection.length) {
           this.$message.warning('请先勾选要打印的数据');
           return;
         }
 
-        const row = this.selection[0] || {};
         if (key === 'unqualifiedProductReview') {
-          this.$refs.unqualifiedProductReviewRef.open(row);
+          await this.openUnqualifiedProductPrint();
           return;
         }
         if (key === 'productReleaseApproval') {
-          this.$refs.productReleaseApproval.open(
-            this.buildReleaseOrderPrintData(row)
-          );
+          await this.openReleaseOrderPrint();
         }
       },
-      buildReleaseOrderPrintData(row) {
-        const firstOrder = this.getFirstOrder(row);
+      async openReleaseOrderPrint() {
+        try {
+          const ids = this.selection.map((item) => item.id).filter(Boolean);
+          if (!ids.length) {
+            this.$message.warning('未获取到可打印数据的ID');
+            return;
+          }
+          const res = await checklistrecordQueryPrint(ids);
+          const data = buildReleaseOrderPrintData(res, this.selection);
+          if (!data) {
+            this.$message.warning('未查询到可打印的放行单数据');
+            return;
+          }
+          this.$refs.productReleaseApproval.open(data);
+        } catch (error) {
+          this.$message.error(error.message || '查询打印数据失败');
+        }
+      },
+      async openUnqualifiedProductPrint() {
+        try {
+          const ids = this.selection.map((item) => item.id).filter(Boolean);
+          if (!ids.length) {
+            this.$message.warning('未获取到可打印数据的ID');
+            return;
+          }
+          const res = await queryUnacceptedProductPrint({ ids });
+          const data = this.buildUnqualifiedProductPrintData(res);
+          if (!data) {
+            this.$message.warning('未查询到可打印的不良品数据');
+            return;
+          }
+          this.$refs.unqualifiedProductReviewRef.open(data);
+        } catch (error) {
+          this.$message.error(error.message || '查询打印数据失败');
+        }
+      },
+      buildUnqualifiedProductPrintData(res) {
+        const list = Array.isArray(res) ? res : [];
+        if (!list.length) {
+          return null;
+        }
+        return list.map((item, index) =>
+          this.buildUnqualifiedProductPrintItem(
+            item,
+            this.getSelectedUnqualifiedProduct(item, index)
+          )
+        );
+      },
+      getSelectedUnqualifiedProduct(item = {}, index) {
+        return (
+          this.selection.find(
+            (row) =>
+              (item.id && row.id == item.id) ||
+              (item.unqualifiedProductsCode &&
+                row.unqualifiedProductsCode == item.unqualifiedProductsCode)
+          ) ||
+          this.selection[index] ||
+          this.selection[0] ||
+          {}
+        );
+      },
+      buildUnqualifiedProductPrintItem(item, selected) {
+        const first = item || {};
+        const specification = this.joinText([
+          this.getValue(first.specification, selected.specification),
+          this.getValue(first.modelType, selected.modelType)
+        ]);
+
         return {
-          ...row,
-          productCode:
-            row.productCode || this.getOrderField(row, 'productCode'),
-          productName:
-            row.productName || this.getOrderField(row, 'productName'),
-          specification:
-            row.specification || this.getOrderField(row, 'specification'),
-          productModel:
-            row.productModel || this.getOrderField(row, 'productModel'),
-          batchNo: row.batchNo || this.getOrderField(row, 'batchNo'),
-          quantity:
-            row.quantity ||
-            row.formedNum ||
-            firstOrder.formedNum ||
-            firstOrder.formingNum ||
-            this.getOrderField(row, 'formedNum') ||
-            this.getOrderField(row, 'formingNum'),
-          sterilizationBatchNo:
-            row.sterilizationBatchNo ||
-            row.sterileBatchNo ||
-            firstOrder.sterilizationBatchNo ||
-            firstOrder.sterileBatchNo ||
-            '',
-          inspectionCode:
-            row.inspectionCode ||
-            row.inspectionNo ||
-            firstOrder.inspectionCode ||
-            firstOrder.inspectionNo ||
-            ''
+          ...selected,
+          ...first,
+          disposeNo: this.getValue(
+            first.disposeNo,
+            selected.disposeNo,
+            first.unqualifiedProductsCode,
+            selected.unqualifiedProductsCode
+          ),
+          categoryName: this.getValue(first.categoryName, selected.categoryName),
+          specification,
+          modelType: this.getValue(first.modelType, selected.modelType),
+          batchNo: this.getValue(first.batchNo, selected.batchNo),
+          quantity: this.getValue(first.quantity, selected.quantity),
+          measureUnit: this.getValue(first.measureUnit, selected.measureUnit),
+          unqualifiedProductsCode: this.getValue(
+            first.unqualifiedProductsCode,
+            selected.unqualifiedProductsCode
+          ),
+          unqualifiedDescription:
+            this.getValue(
+              first.unqualifiedReason,
+              selected.unqualifiedDescription,
+              selected.unqualifiedReason
+            ),
+          unqualifiedReason: this.getValue(
+            first.unqualifiedReason,
+            selected.unqualifiedReason
+          ),
+          brandNum: this.getValue(first.brandNum, selected.brandNum)
         };
       },
+      joinText(list) {
+        return [
+          ...new Set(
+            (list || []).filter(
+              (item) => item !== undefined && item !== null && item !== ''
+            )
+          )
+        ].join('/');
+      },
+      getValue(...values) {
+        const value = values.find(
+          (item) => item !== undefined && item !== null && item !== ''
+        );
+        return value === undefined ? '' : value;
+      },
       getFirstOrder(row) {
         return Array.isArray(row.orders) && row.orders.length
           ? row.orders[0]

+ 54 - 0
src/views/batchRecord/components/tables/workOrderTable.vue

@@ -45,6 +45,10 @@
   import dictMixins from '@/mixins/dictMixins';
   import tableColumnsMixin from '@/mixins/tableColumnsMixin';
   import { batchRecordPage, queryWorkOrderPrint } from '@/api/workOrderList';
+  import {
+    checklistByWorkOrderId,
+    checklistrecordQueryPrint
+  } from '@/api/checklistrecord/index';
   import detailsPop from '@/views/produceOrder/components/details/index.vue';
   import { getById } from '@/api/produceOrder/index';
   import { getAllProduceTaskByUsing } from '@/api/InTheSystem/index';
@@ -54,6 +58,7 @@
   import productionOrder from '../../print/electrodeBatchRecord/productionOrder.vue';
   import materialBalance from '../../print/electrodeBatchRecord/materialBalance.vue';
   import productReleaseApproval from '../../print/electrodeBatchRecord/productReleaseApproval.vue';
+  import { buildReleaseOrderPrintData } from '../../utils/releaseOrderPrint';
 
   export default {
     mixins: [dictMixins, tableColumnsMixin],
@@ -315,6 +320,10 @@
           return;
         }
         try {
+          if (key === 'productReleaseApproval') {
+            await this.openReleaseOrderPrint();
+            return;
+          }
           const ids = this.selection.map((item) => item.id).filter(Boolean);
           const res = await queryWorkOrderPrint({ ids, printType });
           const data = this.buildPrintData(key, res);
@@ -329,6 +338,51 @@
           this.$message.error(error.message || '查询打印数据失败');
         }
       },
+      async openReleaseOrderPrint() {
+        const releaseOrders = await this.getReleaseOrdersByWorkOrders();
+        const ids = [
+          ...new Set(releaseOrders.map((item) => item.id).filter(Boolean))
+        ];
+        if (!ids.length) {
+          this.$message.warning('未查询到所选工单关联的放行单');
+          return;
+        }
+        const res = await checklistrecordQueryPrint(ids);
+        const data = buildReleaseOrderPrintData(res, releaseOrders);
+        if (!data) {
+          this.$message.warning('未查询到可打印的放行单数据');
+          return;
+        }
+        this.$refs.productReleaseApproval.open(data);
+      },
+      async getReleaseOrdersByWorkOrders() {
+        const rows = this.selection.filter((item) => item.id);
+        const result = await Promise.all(
+          rows.map((item) => checklistByWorkOrderId(item.id))
+        );
+        const releaseOrders = result.flatMap((item) =>
+          this.getReleaseOrderList(item)
+        );
+        const map = new Map();
+        releaseOrders.forEach((item) => {
+          if (item && item.id && !map.has(item.id)) {
+            map.set(item.id, item);
+          }
+        });
+        return [...map.values()];
+      },
+      getReleaseOrderList(data) {
+        if (Array.isArray(data)) {
+          return data;
+        }
+        if (Array.isArray(data?.list)) {
+          return data.list;
+        }
+        if (Array.isArray(data?.records)) {
+          return data.records;
+        }
+        return data ? [data] : [];
+      },
       buildPrintData(key, res) {
         const map = {
           batchRecordCover: 'batchRecordCoverList',

+ 7 - 2
src/views/batchRecord/print/electrodeBatchRecord/cleaningRecord.vue

@@ -103,7 +103,7 @@
       return {
         visible: false,
         form: {},
-        checkItems: [
+        defaultCheckItems: [
           { name: '顶棚清洁干净', cleaner: '', abnormalDesc: '' },
           { name: '墙面清洁干净', cleaner: '', abnormalDesc: '' },
           { name: '出风口清洁干净', cleaner: '', abnormalDesc: '' },
@@ -117,7 +117,8 @@
           { name: '批生产记录按规定收集、送交', cleaner: '', abnormalDesc: '' },
           { name: '与上批生产的容器标识已清除或更换', cleaner: '', abnormalDesc: '' },
           { name: '需销毁的物资按规定清除出生产区', cleaner: '', abnormalDesc: '' }
-        ]
+        ],
+        checkItems: []
       };
     },
     computed: {
@@ -145,6 +146,10 @@
     methods: {
       open(data) {
         this.form = data || {};
+        this.checkItems =
+          Array.isArray(this.form.checkItems) && this.form.checkItems.length
+            ? this.form.checkItems
+            : this.defaultCheckItems.map((item) => ({ ...item }));
         this.visible = true;
       },
       print() {

+ 13 - 3
src/views/batchRecord/print/electrodeBatchRecord/productReleaseApproval.vue

@@ -1,7 +1,11 @@
 <template>
   <ele-modal title="成品放行审批单 ZL-065" :visible.sync="visible" v-if="visible" width="80%" :maxable="true">
     <div id="printSection_productReleaseApproval">
-      <div class="report-container">
+      <div
+        class="report-container"
+        v-for="(form, index) in formList"
+        :key="index"
+      >
         <div class="report-header">
           <div class="header-left">
             <img src="" alt="特瑞精密医疗" class="logo" />
@@ -174,12 +178,14 @@
     data() {
       return {
         visible: false,
-        form: {}
+        form: {},
+        formList: []
       };
     },
     methods: {
       open(data) {
-        this.form = data || {};
+        this.formList = Array.isArray(data) ? data : [data || {}];
+        this.form = this.formList[0] || {};
         this.visible = true;
       },
       print() {
@@ -190,6 +196,7 @@
         win.document.write('<style>');
         win.document.write('body{margin:0;padding:20px;font-family:SimSun,serif;font-size:12px;}');
         win.document.write('.report-container{padding:20px;background:#fff;}');
+        win.document.write('.report-container + .report-container{page-break-before:always;}');
         win.document.write('.report-header{display:flex;align-items:center;justify-content:center;position:relative;margin-bottom:5px;}');
         win.document.write('.header-center{font-size:20px;letter-spacing:3px;}');
         win.document.write('.report-title{text-align:center;font-size:18px;font-weight:bold;margin-bottom:5px;}');
@@ -222,6 +229,9 @@
     background: #fff;
     font-size: 12px;
   }
+  .report-container + .report-container {
+    page-break-before: always;
+  }
   .report-header {
     display: flex;
     align-items: center;

+ 45 - 15
src/views/batchRecord/print/electrodeBatchRecord/unqualifiedProductReview.vue

@@ -8,6 +8,11 @@
     append-to-body
   >
     <div id="printSection_unqualifiedProductReview">
+      <div
+        v-for="(item, index) in printForms"
+        :key="'uqr_form_' + index"
+        class="uqr-form-group"
+      >
       <div class="uqr-page">
         <div class="crop crop-tl"></div>
         <div class="crop crop-tr"></div>
@@ -53,7 +58,7 @@
             </td>
             <td class="nowrap" colspan="2"
               >处置编号<span class="fill-line">{{
-                field('disposeNo')
+                field('disposeNo', item)
               }}</span></td
             >
           </tr>
@@ -68,10 +73,10 @@
             <td colspan="2">来源</td>
           </tr>
           <tr class="info-row">
-            <td>{{ field('categoryName') }}</td>
-            <td>{{ field('specification') || field('modelType') }}</td>
-            <td>{{ field('batchNo') }}</td>
-            <td>{{ quantityText }}</td>
+            <td>{{ field('categoryName', item) }}</td>
+            <td>{{ field('specification', item) || field('modelType', item) }}</td>
+            <td>{{ field('batchNo', item) }}</td>
+            <td>{{ getQuantityText(item) }}</td>
             <td colspan="2" class="source-cell">
               <span><span class="check">□</span>来料检</span>
               <span><span class="check">□</span>过程检</span>
@@ -89,7 +94,8 @@
                 >不合格描述:(来料不合格的,应描述供应商名称、厂家批号等信息)</div
               >
               <div class="write-area">{{
-                field('unqualifiedDescription') || field('unqualifiedReason')
+                field('unqualifiedDescription', item) ||
+                field('unqualifiedReason', item)
               }}</div>
               <div>
                 是否有其他物料/中间产品/成品受影响(<span class="check">□</span
@@ -144,7 +150,11 @@
             <td>意见</td>
             <td>评审人签字/日期</td>
           </tr>
-          <tr v-for="n in 5" :key="'review_' + n" class="review-row">
+          <tr
+            v-for="n in 5"
+            :key="'review_' + index + '_' + n"
+            class="review-row"
+          >
             <td></td>
             <td></td>
             <td></td>
@@ -297,6 +307,7 @@
         </div>
         <div class="page-number">2 / 2</div>
       </div>
+      </div>
     </div>
     <div slot="footer">
       <el-button @click="print">打印预览</el-button>
@@ -311,26 +322,35 @@
     data() {
       return {
         visible: false,
-        form: {}
+        form: {},
+        formList: []
       };
     },
     computed: {
+      printForms() {
+        return this.formList.length ? this.formList : [{}];
+      },
       quantityText() {
-        const quantity =
-          this.field('quantity') || this.field('unqualifiedQuantity');
-        const unit = this.field('measureUnit') || this.field('unit');
-        return `${quantity || ''}${unit || ''}`;
+        return this.getQuantityText(this.form);
       }
     },
     methods: {
       open(data) {
-        this.form = data || {};
+        this.formList = Array.isArray(data) ? data : data ? [data] : [];
+        this.form = this.formList[0] || {};
         this.visible = true;
       },
-      field(key) {
-        const value = this.form[key];
+      field(key, form = this.form) {
+        const value = (form || {})[key];
         return value === 0 || value ? value : '';
       },
+      getQuantityText(form = this.form) {
+        const quantity = this.field('quantity', form);
+        const finalQuantity =
+          quantity === '' ? this.field('unqualifiedQuantity', form) : quantity;
+        const unit = this.field('measureUnit', form) || this.field('unit', form);
+        return `${finalQuantity === '' ? '' : finalQuantity}${unit || ''}`;
+      },
       print() {
         const el = document.getElementById(
           'printSection_unqualifiedProductReview'
@@ -353,6 +373,8 @@
         return `
           @page{size:A4;margin:0;}
           body{margin:0;background:#fff;font-family:SimSun,serif;color:#000;}
+          .uqr-form-group{page-break-after:always;break-after:page;}
+          .uqr-form-group:last-child{page-break-after:auto;break-after:auto;}
           .uqr-page{width:210mm;height:297mm;margin:0 auto;padding:12mm 17.5mm 10mm;box-sizing:border-box;position:relative;page-break-after:always;background:#fff;font-size:14px;}
           .uqr-page:last-child{page-break-after:auto;}
           .uqr-header{height:27mm;display:flex;align-items:flex-start;justify-content:center;position:relative;padding-top:3.5mm;}
@@ -421,6 +443,14 @@
 </script>
 
 <style scoped>
+  .uqr-form-group {
+    page-break-after: always;
+    break-after: page;
+  }
+  .uqr-form-group:last-child {
+    page-break-after: auto;
+    break-after: auto;
+  }
   .uqr-page {
     width: 210mm;
     height: 297mm;

+ 145 - 0
src/views/batchRecord/utils/releaseOrderPrint.js

@@ -0,0 +1,145 @@
+function hasValue(value) {
+  return value !== undefined && value !== null && value !== '';
+}
+
+function getValue(...values) {
+  const value = values.find(hasValue);
+  return value === undefined ? '' : value;
+}
+
+function joinText(list) {
+  return [
+    ...new Set((list || []).filter((item) => hasValue(item)))
+  ].join('/');
+}
+
+function getFirstOrder(row = {}) {
+  return Array.isArray(row.orders) && row.orders.length ? row.orders[0] : {};
+}
+
+function getOrderField(row = {}, key) {
+  if (hasValue(row[key])) {
+    return row[key];
+  }
+  if (!Array.isArray(row.orders)) {
+    return '';
+  }
+  return row.orders
+    .map((item) => item && item[key])
+    .filter((item) => hasValue(item))
+    .join(', ');
+}
+
+function getSelectedRecord(item = {}, index, selectedList = []) {
+  return (
+    selectedList.find(
+      (row) =>
+        (hasValue(item.id) && row.id == item.id) ||
+        (hasValue(item.checklistRecordId) &&
+          row.id == item.checklistRecordId) ||
+        (hasValue(item.checklistrecordId) &&
+          row.id == item.checklistrecordId) ||
+        (hasValue(item.checklistId) && row.id == item.checklistId) ||
+        (hasValue(item.code) && row.code == item.code)
+    ) ||
+    selectedList[index] ||
+    selectedList[0] ||
+    {}
+  );
+}
+
+function buildReleaseOrderPrintItem(item = {}, selected = {}) {
+  const firstOrder = getFirstOrder(selected);
+  const selectedSpecification = joinText([
+    selected.specification,
+    selected.productModel || selected.modelType
+  ]);
+
+  return {
+    ...selected,
+    ...item,
+    productCode: getValue(
+      item.productCode,
+      selected.productCode,
+      getOrderField(selected, 'productCode')
+    ),
+    productName: getValue(
+      item.productName,
+      selected.productName,
+      getOrderField(selected, 'productName')
+    ),
+    specification: getValue(
+      item.specification,
+      item.specModel,
+      item.specificationModel,
+      selectedSpecification,
+      selected.specification
+    ),
+    productModel: getValue(
+      item.productModel,
+      selected.productModel,
+      firstOrder.productModel,
+      getOrderField(selected, 'productModel')
+    ),
+    batchNo: getValue(
+      item.batchNo,
+      selected.batchNo,
+      firstOrder.batchNo,
+      getOrderField(selected, 'batchNo')
+    ),
+    quantity: getValue(
+      item.quantity,
+      selected.quantity,
+      selected.formedNum,
+      firstOrder.formedNum,
+      firstOrder.formingNum,
+      getOrderField(selected, 'formedNum'),
+      getOrderField(selected, 'formingNum')
+    ),
+    sterilizationBatchNo: getValue(
+      item.sterilizationBatchNo,
+      item.sterileBatchNo,
+      item.sterilizationBatch,
+      selected.sterilizationBatchNo,
+      selected.sterileBatchNo,
+      firstOrder.sterilizationBatchNo,
+      firstOrder.sterileBatchNo,
+      getOrderField(selected, 'sterilizationBatchNo'),
+      getOrderField(selected, 'sterileBatchNo')
+    ),
+    inspectionCode: getValue(
+      item.inspectionNo,
+      item.inspectionCode,
+      selected.inspectionCode,
+      selected.inspectionNo,
+      firstOrder.inspectionCode,
+      firstOrder.inspectionNo
+    ),
+    inspectionNo: getValue(
+      item.inspectionNo,
+      item.inspectionCode,
+      selected.inspectionNo,
+      selected.inspectionCode,
+      firstOrder.inspectionNo,
+      firstOrder.inspectionCode
+    )
+  };
+}
+
+export function buildReleaseOrderPrintDataList(list, selectedList = []) {
+  const records = Array.isArray(list) ? list : [];
+  return records.map((item, index) =>
+    buildReleaseOrderPrintItem(
+      item,
+      getSelectedRecord(item, index, selectedList)
+    )
+  );
+}
+
+export function buildReleaseOrderPrintData(list, selectedList = []) {
+  const records = buildReleaseOrderPrintDataList(list, selectedList);
+  if (!records.length) {
+    return null;
+  }
+  return records.length === 1 ? records[0] : records;
+}