Browse Source

前端生成pdf模板并下载成pdf文件

lxf 2 years ago
parent
commit
8d38d1b54e

+ 2 - 0
package.json

@@ -24,12 +24,14 @@
     "echarts-gl": "^2.0.9",
     "element-ui": "^2.15.7",
     "file-saver": "^2.0.5",
+    "html2canvas": "^1.4.1",
     "jquery": "^3.5.1",
     "js-base64": "^2.5.1",
     "js-cookie": "^2.2.0",
     "js-export-excel": "^1.1.4",
     "js-md5": "^0.7.3",
     "js-table2excel": "^1.0.3",
+    "jspdf": "^2.5.1",
     "jsplumb": "^2.15.5",
     "less-loader": "^5.0.0",
     "mockjs": "^1.0.1-beta3",

+ 10 - 1
src/api/shengde/productionSystem/purchase/contract.js

@@ -74,7 +74,7 @@ export function purchaseContractRemove(data) {
 }
 
 // 采购合同-生成采购PDF
-export function generatePdf(data) {
+export function purchaseGeneratePdf(data) {
   return request({
     url: '/saas-production/saas/production/purchaseContract/generatePdf',
     method: 'get',
@@ -82,6 +82,15 @@ export function generatePdf(data) {
   })
 }
 
+// 采购合同-生成采购PDF-新版
+export function purchaseGeneratePdfV2(data) {
+  return request({
+    url: '/saas-production/saas/production/purchaseContract/generateV2',
+    method: 'get',
+    params: data,
+  })
+}
+
 // 采购合同-作废-发起
 export function cancellationStart(data) {
   return request({

+ 2 - 0
src/main.js

@@ -54,6 +54,7 @@ import VueWechatTitle from 'vue-wechat-title'
 import './util/table2excel' // global table2excel
 // import 'view-design/dist/styles/iview.css';
 import VueBarcode from 'vue-barcode'
+import htmlToPdf from "@/util/htmlToPdf"
 
 Vue.prototype.selectConstantsLabel = selectConstantsLabel
 Vue.prototype.selectConstantsLabelRemark = selectConstantsLabelRemark
@@ -95,6 +96,7 @@ Vue.use(animate)
 Vue.use(Contextmenu)
 Vue.use(ViewUI)
 Vue.use(VueWechatTitle)
+Vue.use(htmlToPdf)
 
 const errImg = require('./assets/images/empty.png')
 // const loadingImg = require('./assets/images/loading-spin.svg')

+ 54 - 0
src/util/htmlToPdf.js

@@ -0,0 +1,54 @@
+// 导出页面为PDF格式
+import html2canvas from 'html2canvas'
+import JSPDF from 'jspdf'
+var a4w = 200
+var a4h = 287 // A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257
+var imgw = 40
+var imgh = 40
+function addWaterMark(doc) {
+  var totalPages = doc.internal.getNumberOfPages()
+  for (var i = 1; i <= totalPages; i++) {
+    doc.setPage(i)
+    // doc.addImage('http://www.printmat.cn:8181/file/upload/2023/02/24/20230224180954A0974981a85a2400425eb03c2c3f588a9711.png', 'PNG', 0, 0, 210, 297)
+    // doc.addImage(require('../assets/logo/watermark.png'), 'PNG', 0, 0, 210, 297)
+    // doc.setTextColor(150);
+    // doc.text(50, doc.internal.pageSize.height - 30, 'Watermark');
+  }
+  return doc
+}
+export default {
+  install(Vue, options) {
+    Vue.prototype.ExportSavePdf = function (htmlTitle, currentTime) {
+      //注意:这里建立了方法名字(ExportSavePdf),Vue.prototype 代表着通过 vue 来加载应用这个方法。下面的全局注册这个文件意思就是说可以将这个方法在 vue项目的全局中应用
+      var element = document.getElementById('pdfContent') //特别注意:这个id很重要,需要在页面应用到这个id。
+      html2canvas(element, {
+        logging: false,
+        dpi: 120, // 图片清晰度问题
+        allowTaint: true,  //开启跨域
+        useCORS: true, // 支持跨域打印图片
+        scrollY: 0,
+        scrollX: 0,
+      }).then(function (canvas) {
+        var pdf = new JSPDF('p', 'mm', 'a4') // A4纸,纵向
+        var ctx = canvas.getContext('2d')
+        var imgHeight = Math.floor((a4h * canvas.width) / a4w) // 按A4显示比例换算一页图像的像素高度
+        var renderedHeight = 0
+        while (renderedHeight < canvas.height) {
+          var page = document.createElement('canvas')
+          page.width = canvas.width
+          page.height = Math.min(imgHeight, canvas.height - renderedHeight) // 可能内容不足一页
+          // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
+          page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0)
+          pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 5, 5, a4w, Math.min(a4h, (a4w * page.height) / page.width)) // 添加图像到页面,保留10mm边距
+          renderedHeight += imgHeight
+          if (renderedHeight < canvas.height) {
+            pdf.addPage()
+          } // 如果后面还有内容,添加一个空页
+          // delete page;
+        }
+        pdf = addWaterMark(pdf)
+        pdf.save(htmlTitle + currentTime)
+      })
+    }
+  },
+}

+ 229 - 6
src/views/shengde/productionSystem/purchase/contract/contractDetails.vue

@@ -51,6 +51,157 @@
         </el-card>
       </el-col>
     </el-row>
+
+    <el-dialog title="生成PDF" v-if="openPdf" :visible.sync="openPdf" width="770px" append-to-body>
+      <div id="pdfContent" style="width: 726px">
+        <div class="con">
+          <div style="font-size: 24px; font-weight: 700; padding: 16px; text-align: center">福清市胜德体育用品有限公司</div>
+          <div style="font-size: 24px; padding: 8px 0 4px 0; text-align: center; border-bottom: 2px solid black">采购合同</div>
+          <div style="height: 8px"></div>
+          <table cellspacing="0" cellpadding="0" border="0" style="width: 100%; line-height: 24px">
+            <tr>
+              <td style="width: 50%">
+                <span>需方:{{ pdfDetail.company.nameChinese }}</span>
+              </td>
+              <td>
+                <span>订单号:{{ pdfDetail.purchaseContract.code }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td style="width: 50%">
+                <span>供方:{{ pdfDetail.purchaseContract.supplyName }}</span>
+              </td>
+              <td>
+                <span>日期:{{ pdfDetail.createTime }}</span>
+              </td>
+            </tr>
+          </table>
+          <div style="height: 8px"></div>
+          <table cellspacing="0" cellpadding="0" border="0" class="tableOne">
+            <tr>
+              <th style="width: 30px">序号</th>
+              <th style="width: 120px">品号</th>
+              <th style="width: 260px">产品名称</th>
+              <th style="width: 45px">数量</th>
+              <th style="width: 45px">单位</th>
+              <th style="width: 45px">单价</th>
+              <th style="width: 60px">金额</th>
+              <th style="width: 100px">交货期</th>
+            </tr>
+            <template v-if="pdfDetail.products && pdfDetail.products.length > 0">
+              <tr v-for="(item, index) in pdfDetail.products" :key="index">
+                <td>
+                  {{ index + 1 }}
+                </td>
+                <td style="text-align: left; word-break: break-all">
+                  <span>{{ item.bomColorCode }}</span>
+                </td>
+                <td style="text-align: left; word-break: break-all">
+                  <span>{{ item.bomColorName }}</span>
+                </td>
+                <td>
+                  <span>{{ item.bomCompany }}</span>
+                </td>
+                <td>
+                  <span>{{ item.quantity }}</span>
+                </td>
+                <td>
+                  <span>{{ item.price }}</span>
+                </td>
+                <td>
+                  <span>{{ item.sumPrice }}</span>
+                </td>
+                <td style="text-align: left; word-break: break-all">
+                  <span>{{ pdfDetail.deliveryTime }}</span>
+                </td>
+              </tr>
+            </template>
+            <tr>
+              <td>合计:</td>
+              <td colspan="5"></td>
+              <td>
+                <span>{{ pdfDetail.total }}</span>
+              </td>
+              <td style="border-right: 0"></td>
+            </tr>
+          </table>
+          <div style="height: 8px"></div>
+          <table cellspacing="0" cellpadding="0" border="0" class="tableTwo">
+            <tr>
+              <td>
+                <div crossOrigin="anonymous" class="ql-snow" v-html="limitImg(pdfDetail.purchaseContract.remark)"></div>
+              </td>
+            </tr>
+          </table>
+          <div style="height: 32px"></div>
+          <table cellspacing="0" cellpadding="0" border="0" class="tableThree">
+            <tr>
+              <td style="width: 50%; position: relative">
+                <div>
+                  <span>需方(签章):{{ pdfDetail.company.nameChinese }}</span>
+                </div>
+                <div style="position: absolute; top: -50px; left: 20px">
+                  <img
+                    v-if="pdfDetail.company.companySeal"
+                    style="width: 160px; height: 160px"
+                    :src="pathPrefix + pdfDetail.company.companySeal"
+                    alt=""
+                    srcset=""
+                  />
+                </div>
+              </td>
+              <td>
+                <span>供方(签章):{{ pdfDetail.supplier.name }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td style="width: 50%">
+                <span>税 号:{{ pdfDetail.company.taxpayerNumber }}</span>
+              </td>
+              <td>
+                <span>税 号:{{ pdfDetail.supplier.dutyParagraph }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td style="width: 50%">
+                <span>开 户:{{ pdfDetail.company.bankName }}</span>
+              </td>
+              <td>
+                <span>开 户:{{ pdfDetail.supplier.bank }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td style="width: 50%">
+                <span>账 号:{{ pdfDetail.company.bankAccount }}</span>
+              </td>
+              <td>
+                <span>账 号:{{ pdfDetail.supplier.accountNumber }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td style="width: 50%">
+                <span>地 址:{{ pdfDetail.company.bankAddress }}</span>
+              </td>
+              <td>
+                <span>地 址:{{ pdfDetail.supplier.province }} {{ pdfDetail.supplier.city }} {{ pdfDetail.supplier.address }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td style="width: 50%">
+                <span>电 话:{{ pdfDetail.company.telephone }}</span>
+              </td>
+              <td>
+                <span>电 话:{{ pdfDetail.supplier.phone }}</span>
+              </td>
+            </tr>
+          </table>
+        </div>
+      </div>
+      <div style="width: 100%; text-align: center">
+        <el-button type="primary" @click="clickDownload()" size="small" v-db-click>下载PDF</el-button>
+        <el-button @click="openPdf = false" size="small" v-db-click>取 消</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -63,7 +214,7 @@ import LabelTemplate from '@/components/LabelTemplate'
 import NewHistory from '@/views/activiti/include/NewHistory'
 import { mapGetters } from 'vuex'
 import SubscriptionDetails from '@/views/shengde/group/subscription/management/details/index'
-import { generatePdf } from '@/api/shengde/productionSystem/purchase/contract'
+import { purchaseGeneratePdfV2 } from '@/api/shengde/productionSystem/purchase/contract'
 import Utils from '@/util/transit'
 
 export default {
@@ -82,6 +233,20 @@ export default {
       pdfUrl: '',
       activeTwo: 'one',
       processInstanceId: '',
+      pdfDetail: {
+        sumCount: '',
+        purchaseCode: '',
+        baseUrl: '',
+        total: '',
+        deliveryTime: '',
+        createTime: '',
+        purchaseId: '',
+        purchaseContract: {},
+        supplier: {},
+        company: {},
+        products: [],
+      },
+      openPdf: false,
     }
   },
   created() {
@@ -107,13 +272,30 @@ export default {
       }
     },
     clickOpenPdf() {
-      if (this.pdfUrl) {
-        window.open(this.pathPrefix + this.pdfUrl)
-      } else {
-        generatePdf({ id: this.rowData.id }).then((res) => {
-          window.open(this.pathPrefix + res.data.data)
+      if (!this.pdfDetail.purchaseId) {
+        purchaseGeneratePdfV2({ id: this.$route.query.id }).then((res) => {
+          this.pdfDetail = res.data.data
         })
       }
+      this.openPdf = true
+    },
+    clickDownload() {
+      const loading = this.$loading({})
+      setTimeout(() => {
+        let fileName = '采购合同PDF文件'
+        if (this.pdfDetail.purchaseCode) {
+          fileName = this.pdfDetail.purchaseCode
+        }
+        this.ExportSavePdf(fileName, '')
+        loading.close()
+      }, 500)
+    },
+    limitImg(text) {
+      if (text) {
+        return text.replace(/<img/g, '<img style="max-width: 98%;"')
+      } else {
+        return text
+      }
     },
   },
 }
@@ -140,4 +322,45 @@ export default {
     font-size: 12px !important;
   }
 }
+.con {
+  font-family: 'Times New Roman', 'SimSun' !important;
+  color: black !important;
+  font-size: 12px !important;
+  width: 705px;
+  text-align: left;
+  background-color: white;
+  padding: 16px;
+}
+.tableOne {
+  border: 1px solid black;
+  line-height: 18px;
+  overflow: auto;
+  width: 100%;
+}
+.tableOne th {
+  font-weight: 700;
+  border-right: 1px solid black;
+  text-align: center;
+}
+.tableOne td {
+  border-right: 1px solid black;
+  border-top: 1px solid black;
+  text-align: center;
+}
+.tableTwo {
+  width: 100%;
+  line-height: 18px;
+  word-break: break-all;
+}
+.tableTwo td {
+  vertical-align: top;
+}
+.tableThree {
+  width: 100%;
+  line-height: 24px;
+  word-break: break-all;
+}
+.tableThree td {
+  vertical-align: top;
+}
 </style>