Browse Source

请款打款打印下载pdf功能

lxf 11 tháng trước cách đây
mục cha
commit
82ea8e5615

+ 5 - 2
jy-ui/package.json

@@ -12,12 +12,14 @@
     "lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\""
   },
   "dependencies": {
+    "@element-plus/icons-vue": "^2.3.1",
     "@logicflow/core": "^1.2.15",
     "@logicflow/extension": "^1.2.16",
-    "@element-plus/icons-vue": "^2.3.1",
     "@vueuse/core": "^10.11.0",
     "axios": "^1.7.2",
     "element-plus": "^2.8.5",
+    "html2canvas": "^1.4.1",
+    "jspdf": "^2.5.1",
     "mitt": "^3.0.1",
     "nprogress": "^0.2.0",
     "pinia": "^2.1.7",
@@ -28,7 +30,8 @@
     "sortablejs": "^1.15.2",
     "terser": "^5.4.0",
     "vue": "^3.4.31",
-    "vue-router": "^4.4.0"
+    "vue-router": "^4.4.0",
+    "vue3-print-nb": "^0.1.4"
   },
   "devDependencies": {
     "@rushstack/eslint-patch": "^1.8.0",

+ 5 - 0
jy-ui/src/api/flow/execute.ts

@@ -20,3 +20,8 @@ export function handleApi(data: StrAnyObj): Promise<void> {
 export function getDonePageApi(params: StrAnyObj): Promise<PageType<StrAnyObj>> {
   return request.get('/flow/execute/donePage', params)
 }
+
+// 查询已办任务历史记录
+export function getDoneListTwoApi(id: string): Promise<PageType<StrAnyObj>> {
+  return request.get(`/flow/execute/doneListByBusinessId/${id}`)
+}

+ 690 - 0
jy-ui/src/components/PDF/moneyPDF.vue

@@ -0,0 +1,690 @@
+<template>
+  <div>
+    <div id="pdfDom" style="width: 776px">
+      <div style="padding: 60px 30px; font-size: 12px !important; color: black">
+        <div style="font-size: 16px; text-align: center; padding: 8px">
+          <span>{{ dictValueLabel(printDetails.type, paymentType) }}审批单</span>
+        </div>
+        <div style="padding: 8px 0">
+          <span>{{ dictValueLabel(printDetails.corporationId, companyData) }}</span>
+          <span style="padding-left: 32px">创建时间: {{ printDetails.createTime }}</span>
+        </div>
+        <div style="border: 1px solid black">
+          <div style="display: flex; border-bottom: 1px solid black">
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 8px;
+              "
+            >
+              创建人
+            </div>
+            <div style="width: calc(100% - 140px); padding: 8px">
+              {{ printDetails.userName }}
+            </div>
+          </div>
+          <div style="display: flex; border-bottom: 1px solid black">
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 8px;
+              "
+            >
+              创建人部门
+            </div>
+            <div style="width: calc(100% - 140px); padding: 8px">
+              {{ printDetails.deptName }}
+            </div>
+          </div>
+          <div
+            style="display: flex; border-bottom: 1px solid black"
+            v-if="printDetails.type != '3'"
+          >
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 4px 8px;
+                display: flex;
+                align-items: center;
+              "
+            >
+              费用明细
+            </div>
+            <div style="width: calc(100% - 140px)">
+              <div style="border-bottom: 1px solid black; display: flex">
+                <div
+                  style="
+                    max-width: 140px;
+                    min-width: 140px;
+                    padding: 4px 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  费用类型
+                </div>
+                <div
+                  style="
+                    width: calc(100% - 300px);
+                    padding: 4px 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  款项说明
+                </div>
+                <div
+                  style="
+                    width: 60px;
+                    padding: 4px 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  货币
+                </div>
+                <div style="width: 100px; padding: 4px 8px; text-align: center">付款金额</div>
+              </div>
+              <template
+                v-if="
+                  printDetails.paymentRequestsDetailList &&
+                  printDetails.paymentRequestsDetailList.length > 0
+                "
+              >
+                <div v-for="(item, index) in printDetails.paymentRequestsDetailList" :key="index">
+                  <div
+                    :style="
+                      index + 1 !== printDetails.paymentRequestsDetailList.length
+                        ? 'border-bottom: 1px solid black;  display: flex'
+                        : ' display: flex'
+                    "
+                  >
+                    <div
+                      style="
+                        max-width: 140px;
+                        min-width: 140px;
+                        padding: 4px 8px;
+                        border-right: 1px solid black;
+                        text-align: center;
+                      "
+                    >
+                      {{ dictValueLabel(item.expenseType, expenseType) }}
+                    </div>
+                    <div
+                      style="
+                        width: calc(100% - 300px);
+                        padding: 4px 8px;
+                        border-right: 1px solid black;
+                        display: flex;
+                        align-items: center;
+                      "
+                    >
+                      {{ item.remark }}
+                    </div>
+                    <div
+                      style="
+                        width: 60px;
+                        padding: 4px 8px;
+                        border-right: 1px solid black;
+                        display: flex;
+                        align-items: center;
+                      "
+                    >
+                      人民币
+                    </div>
+                    <div style="width: 100px; padding: 4px 8px; display: flex; align-items: center">
+                      {{ item.amount }}
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+          <div style="display: flex; border-bottom: 1px solid black" v-else>
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 4px 8px;
+                display: flex;
+                align-items: center;
+              "
+            >
+              费用明细
+            </div>
+            <div style="width: calc(100% - 140px)">
+              <div style="border-bottom: 1px solid black; display: flex">
+                <div
+                  style="
+                    max-width: 140px;
+                    min-width: 140px;
+                    padding: 4px 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  费用类型
+                </div>
+                <div
+                  style="
+                    width: calc(100% - 360px);
+                    padding: 4px 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  款项说明
+                </div>
+                <div
+                  style="
+                    width: 60px;
+                    padding: 4px 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  货币
+                </div>
+                <div
+                  style="
+                    width: 80px;
+                    padding: 4px 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  预支金额
+                </div>
+                <div style="width: 80px; padding: 4px 8px; text-align: center">付款金额</div>
+              </div>
+              <template
+                v-if="
+                  printDetails.paymentRequestsDetailList &&
+                  printDetails.paymentRequestsDetailList.length > 0
+                "
+              >
+                <div v-for="(item, index) in printDetails.paymentRequestsDetailList" :key="index">
+                  <div
+                    :style="
+                      index + 1 !== printDetails.paymentRequestsDetailList.length
+                        ? 'border-bottom: 1px solid black;  display: flex'
+                        : ' display: flex'
+                    "
+                  >
+                    <div
+                      style="
+                        max-width: 140px;
+                        min-width: 140px;
+                        padding: 4px 8px;
+                        border-right: 1px solid black;
+                        text-align: center;
+                      "
+                    >
+                      {{ dictValueLabel(item.expenseType, expenseType) }}
+                    </div>
+                    <div
+                      style="
+                        width: calc(100% - 360px);
+                        padding: 4px 8px;
+                        border-right: 1px solid black;
+                        display: flex;
+                        align-items: center;
+                      "
+                    >
+                      {{ item.remark }}
+                    </div>
+                    <div
+                      style="
+                        width: 60px;
+                        padding: 4px 8px;
+                        border-right: 1px solid black;
+                        display: flex;
+                        align-items: center;
+                      "
+                    >
+                      人民币
+                    </div>
+                    <div
+                      style="
+                        width: 80px;
+                        padding: 4px 8px;
+                        border-right: 1px solid black;
+                        display: flex;
+                        align-items: center;
+                      "
+                    >
+                      {{ item.advanceAmount }}
+                    </div>
+                    <div style="width: 80px; padding: 4px 8px; display: flex; align-items: center">
+                      {{ item.amount }}
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+          <div
+            style="display: flex; border-bottom: 1px solid black"
+            v-if="printDetails.type !== '3'"
+          >
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 8px;
+              "
+            >
+              总报销金额
+            </div>
+            <div style="width: calc(100% - 140px); display: flex">
+              <div style="width: calc(100% - 100px); padding: 8px; border-right: 1px solid black">
+                {{ NumberToChinese(computeMoney('amount')) }}
+              </div>
+              <div style="width: 100px; padding: 8px">
+                {{ computeMoney('amount') }}
+              </div>
+            </div>
+          </div>
+          <div v-else>
+            <div style="display: flex; border-bottom: 1px solid black">
+              <div
+                style="
+                  max-width: 140px;
+                  min-width: 140px;
+                  border-right: 1px solid black;
+                  padding: 8px;
+                "
+              >
+                核销总金额
+              </div>
+              <div style="width: calc(100% - 140px); display: flex">
+                <div style="width: calc(100% - 80px); padding: 8px; border-right: 1px solid black">
+                  {{ NumberToChinese(computeMoney('amount')) }}
+                </div>
+                <div style="width: 80px; padding: 8px">
+                  {{ computeMoney('amount') }}
+                </div>
+              </div>
+            </div>
+            <div style="display: flex; border-bottom: 1px solid black">
+              <div
+                style="
+                  max-width: 140px;
+                  min-width: 140px;
+                  border-right: 1px solid black;
+                  padding: 8px;
+                "
+              >
+                预支总金额
+              </div>
+              <div style="width: calc(100% - 140px); display: flex">
+                <div style="width: calc(100% - 80px); padding: 8px; border-right: 1px solid black">
+                  {{ NumberToChinese(computeMoney('advanceAmount')) }}
+                </div>
+                <div style="width: 80px; padding: 8px">
+                  {{ computeMoney('advanceAmount') }}
+                </div>
+              </div>
+            </div>
+            <div style="display: flex; border-bottom: 1px solid black">
+              <div
+                style="
+                  max-width: 140px;
+                  min-width: 140px;
+                  border-right: 1px solid black;
+                  padding: 8px;
+                "
+              >
+                差额 (核销 - 预支)
+              </div>
+              <div style="width: calc(100% - 140px); display: flex">
+                <div style="width: calc(100% - 80px); padding: 8px; border-right: 1px solid black">
+                  {{ NumberToChinese(computeBalance()) }}
+                </div>
+                <div style="width: 80px; padding: 8px">
+                  {{ computeBalance() }}
+                </div>
+              </div>
+            </div>
+          </div>
+          <div style="display: flex; border-bottom: 1px solid black">
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 8px;
+              "
+            >
+              单据数量
+            </div>
+            <div style="width: calc(100% - 140px); padding: 8px">
+              {{ printDetails.documentQuantity }}
+            </div>
+          </div>
+          <div style="display: flex; border-bottom: 1px solid black">
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 0 8px;
+                display: flex;
+                align-items: center;
+              "
+            >
+              收款信息
+            </div>
+            <div style="width: calc(100% - 140px)">
+              <div style="border-bottom: 1px solid black; display: flex">
+                <div
+                  style="
+                    width: 19%;
+                    padding: 0 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  支付方式
+                </div>
+                <div
+                  style="
+                    width: 27%;
+                    padding: 0 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  收款方户名
+                </div>
+                <div
+                  style="
+                    width: 27%;
+                    padding: 0 8px;
+                    border-right: 1px solid black;
+                    text-align: center;
+                  "
+                >
+                  开户行
+                </div>
+                <div style="width: 27%; padding: 0 8px; text-align: center">收款方账号</div>
+              </div>
+              <div style="display: flex">
+                <div
+                  style="
+                    width: 19%;
+                    padding: 0 8px;
+                    border-right: 1px solid black;
+                    display: flex;
+                    align-items: center;
+                  "
+                >
+                  {{ dictValueLabel(printDetails.payType, payType) }}
+                </div>
+                <div
+                  style="
+                    width: 27%;
+                    padding: 0 8px;
+                    border-right: 1px solid black;
+                    display: flex;
+                    align-items: center;
+                  "
+                >
+                  {{ printDetails.accountName }}
+                </div>
+                <div
+                  style="
+                    width: 27%;
+                    padding: 0 8px;
+                    border-right: 1px solid black;
+                    display: flex;
+                    align-items: center;
+                  "
+                >
+                  {{ printDetails.depositBank }}
+                </div>
+                <div style="width: 27%; padding: 0 8px; display: flex; align-items: center">
+                  {{ printDetails.account }}
+                </div>
+              </div>
+            </div>
+          </div>
+          <div style="display: flex; border-bottom: 1px solid black">
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 8px;
+              "
+            >
+              电子发票(PDF/JPG)
+            </div>
+            <div style="width: calc(100% - 140px); padding: 8px">
+              {{ getAtts(printDetails.atts) }}
+            </div>
+          </div>
+          <div style="display: flex">
+            <div
+              style="
+                max-width: 140px;
+                min-width: 140px;
+                border-right: 1px solid black;
+                padding: 4px 8px;
+                display: flex;
+                align-items: center;
+              "
+            >
+              审批流程
+            </div>
+            <div style="width: calc(100% - 140px)">
+              <template v-if="recordList && recordList.length > 0">
+                <div v-for="(item, index) in recordList" :key="index">
+                  <div
+                    :style="
+                      index + 1 !== recordList.length
+                        ? 'border-bottom: 1px solid black; padding: 4px 8px; display: flex'
+                        : 'padding: 4px 8px; display: flex'
+                    "
+                  >
+                    <div style="width: calc(100% - 120px); word-wrap: break-word">
+                      <span>{{ item.nodeName }}: </span>
+                      <span style="padding-left: 4px">{{ item.approver }}</span>
+                      <span style="padding-left: 4px"
+                        >({{
+                          item.flowStatus == 3 ? '驳回' : item.skipType == 'PASS' ? '通过' : '退回'
+                        }})</span
+                      >
+                      <span style="padding-left: 4px">{{ item.message }}</span>
+                    </div>
+                    <div style="width: 120px">{{ item.updateTime }}</div>
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+        </div>
+        <div style="padding-top: 16px">
+          <span>打印时间: {{ presentTime }}</span>
+          <span style="padding-left: 32px">打印人: {{ userStore.nickname }}</span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { getDoneListTwoApi } from '@/api/flow/execute'
+import { getDetailApi } from '@/api/business/payment/requests'
+import { getDictByCode } from '@/utils/dict'
+import { getPageApi as getCorporationPageApi } from '@/api/business/corporation/corporation'
+import { useUserStore } from '@/stores/modules/user'
+
+const props = defineProps({
+  rowData: Object
+})
+const userStore = useUserStore()
+const paymentType = ref([])
+const payType = ref([])
+const companyData = ref([])
+const expenseType = ref([])
+const printDetails = ref({})
+const recordList = ref({})
+const presentTime = ref('')
+function formatDate(date) {
+  const year = date.getFullYear()
+  const month = String(date.getMonth() + 1).padStart(2, '0') // 月份从0开始,所以需要加1
+  const day = String(date.getDate()).padStart(2, '0')
+  const hours = String(date.getHours()).padStart(2, '0')
+  const minutes = String(date.getMinutes()).padStart(2, '0')
+  const seconds = String(date.getSeconds()).padStart(2, '0')
+  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+}
+function dictValueLabel(value, arr) {
+  if ((value || value === 0) && arr) {
+    const current = arr.filter((x) => x.value == value)
+    if (current && current.length > 0) {
+      return current[0].label
+    }
+    return ''
+  }
+  return ''
+}
+function getDictData() {
+  getDictByCode('payment_requests_type').then((res) => {
+    paymentType.value = res
+  })
+  getDictByCode('pay_type').then((res) => {
+    payType.value = res
+  })
+  getDictByCode('expense_type').then((res) => {
+    expenseType.value = res
+  })
+  getCorporationPageApi({ searchAll: true }).then((res) => {
+    if (res?.records && res.records.length > 0) {
+      companyData.value = res.records.map((item) => {
+        return {
+          label: item.name,
+          value: item.id
+        }
+      })
+    } else {
+      companyData.value = []
+    }
+  })
+}
+getDictData()
+const computeMoney = (label) => {
+  let amount = 0
+  if (
+    printDetails.value.paymentRequestsDetailList &&
+    printDetails.value.paymentRequestsDetailList.length > 0
+  ) {
+    for (let i = 0; i < printDetails.value.paymentRequestsDetailList.length; i++) {
+      if (printDetails.value.paymentRequestsDetailList[i][label]) {
+        amount = Number(
+          parseFloat(
+            Number(amount) + Number(printDetails.value.paymentRequestsDetailList[i][label])
+          ).toFixed(2)
+        )
+      }
+    }
+  }
+  return amount
+}
+function toDx(n) {
+  //阿拉伯数字转换函数
+  switch (n) {
+    case '0':
+      return '零'
+    case '1':
+      return '壹'
+    case '2':
+      return '贰'
+    case '3':
+      return '叁'
+    case '4':
+      return '肆'
+    case '5':
+      return '伍'
+    case '6':
+      return '陆'
+    case '7':
+      return '柒'
+    case '8':
+      return '捌'
+    case '9':
+      return '玖'
+  }
+}
+// 金额转大写
+function NumberToChinese(m) {
+  let unit = ['仟', '佰', '拾', '', '仟', '佰', '拾', '', '角', '分', '厘']
+  m *= 1000
+  m = Number(parseFloat(m).toFixed(0))
+  m += ''
+  var x = m.length
+  var result = ''
+  for (var i = 0; i < x; i++) {
+    if (i == 3) {
+      result = '元' + result
+    } else if (i == 7) {
+      result = '万' + result
+    }
+    if (m.charAt(x - i - 1) == 0) {
+      if (i != 0 && i != 1 && i != 2) {
+        if (result.charAt(0) != '零' && result.charAt(0) != '元' && result.charAt(0) != '万') {
+          result = '零' + result
+        }
+      }
+      continue
+    }
+    result = toDx(m.charAt(x - i - 1)) + unit[unit.length - i - 1] + result
+  }
+  result += result.charAt(result.length - 1) == '元' ? '整' : ''
+  return result
+}
+const computeBalance = () => {
+  let balance = 0
+  let advanceAmount = computeMoney('advanceAmount')
+  let amount = computeMoney('amount')
+  if (amount) {
+    balance = Number(amount)
+  }
+  if (advanceAmount) {
+    balance = Number(parseFloat(Number(balance) - Number(advanceAmount)).toFixed(2))
+  }
+  return balance
+}
+const getAtts = (atts) => {
+  let text = ''
+  if (atts) {
+    let att = JSON.parse(atts)
+    if (att && att.length > 0) {
+      text = att.map((item) => item.name).join(',')
+    }
+  }
+  return text
+}
+onMounted(() => {
+  presentTime.value = formatDate(new Date())
+  if (props?.rowData?.id) {
+    getDetailApi({ id: props.rowData.id }).then((res) => {
+      printDetails.value = res
+    })
+    getDoneListTwoApi(props.rowData.id).then((res) => {
+      recordList.value = res
+    })
+  }
+})
+</script>
+
+<style lang="scss" scoped></style>

+ 2 - 1
jy-ui/src/main.ts

@@ -1,5 +1,6 @@
 import App from './App.vue'
 import setupPlugins from '@/plugins'
+import print from 'vue3-print-nb'
 
 import 'element-plus/dist/index.css'
 import 'element-plus/theme-chalk/dark/css-vars.css'
@@ -9,4 +10,4 @@ import '@/styles/element.scss'
 import '@/styles/element-dark.scss'
 import '@/styles/common.scss'
 
-createApp(App).use(setupPlugins).mount('#app')
+createApp(App).use(setupPlugins).use(print).mount('#app')

+ 91 - 0
jy-ui/src/utils/getPdf.js

@@ -0,0 +1,91 @@
+import html2Canvas from 'html2canvas'
+import JsPDF from 'jspdf'
+export function getPdf(title) {
+  // pdfDom 这个就是你vue页面中定义的ID  比如<div id="pdfDom">  这个也要避下雷
+  const element = document.getElementById('pdfDom')
+  window.pageYoffset = 0
+  document.documentElement.scrollTop = 0
+  document.body.scrollTop = 0
+  setTimeout(() => {
+    // const nowDate = new Date();
+    // const date = {
+    //   year: nowDate.getFullYear(),
+    //   month: nowDate.getMonth() + 1,
+    //   date: nowDate.getDate(),
+    //   hours: nowDate.getHours(),
+    //   minutes: nowDate.getMinutes(),
+    //   seconds: nowDate.getSeconds(),
+    // };
+    // const newMonth = date.month > 10 ? date.month : "0" + date.month;
+    // const newDay = date.date > 10 ? date.date : "0" + date.date;
+    // const newMinutes = date.minutes < 10 ? "0" + date.minutes : date.minutes;
+    // const newSeconds = date.seconds < 10 ? "0" + date.seconds : date.seconds;
+    // const value = date.year + newMonth + newDay + date.hours + newMinutes + newSeconds;
+    let id = ''
+    //创建一个画布    ---  增加导出的pdf水印 !!
+    let can = document.createElement('canvas')
+    //设置画布的长宽
+    can.width = 400
+    can.height = 500
+    let cans = can.getContext('2d')
+    //旋转角度
+    cans.rotate((-15 * Math.PI) / 180)
+    cans.font = '18px Vedana'
+    //设置填充绘画的颜色、渐变或者模式
+    cans.fillStyle = 'rgba(200, 200, 200, 0.40)'
+    //设置文本内容的当前对齐方式
+    cans.textAlign = 'left'
+    //设置在绘制文本时使用的当前文本基线
+    cans.textBaseline = 'Middle'
+    //在画布上绘制填色的文本(输出的文本,开始绘制文本的X坐标位置,开始绘制文本的Y坐标位置)
+    //cans.fillText(value, can.width / 8, can.height / 2)
+    let div = document.createElement('div')
+    div.id = id
+    div.style.pointerEvents = 'none'
+    div.style.top = '2000px'
+    div.style.left = '-2000px'
+    div.style.position = 'fixed'
+    div.style.zIndex = '100000'
+    div.style.width = document.getElementById('pdfDom').scrollHeight + 'px'
+    div.style.height = document.getElementById('pdfDom').scrollHeight + 'px'
+    div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat'
+    document.getElementById('pdfDom').appendChild(div) // 到页面中
+    html2Canvas(element, {
+      allowTaint: true,
+      useCORS: true, // 需要注意,element的 高度 宽度一定要在这里定义一下,不然会存在只下载了当前你能看到的页面   避雷避雷!!!
+      scale: 2, // 提升画面质量,但是会增加文件大小
+      height: document.getElementById('pdfDom').scrollHeight,
+      windowHeight: document.getElementById('pdfDom').scrollHeight
+    }).then(function (canvas) {
+      var contentWidth = canvas.width
+      var contentHeight = canvas.height
+      // 一页pdf显示html页面生成的canvas高度;
+      var pageHeight = (contentWidth * 841.89) / 592.28
+      // 未生成pdf的html页面高度
+      var leftHeight = contentHeight
+      // 页面偏移
+      var position = 0
+      // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
+      var imgWidth = 595.28
+      var imgHeight = (592.28 / contentWidth) * contentHeight
+      var pageData = canvas.toDataURL('image/jpeg', 1.0)
+      var pdf = new JsPDF('', 'pt', 'a4')
+      // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
+      // 当内容未超过pdf一页显示的范围,无需分页
+      if (leftHeight < pageHeight) {
+        pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
+      } else {
+        while (leftHeight > 0) {
+          pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
+          leftHeight -= pageHeight
+          position -= 841.89
+          // 避免添加空白页
+          if (leftHeight > 0) {
+            pdf.addPage()
+          }
+        }
+      }
+      pdf.save(title + '.pdf')
+    })
+  }, 1000)
+}

+ 40 - 7
jy-ui/src/views/business/payment/remit/index.vue

@@ -14,6 +14,8 @@ import {
 import { getPageApi as getCorporationPageApi } from '@/api/business/corporation/corporation'
 import DeptTreeSelect from '@/views/components/DeptTreeSelect/index.vue'
 import { getPageApi as getCapitalAccountPageApi } from '@/api/business/capital/account'
+import MoneyPDF from '@/components/PDF/moneyPDF.vue'
+import { getPdf } from '@/utils/getPdf.js'
 
 const queryRef = ref<InstanceType<typeof AForm>>()
 const formRef = ref<InstanceType<typeof AForm>>()
@@ -34,6 +36,9 @@ const selectDeptIdRef = ref<InstanceType<typeof DeptTreeSelect>>()
 
 const disabled = ref(false)
 
+const dialogPrint = ref<boolean>(false)
+const rowData = ref<StrAnyObj>({})
+
 const queryConfig: FormConfigType[] = [
   {
     type: 'select',
@@ -98,13 +103,13 @@ const toolbarConfig: ToolbarConfigType[] = [
       queryRef.value?.resetFields()
       getPage()
     }
-  },
-  {
-    common: 'add',
-    click() {
-      dialogVisible.value = true
-      dialogTitle.value = '新增'
-    }
+  // },
+  // {
+  //   common: 'add',
+  //   click() {
+  //     dialogVisible.value = true
+  //     dialogTitle.value = '新增'
+  //   }
   }
 ]
 
@@ -186,6 +191,13 @@ const columnConfig: ColumnConfigType[] = [
             detailData.value = resp
           })
         }
+      },
+      {
+        text: '打印',
+        click(row) {
+          rowData.value = row
+          dialogPrint.value = true
+        }
       }
     ]
   }
@@ -348,6 +360,16 @@ function formSubmit() {
 function formClosed() {
   formRef.value?.resetFields()
 }
+const printObj = ref({
+  id: 'pdfDom',
+  popTitle: '',
+  extraCss:
+    'https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css',
+  extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>'
+})
+const clickDownload = () => {
+  getPdf('请款PDF文件')
+}
 </script>
 
 <template>
@@ -393,5 +415,16 @@ function formClosed() {
         <a-form ref="formRef" v-model="formData" :config="formConfig" :span="12"> </a-form>
       </el-card>
     </a-dialog>
+
+    <a-dialog :footer="false" v-model="dialogPrint" title="打印" width="840px" height="200px">
+      <MoneyPDF :rowData="rowData"></MoneyPDF>
+      <template #footer>
+        <div>
+          <el-button @click="dialogPrint = false" size="large">取消</el-button>
+          <el-button type="primary" v-print="printObj" size="large">打印</el-button>
+          <el-button type="primary" @click="clickDownload()" size="large">下载PDF</el-button>
+        </div>
+      </template>
+    </a-dialog>
   </div>
 </template>

+ 33 - 0
jy-ui/src/views/business/payment/requests/index.vue

@@ -17,6 +17,8 @@ import DeptTreeSelect from '@/views/components/DeptTreeSelect/index.vue'
 import { getPageApi as getCapitalAccountPageApi } from '@/api/business/capital/account'
 import FileUpload from '@/components/FlieUpload/index.vue'
 import { getDictByCode } from '@/utils/dict'
+import MoneyPDF from '@/components/PDF/moneyPDF.vue'
+import { getPdf } from '@/utils/getPdf.js'
 
 const queryRef = ref<InstanceType<typeof AForm>>()
 const formRef = ref<InstanceType<typeof AForm>>()
@@ -32,6 +34,9 @@ const formData = ref<StrAnyObj>({ paymentRequestsDetailList: [{}] })
 const dialogTitle = ref<string>('')
 const dialogVisible = ref<boolean>(false)
 
+const dialogPrint = ref<boolean>(false)
+const rowData = ref<StrAnyObj>({})
+
 const deptIdRef = ref<InstanceType<typeof DeptTreeSelect>>()
 const selectDeptIdRef = ref<InstanceType<typeof DeptTreeSelect>>()
 
@@ -239,6 +244,13 @@ const columnConfig: ColumnConfigType[] = [
             formData.value = resp
           })
         }
+      },
+      {
+        text: '打印',
+        click(row) {
+          rowData.value = row
+          dialogPrint.value = true
+        }
       }
     ]
   }
@@ -478,6 +490,16 @@ function updateAmount() {
 
   updateDetailRemark()
 }
+const printObj = ref({
+  id: 'pdfDom',
+  popTitle: '',
+  extraCss:
+    'https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css',
+  extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>'
+})
+const clickDownload = () => {
+  getPdf('请款PDF文件')
+}
 </script>
 
 <template>
@@ -561,5 +583,16 @@ function updateAmount() {
         </template>
       </a-form>
     </a-dialog>
+
+    <a-dialog :footer="false" v-model="dialogPrint" title="打印" width="840px" height="200px">
+      <MoneyPDF :rowData="rowData"></MoneyPDF>
+      <template #footer>
+        <div>
+          <el-button @click="dialogPrint = false" size="large">取消</el-button>
+          <el-button type="primary" v-print="printObj" size="large">打印</el-button>
+          <el-button type="primary" @click="clickDownload()" size="large">下载PDF</el-button>
+        </div>
+      </template>
+    </a-dialog>
   </div>
 </template>