Bläddra i källkod

feat: 发货单多条出库单打印

liujt 2 veckor sedan
förälder
incheckning
054c326aa1

+ 321 - 168
src/views/saleManage/saleOrder/invoice/components/print-template-ht-1.vue

@@ -4,166 +4,168 @@
     :visible.sync="QRvisible"
     v-if="QRvisible"
     width="80%"
+    @close="close"
   >
-    <div
-      id="printSection"
-      style="
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        flex-direction: column;
-      "
-    >
-      <div>
-        <div
-          style="
-            font-size: 20px;
-            font-weight: 800;
-            padding-right: 20px;
-            width: 400px;
-            margin: 0 auto;
-          "
-          >{{ groupName }}出库单</div
-        >
-      </div>
-      <div
-        style="
-          width: 100%;
-          font-size: 12px;
-          display: flex;
-          justify-content: space-between;
-          margin-bottom: 10px;
-          margin-top: 10px;
-        "
-      >
-        <span style="width: 30%">客户:{{ formData.contactName }}</span>
-        <span style="width: 30%">单据编码:{{ formData.docNo }}</span>
-        <span style="width: 30%">单据日期:{{ formData.createTime ? formData.createTime.split(' ')[0] : '' }}</span>
-      </div>
-      <div
-        style="
-          width: 100%;
-          font-size: 12px;
-          display: flex;
-          justify-content: space-between;
-          margin-bottom: 10px;
-        "
-      >
-        <span style="width: 80%">收货人联系方式:{{ formData.linkName }} {{ formData.linkPhone }}</span>
-      </div>
-      <div
-        style="
-          width: 100%;
-          font-size: 12px;
-          display: flex;
-          justify-content: space-between;
-          margin-bottom: 10px;
-        "
-      >
-        <span style="width: 80%">送货地址:{{ formData.receiveAddress }}</span>
-      </div>
-      <table
-        cellspacing="0"
-        border
-        style="
-          width: 100%;
-          table-layout: fixed;
-          word-break: break-all;
-          word-wrap: break-word;
-          font-size: 12px;
-        "
-      >
-        <tbody>
-          <tr align="center">
-            <td style="padding: 5px; width: 4%"> 序号 </td>
-            <!-- <td style="padding: 5px; width: 18%"> 名称 </td> -->
-            <td style="padding: 5px; width: 22%"> 规格型号 </td>
-            <td style="padding: 5px; width: 6%"> 单位 </td>
-            <td style="padding: 5px; width: 8%"> 数量 </td>
-            <td style="padding: 5px; width: 8%"> 颜色 </td>
-            <td style="padding: 5px; width: 8%"> 生产批号 </td>
-            <td style="padding: 5px; width: 10%"> 裁线米段 </td>
-            <td style="padding: 5px; width: 12%"> 仓库 </td>
-          </tr>
-
-          <tr align="center" v-for="(item, index) in formData.productList">
-            <td style="padding: 5px"> {{ index + 1 }} </td>
-            <!-- <td style="padding: 5px"> {{ item.productName }} </td> -->
-            <td style="padding: 5px">
-              <!-- {{ item.specification }}/ -->
-              {{ item.modelType }}
-            </td>
-            <td style="padding: 5px"> {{ item.measuringUnit }}</td>
-            <td style="padding: 5px"> {{ item.totalCount }}</td>
-            <td style="padding: 5px"> {{ item.colorKey }}</td>
-            <td style="padding: 5px"> {{ item.batchNo }}</td>
-            <td style="padding: 5px"> {{ item.cuttingLength }}</td>
-            <td style="padding: 5px"> {{ item.warehouseName }}</td>
-          </tr>
-          <tr align="center">
-            <td style="padding: 5px"> </td>
-            <td style="padding: 5px"> 合计 </td>
-            <td style="padding: 5px">  </td>
-            <td style="padding: 5px">{{ getTotalValue('totalCount', 2) }} </td>
-            <td style="padding: 5px"> </td>
-            <td style="padding: 5px"> </td>
-            <td style="padding: 5px"> </td>
-            <td style="padding: 5px"> </td>
-          </tr>
-        </tbody>
-      </table>
+    <div id="printSectionHt1">
       <div
+        v-for="(rowItem, idx) in formData"
+        :key="rowItem.id || idx"
         style="
-          width: 100%;
-          font-size: 12px;
           display: flex;
-          justify-content: space-between;
-          margin-top: 10px;
+          align-items: center;
+          justify-content: center;
+          flex-direction: column;
         "
       >
-        <div style="flex: 1">
-          <div>制单人:{{ formData.makerName }}</div>
+        <div>
+          <div
+            style="
+              font-size: 20px;
+              font-weight: 800;
+              padding-right: 20px;
+              width: 400px;
+              margin: 0 auto;
+            "
+          >{{ groupName }}出库单</div
+          >
         </div>
-        <div style="flex: 1"> 核对人: </div>
-        <div style="flex: 1">
-          <div>仓库:</div>
+        <div
+          style="
+            width: 100%;
+            font-size: 12px;
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 10px;
+            margin-top: 10px;
+          "
+        >
+          <span style="width: 30%">客户:{{ rowItem.contactName }}</span>
+          <span style="width: 30%">单据编码:{{ rowItem.docNo }}</span>
+          <span style="width: 30%">单据日期:{{ rowItem.createTime ? rowItem.createTime.split(' ')[0] : '' }}</span>
         </div>
-        <div style="flex: 1"> 审核: {{ formData.reviewerName || '' }}</div>
-      </div>
-      <div
-        style="
-          width: 100%;
-          font-size: 12px;
-          display: flex;
-          justify-content: space-between;
-          margin-top: 10px;
-        "
-      >
-        <div style="flex: 1">
-          <div>司机:</div>
+        <div
+          style="
+            width: 100%;
+            font-size: 12px;
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 10px;
+          "
+        >
+          <span style="width: 80%">收货人联系方式:{{ rowItem.linkName }} {{ rowItem.linkPhone }}</span>
         </div>
-        <div style="flex: 1"> 是否回单: {{ receiptRequirementTypeOption.find(item => item.value === formData.receiptRequirementTypeId)?.label || '' }}</div>
-        <div style="flex: 1">
-          <div>运费:{{ formData.deliveryTypeName || '' }}</div>
+        <div
+          style="
+            width: 100%;
+            font-size: 12px;
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 10px;
+          "
+        >
+          <span style="width: 80%">送货地址:{{ rowItem.receiveAddress }}</span>
         </div>
-        <div style="flex: 1"> </div>
-      </div>
-      <div
-        style="
-          width: 100%;
-          font-size: 12px;
-          display: flex;
-          justify-content: space-between;
-          margin-top: 10px;
-        "
-      >
-        <div style="flex: 1">
-          <div>备注:</div>
+        <table
+          cellspacing="0"
+          border
+          style="
+            width: 100%;
+            table-layout: fixed;
+            word-break: break-all;
+            word-wrap: break-word;
+            font-size: 12px;
+          "
+        >
+          <tbody>
+            <tr align="center">
+              <td style="padding: 5px; width: 4%"> 序号 </td>
+              <td style="padding: 5px; width: 22%"> 规格型号 </td>
+              <td style="padding: 5px; width: 6%"> 单位 </td>
+              <td style="padding: 5px; width: 8%"> 数量 </td>
+              <td style="padding: 5px; width: 8%"> 颜色 </td>
+              <td style="padding: 5px; width: 8%"> 生产批号 </td>
+              <td style="padding: 5px; width: 10%"> 裁线米段 </td>
+              <td style="padding: 5px; width: 12%"> 仓库 </td>
+            </tr>
+
+            <tr align="center" v-for="(item, index) in rowItem.productList" :key="item.id || index">
+              <td style="padding: 5px"> {{ index + 1 }} </td>
+              <td style="padding: 5px">
+                {{ item.modelType }}
+              </td>
+              <td style="padding: 5px"> {{ item.measuringUnit }}</td>
+              <td style="padding: 5px"> {{ item.totalCount }}</td>
+              <td style="padding: 5px"> {{ item.colorKey }}</td>
+              <td style="padding: 5px"> {{ item.batchNo }}</td>
+              <td style="padding: 5px"> {{ item.cuttingLength }}</td>
+              <td style="padding: 5px"> {{ item.warehouseName }}</td>
+            </tr>
+            <tr align="center">
+              <td style="padding: 5px"> </td>
+              <td style="padding: 5px"> 合计 </td>
+              <td style="padding: 5px">  </td>
+              <td style="padding: 5px">{{ getRowTotal(rowItem, 'totalCount', 2) }} </td>
+              <td style="padding: 5px"> </td>
+              <td style="padding: 5px"> </td>
+              <td style="padding: 5px"> </td>
+              <td style="padding: 5px"> </td>
+            </tr>
+          </tbody>
+        </table>
+        <div
+          style="
+            width: 100%;
+            font-size: 12px;
+            display: flex;
+            justify-content: space-between;
+            margin-top: 10px;
+          "
+        >
+          <div style="flex: 1">
+            <div>制单人:{{ rowItem.makerName }}</div>
+          </div>
+          <div style="flex: 1"> 核对人: </div>
+          <div style="flex: 1">
+            <div>仓库:</div>
+          </div>
+          <div style="flex: 1"> 审核: {{ rowItem.reviewerName || '' }}</div>
+        </div>
+        <div
+          style="
+            width: 100%;
+            font-size: 12px;
+            display: flex;
+            justify-content: space-between;
+            margin-top: 10px;
+          "
+        >
+          <div style="flex: 1">
+            <div>司机:</div>
+          </div>
+          <div style="flex: 1"> 是否回单: {{ receiptRequirementTypeOption.find(item => item.value === rowItem.receiptRequirementTypeId)?.label || '' }}</div>
+          <div style="flex: 1">
+            <div>运费:{{ getDeliveryTypeName(rowItem) }}</div>
+          </div>
+          <div style="flex: 1"> </div>
+        </div>
+        <div
+          style="
+            width: 100%;
+            font-size: 12px;
+            display: flex;
+            justify-content: space-between;
+            margin-top: 10px;
+          "
+        >
+          <div style="flex: 1">
+            <div>备注:</div>
+          </div>
         </div>
       </div>
     </div>
 
     <div slot="footer">
+      <el-button type="primary" @click="exportExcel">导出</el-button>
       <el-button @click="print">打印预览</el-button>
       <el-button @click="close">关闭</el-button>
     </div>
@@ -171,8 +173,9 @@
 </template>
 
 <script>
-  import { getSendSaleOrderrecordDetailSplit } from '@/api/saleManage/saleordersendrecord';
+  import { getSendSaleOrderCordDetailByIds } from '@/api/saleManage/saleordersendrecord';
   import { mapGetters } from 'vuex';
+  import { saveAs } from 'file-saver';
   import dictMixins from '@/mixins/dictMixins';
   export default {
     mixins: [dictMixins],
@@ -181,14 +184,15 @@
       ...mapGetters(['user'])
     },
     props: {
-      groupName: ''
+      groupName: {
+        type: String,
+        default: ''
+      }
     },
     data() {
       return {
-        checked: '',
         QRvisible: false,
-        isPrintPrice: false,
-        formData: {},
+        formData: [],
         receiptRequirementTypeOption: [
           {
             label: '签回单',
@@ -209,29 +213,34 @@
       this.requestDict('送货方式');
     },
     methods: {
-      async open(id, isPrintPrice) {
-        this.formData = await getSendSaleOrderrecordDetailSplit(id);
-        this.formData.deliveryTypeName = this.getDictValue(
-            '送货方式',
-            this.formData.deliveryTypeId
-          );
+      async open(ids) {
+        const list = await getSendSaleOrderCordDetailByIds(ids);
+        // 处理每条数据:合并 productList 和 replaceList,设置 deliveryTypeName
+        this.formData = list.map((rowItem) => {
           const productList = [
-            ...this.formData.productList.filter(item => item.isReplace != 1),
-            ...this.formData.replaceList
-          ]
-        this.formData.productList = productList;
+            ...(rowItem.productList || []).filter(item => item.isReplace != 1),
+            ...(rowItem.replaceList || [])
+          ];
+          return {
+            ...rowItem,
+            productList,
+            deliveryTypeName: this.getDictValue('送货方式', rowItem.deliveryTypeId)
+          };
+        });
         this.QRvisible = true;
-        this.isPrintPrice = isPrintPrice;
-        //包装维度
       },
       close() {
+        this.formData = [];
         this.QRvisible = false;
       },
-      getTotalValue(key, num) {
-        let val = this.formData?.productList?.reduce((total, item) => {
-          return (total += Number(item[key]));
+      getDeliveryTypeName(rowItem) {
+        return rowItem.deliveryTypeName || this.getDictValue('送货方式', rowItem.deliveryTypeId) || '';
+      },
+      // 计算单条单据的合计值
+      getRowTotal(rowItem, key, num) {
+        let val = rowItem?.productList?.reduce((total, item) => {
+          return (total += Number(item[key] || 0));
         }, 0);
-
         return (
           (val &&
             parseFloat(val)
@@ -241,7 +250,11 @@
         );
       },
       print() {
-        const printSection = document.getElementById('printSection');
+        const printSection = document.getElementById('printSectionHt1');
+        if (!printSection) {
+          this.$message.warning('未找到打印内容');
+          return;
+        }
         // 创建打印任务
         const printWindow = window.open('', '_blank');
         printWindow.document.open();
@@ -256,9 +269,149 @@
         printWindow.onload = function () {
           printWindow.print();
         };
+      },
+
+      /**
+       * 导出Excel
+       */
+      exportExcel() {
+        const border =
+          'border-top:1px solid #000;border-right:1px solid #000;border-bottom:1px solid #000;border-left:1px solid #000;';
+        const cellBase = `${border}padding:4px;mso-number-format:"\\@";vertical-align:middle;text-align:center;mso-horizontal-align:center;`;
+        const th = `${cellBase}font-weight:bold;font-family:'宋体';font-size:12pt;`;
+        const td = `${cellBase}font-family:'宋体';font-size:11pt;`;
+        const labelLeft = `${border}padding:4px;mso-number-format:"\\@";vertical-align:middle;text-align:left;mso-horizontal-align:left;font-family:'宋体';font-size:11pt;`;
+
+        const title = `${this.groupName || ''}出库单`;
+
+        const colWidths = [45, 190, 55, 70, 70, 80, 80, 100];
+        const totalCols = 8;
+        const colGroup = colWidths.map(w => `<col width="${w}" style="width:${w}pt;" />`).join('');
+
+        // 遍历多个单据生成多个表格
+        let tables = '';
+        this.formData.forEach((rowItem) => {
+          const list = rowItem.productList || [];
+          const totalCount = this.getRowTotal(rowItem, 'totalCount', 2);
+          const deliveryTypeName = this.getDeliveryTypeName(rowItem);
+          const receiptLabel = this.receiptRequirementTypeOption.find(
+            item => item.value === rowItem.receiptRequirementTypeId
+          )?.label || '';
+
+          const rows = list.map((item, index) => `
+            <tr height="24" style="height:24pt;">
+              <td align="center" valign="middle" style="${td}">${index + 1}</td>
+              <td align="center" valign="middle" style="${td}">${item.modelType || ''}</td>
+              <td align="center" valign="middle" style="${td}">${item.measuringUnit || ''}</td>
+              <td align="center" valign="middle" style="${td}">${item.totalCount ?? ''}</td>
+              <td align="center" valign="middle" style="${td}">${item.colorKey || ''}</td>
+              <td align="center" valign="middle" style="${td}">${item.batchNo || ''}</td>
+              <td align="center" valign="middle" style="${td}">${item.cuttingLength || ''}</td>
+              <td align="center" valign="middle" style="${td}">${item.warehouseName || ''}</td>
+            </tr>`
+          ).join('');
+
+          tables += `
+          <table border="1" cellspacing="0" cellpadding="0" align="center"
+            style="border-collapse:collapse;border:1px solid #000;mso-border-alt:solid #000 0.5pt;font-family:'宋体';font-size:11pt;text-align:center;">
+            <colgroup>${colGroup}</colgroup>
+            <tr height="40" style="height:40pt;">
+              <td colspan="${totalCols}" align="center" valign="middle" style="${border}padding:6px;text-align:center;font-family:'宋体';font-size:22pt;font-weight:bold;">${title}</td>
+            </tr>
+            <tr height="26" style="height:26pt;">
+              <td colspan="3" align="left" valign="middle" style="${labelLeft}">客户:${rowItem.contactName || ''}</td>
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}">单据编码:${rowItem.docNo || ''}</td>
+              <td colspan="3" align="left" valign="middle" style="${labelLeft}">单据日期:${rowItem.createTime ? rowItem.createTime.split(' ')[0] : ''}</td>
+            </tr>
+            <tr height="26" style="height:26pt;">
+              <td colspan="4" align="left" valign="middle" style="${labelLeft}">收货人联系方式:${rowItem.linkName || ''} ${rowItem.linkPhone || ''}</td>
+              <td colspan="4" align="left" valign="middle" style="${labelLeft}">送货地址:${rowItem.receiveAddress || ''}</td>
+            </tr>
+            <tr height="28" style="height:28pt;">
+              <td align="center" valign="middle" style="${th}">序号</td>
+              <td align="center" valign="middle" style="${th}">规格型号</td>
+              <td align="center" valign="middle" style="${th}">单位</td>
+              <td align="center" valign="middle" style="${th}">数量</td>
+              <td align="center" valign="middle" style="${th}">颜色</td>
+              <td align="center" valign="middle" style="${th}">生产批号</td>
+              <td align="center" valign="middle" style="${th}">裁线米段</td>
+              <td align="center" valign="middle" style="${th}">仓库</td>
+            </tr>
+            ${rows}
+            <tr height="26" style="height:26pt;">
+              <td align="center" valign="middle" style="${td}"></td>
+              <td align="center" valign="middle" style="${td};font-weight:bold;">合计</td>
+              <td align="center" valign="middle" style="${td}"></td>
+              <td align="center" valign="middle" style="${td};font-weight:bold;">${totalCount}</td>
+              <td align="center" valign="middle" style="${td}"></td>
+              <td align="center" valign="middle" style="${td}"></td>
+              <td align="center" valign="middle" style="${td}"></td>
+              <td align="center" valign="middle" style="${td}"></td>
+            </tr>
+            <tr height="28" style="height:28pt;">
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}">制单人:${rowItem.makerName || ''}</td>
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}">核对人:</td>
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}">仓库:</td>
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}">审核:${rowItem.reviewerName || ''}</td>
+            </tr>
+            <tr height="28" style="height:28pt;">
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}">司机:</td>
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}">是否回单:${receiptLabel}</td>
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}">运费:${deliveryTypeName}</td>
+              <td colspan="2" align="left" valign="middle" style="${labelLeft}"></td>
+            </tr>
+            <tr height="28" style="height:28pt;">
+              <td colspan="8" align="left" valign="middle" style="${labelLeft}">备注:</td>
+            </tr>
+          </table>
+          <br style="mso-special-character:line-break;page-break-before:always" />`;
+        });
+
+        const html = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
+        <head>
+        <meta charset="UTF-8" />
+        <style>
+          br { mso-data-placement: same-cell; }
+          table { mso-displayed-decimal-separator:"."; mso-displayed-thousand-separator:","; }
+          td { mso-ignore:padding; }
+        </style>
+        <!--[if gte mso 9]><xml>
+        <x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
+        <x:Name>${title}</x:Name>
+        <x:WorksheetOptions>
+          <x:DefaultRowHeight>260</x:DefaultRowHeight>
+          <x:Print><x:ValidPrinterInfo/><x:HorizontalResolution>600</x:HorizontalResolution><x:VerticalResolution>600</x:VerticalResolution></x:Print>
+          <x:Selected/>
+          <x:DoNotDisplayGridlines/>
+        </x:WorksheetOptions>
+        </x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook>
+        </xml><![endif]-->
+        </head>
+        <body>${tables}</body></html>`;
+
+        const blob = new Blob(['\uFEFF' + html], {
+          type: 'application/vnd.ms-excel;charset=utf-8'
+        });
+        const firstDocNo = this.formData[0]?.docNo || '';
+        const suffix = this.formData.length > 1 ? `等${this.formData.length}条` : firstDocNo;
+        saveAs(blob, `${title}_${suffix}.xls`);
       }
     }
   };
 </script>
 
-<style lang="scss"></style>
+<style scoped lang="scss">
+  table {
+    border-collapse: collapse;
+  }
+  th, td {
+    border: 1px solid #000;
+    text-align: center;
+    padding: 8px;
+  }
+  @media print {
+    .no-print {
+      display: none;
+    }
+  }
+</style>

+ 4 - 1
src/views/saleManage/saleOrder/invoice/index.vue

@@ -96,7 +96,7 @@
 
                   <el-dropdown-item
                     v-if="$hasPermission('eom:print-invoice9')"
-                    @click.native="handlePrint('printTemplateHt1Ref')"
+                    @click.native="handleOutPrint('printTemplateHt1Ref')"
                     >出库单</el-dropdown-item
                   >
                 </el-dropdown-menu>
@@ -699,6 +699,9 @@
             this.$refs[ref].open(this.selection.map(item => item.id), false);
           });
       },
+      handleOutPrint(ref) {
+        this.$refs[ref].open(this.selection.map(item => item.id), false);
+      },
       //删除接口
       remove(delData) {
         deleteSendInformation(delData).then((res) => {