|
|
<template>
|
|
|
<div>
|
|
|
|
|
|
<xy-dialog title="打印预览" :is-show.sync="isShow" :width="90" ok-text="打印" @on-ok="printHtml">
|
|
|
<template v-slot:normalContent>
|
|
|
<div style="position: relative; margin-bottom: 16px; min-height: 40px;">
|
|
|
<div style="width: fit-content; margin: 0 auto;">
|
|
|
<RadioGroup v-model="currentForm" type="button">
|
|
|
<!-- <Radio label="pre" :disabled="!getBeforeForms">事前审批表格</Radio> -->
|
|
|
<!-- <Radio label="finance" :disabled="!fundLog">财务审核表</Radio> -->
|
|
|
<Radio label="post" :disabled="!getForms">事后支付表格</Radio>
|
|
|
</RadioGroup>
|
|
|
</div>
|
|
|
<div style="position: absolute; right: 0; top: 0;">
|
|
|
<label>打印方向:</label>
|
|
|
<select v-model="printOrientation" style="margin-right: 16px;">
|
|
|
<option value="portrait">纵向</option>
|
|
|
<option value="landscape">横向</option>
|
|
|
</select>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="white-container">
|
|
|
<div class="form-container">
|
|
|
<!-- Pre-payment Form -->
|
|
|
<div v-if="currentForm === 'pre'" class="payment-form">
|
|
|
<div v-if="getBeforeForms" v-html="getBeforeForms" />
|
|
|
<div v-else class="no-form-message">暂无事前审批表格内容</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- Post-payment Form -->
|
|
|
<div v-else-if="currentForm === 'post'" ref="printtable" class="payment-form">
|
|
|
<!-- 财务审核表内容放到事后支付表头部 -->
|
|
|
<table class="finance-review-table no-print">
|
|
|
<tr>
|
|
|
<th colspan="2" class="finance-header-row">合同信息</th>
|
|
|
<th colspan="5" class="finance-header-row">付款信息</th>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
<td class="sub-header">受款单位</td>
|
|
|
<td>{{ fundLog && fundLog.contract && fundLog.contract.supply || '-' }}</td>
|
|
|
<td class="sub-header">申请付款金额</td>
|
|
|
<td>{{ fundLog && fundLog.apply_money || '-' }}</td>
|
|
|
<td class="sub-header">实际支付金额</td>
|
|
|
<td>{{ fundLog && fundLog.act_money || '-' }}</td>
|
|
|
<td class="sub-header">款项类型</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
<td class="sub-header">合同名称</td>
|
|
|
<td>{{ fundLog && fundLog.contract && fundLog.contract.name || '-' }}</td>
|
|
|
<td class="sub-header">审计金额</td>
|
|
|
<td>{{ fundLog && fundLog.audit_money || '-' }}</td>
|
|
|
<td class="sub-header">本期扣款金额</td>
|
|
|
<td>{{ fundLog && fundLog.discount_money || '-' }}</td>
|
|
|
<td>{{ fundLog && fundLog.type || '-' }}</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
<td class="sub-header">合同金额</td>
|
|
|
<td>{{ fundLog && fundLog.contract && moneyFormat(fundLog.contract.money) || '-' }} (元)</td>
|
|
|
<td class="sub-header">是否为最后一笔</td>
|
|
|
<td>{{ fundLog && fundLog.is_end === 1 ? '是' : '否' }}</td>
|
|
|
<td class="sub-header">备注</td>
|
|
|
<td colspan="2">{{ fundLog && fundLog.remark || '-' }}</td>
|
|
|
</tr>
|
|
|
</table>
|
|
|
<div v-if="getForms" v-html="getForms" />
|
|
|
<div v-else class="no-form-message">暂无事后支付表格内容</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
</xy-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import { detailFundLog } from '@/api/paymentRegistration/fundLog'
|
|
|
import html2canvas from 'html2canvas'
|
|
|
import * as printJS from 'print-js'
|
|
|
|
|
|
// 添加金额转大写的工具函数
|
|
|
function numberToChinese(num) {
|
|
|
const units = ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟', '万']
|
|
|
const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
|
|
|
const [integer, decimal] = num.toString().split('.')
|
|
|
let result = ''
|
|
|
let intNum = parseInt(integer)
|
|
|
if (intNum === 0) {
|
|
|
result = '零'
|
|
|
} else {
|
|
|
let i = 0
|
|
|
let lastDigit = null
|
|
|
let hasZero = false
|
|
|
while (intNum > 0) {
|
|
|
const digit = intNum % 10
|
|
|
if (digit === 0) {
|
|
|
if (!hasZero && lastDigit !== 0) {
|
|
|
result = '零' + result
|
|
|
hasZero = true
|
|
|
}
|
|
|
} else {
|
|
|
let unit = units[i]
|
|
|
if (i === 4 && result.startsWith('零')) {
|
|
|
unit = '万'
|
|
|
} else if (i === 8 && result.startsWith('零')) {
|
|
|
unit = '亿'
|
|
|
}
|
|
|
result = digits[digit] + unit + result
|
|
|
hasZero = false
|
|
|
}
|
|
|
lastDigit = digit
|
|
|
intNum = Math.floor(intNum / 10)
|
|
|
i++
|
|
|
}
|
|
|
result = result.replace(/零+$/, '')
|
|
|
result = result.replace(/零+/, '零')
|
|
|
}
|
|
|
if (decimal) {
|
|
|
const decimalNum = parseInt(decimal)
|
|
|
if (decimalNum > 0) {
|
|
|
result += '点'
|
|
|
for (let i = 0; i < decimal.length; i++) {
|
|
|
result += digits[parseInt(decimal[i])]
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (!decimal || parseInt(decimal) === 0) {
|
|
|
result += '整'
|
|
|
}
|
|
|
return result + '元'
|
|
|
}
|
|
|
|
|
|
export default {
|
|
|
name: 'PrintPaymentForm',
|
|
|
data() {
|
|
|
return {
|
|
|
isShow: false,
|
|
|
currentForm: 'post',
|
|
|
fundLog: null,
|
|
|
printOrientation: 'portrait' // 默认横向
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
getBeforeForms() {
|
|
|
return this.fundLog && this.fundLog.contract && this.fundLog.contract.before_forms
|
|
|
},
|
|
|
getForms() {
|
|
|
return this.fundLog && this.fundLog.contract && this.fundLog.contract.forms
|
|
|
}
|
|
|
},
|
|
|
watch: {
|
|
|
getForms: {
|
|
|
handler(newVal) {
|
|
|
if (newVal) {
|
|
|
this.$nextTick(() => {
|
|
|
this.setupAmountListeners()
|
|
|
})
|
|
|
}
|
|
|
},
|
|
|
immediate: true
|
|
|
},
|
|
|
isShow: {
|
|
|
handler(newVal) {
|
|
|
if (newVal) {
|
|
|
this.$nextTick(() => {
|
|
|
this.setupAmountListeners()
|
|
|
})
|
|
|
}
|
|
|
},
|
|
|
immediate: true
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
async getDetailFundLog(id) {
|
|
|
try {
|
|
|
const res = await detailFundLog({ id })
|
|
|
this.fundLog = res
|
|
|
} catch (error) {
|
|
|
console.error('获取付款详情失败:', error)
|
|
|
this.$Message.error('获取付款详情失败')
|
|
|
}
|
|
|
},
|
|
|
setupAmountListeners() {
|
|
|
const dom = this.$refs.printtable
|
|
|
if (!dom) return
|
|
|
|
|
|
const sdateAmountInputs = dom.querySelectorAll('input[data-field^="sdate"]')
|
|
|
// 移除旧的监听器
|
|
|
sdateAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.caculateRoadDay)
|
|
|
input.removeEventListener('change', this.caculateRoadDay)
|
|
|
input.removeEventListener('blur', this.caculateRoadDay)
|
|
|
})
|
|
|
|
|
|
// 添加新的监听器
|
|
|
sdateAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.caculateRoadDay)
|
|
|
input.addEventListener('change', this.caculateRoadDay)
|
|
|
input.addEventListener('blur', this.caculateRoadDay)
|
|
|
})
|
|
|
|
|
|
const edateAmountInputs = dom.querySelectorAll('input[data-field^="edate"]')
|
|
|
// 移除旧的监听器
|
|
|
edateAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.caculateRoadDay)
|
|
|
input.removeEventListener('change', this.caculateRoadDay)
|
|
|
input.removeEventListener('blur', this.caculateRoadDay)
|
|
|
})
|
|
|
|
|
|
// 添加新的监听器
|
|
|
edateAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.caculateRoadDay)
|
|
|
input.addEventListener('change', this.caculateRoadDay)
|
|
|
input.addEventListener('blur', this.caculateRoadDay)
|
|
|
})
|
|
|
|
|
|
// 获取所有以 wan 开头的输入框
|
|
|
const wanAmountInputs = dom.querySelectorAll('input[data-field^="wan"]')
|
|
|
// 移除旧的监听器
|
|
|
wanAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.calculateTotal)
|
|
|
input.removeEventListener('change', this.calculateTotal)
|
|
|
input.removeEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 添加新的监听器
|
|
|
wanAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.calculateTotal)
|
|
|
input.addEventListener('change', this.calculateTotal)
|
|
|
input.addEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
|
|
|
// 获取所有以 qian 开头的输入框
|
|
|
const qianAmountInputs = dom.querySelectorAll('input[data-field^="qian"]')
|
|
|
// 移除旧的监听器
|
|
|
qianAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.calculateTotal)
|
|
|
input.removeEventListener('change', this.calculateTotal)
|
|
|
input.removeEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 添加新的监听器
|
|
|
qianAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.calculateTotal)
|
|
|
input.addEventListener('change', this.calculateTotal)
|
|
|
input.addEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 获取所有以 bai 开头的输入框
|
|
|
const baiAmountInputs = dom.querySelectorAll('input[data-field^="bai"]')
|
|
|
// 移除旧的监听器
|
|
|
baiAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.calculateTotal)
|
|
|
input.removeEventListener('change', this.calculateTotal)
|
|
|
input.removeEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 添加新的监听器
|
|
|
baiAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.calculateTotal)
|
|
|
input.addEventListener('change', this.calculateTotal)
|
|
|
input.addEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 获取所有以 shi 开头的输入框
|
|
|
const shiAmountInputs = dom.querySelectorAll('input[data-field^="shi"]')
|
|
|
// 移除旧的监听器
|
|
|
shiAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.calculateTotal)
|
|
|
input.removeEventListener('change', this.calculateTotal)
|
|
|
input.removeEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 添加新的监听器
|
|
|
shiAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.calculateTotal)
|
|
|
input.addEventListener('change', this.calculateTotal)
|
|
|
input.addEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 获取所有以 yuan 开头的输入框
|
|
|
const yuanAmountInputs = dom.querySelectorAll('input[data-field^="yuan"]')
|
|
|
// 移除旧的监听器
|
|
|
yuanAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.calculateTotal)
|
|
|
input.removeEventListener('change', this.calculateTotal)
|
|
|
input.removeEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
// 添加新的监听器
|
|
|
yuanAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.calculateTotal)
|
|
|
input.addEventListener('change', this.calculateTotal)
|
|
|
input.addEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 获取所有以 jiao 开头的输入框
|
|
|
const jiaoAmountInputs = dom.querySelectorAll('input[data-field^="jiao"]')
|
|
|
// 移除旧的监听器
|
|
|
jiaoAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.calculateTotal)
|
|
|
input.removeEventListener('change', this.calculateTotal)
|
|
|
input.removeEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
// 添加新的监听器
|
|
|
jiaoAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.calculateTotal)
|
|
|
input.addEventListener('change', this.calculateTotal)
|
|
|
input.addEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 获取所有以 fen 开头的输入框
|
|
|
const fenAmountInputs = dom.querySelectorAll('input[data-field^="fen"]')
|
|
|
// 移除旧的监听器
|
|
|
fenAmountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.calculateTotal)
|
|
|
input.removeEventListener('change', this.calculateTotal)
|
|
|
input.removeEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
// 添加新的监听器
|
|
|
fenAmountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.calculateTotal)
|
|
|
input.addEventListener('change', this.calculateTotal)
|
|
|
input.addEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 获取所有以 amount 开头的输入框
|
|
|
const amountInputs = dom.querySelectorAll('input[data-field^="amount"]')
|
|
|
console.log('找到的金额输入框:', amountInputs.length)
|
|
|
|
|
|
// 移除旧的监听器
|
|
|
amountInputs.forEach(input => {
|
|
|
input.removeEventListener('input', this.calculateTotal)
|
|
|
input.removeEventListener('change', this.calculateTotal)
|
|
|
input.removeEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 添加新的监听器
|
|
|
amountInputs.forEach(input => {
|
|
|
input.addEventListener('input', this.calculateTotal)
|
|
|
input.addEventListener('change', this.calculateTotal)
|
|
|
input.addEventListener('blur', this.calculateTotal)
|
|
|
})
|
|
|
|
|
|
// 监听 total 输入框的变化
|
|
|
const totalInput = dom.querySelector('input[data-field="total"]')
|
|
|
if (totalInput) {
|
|
|
totalInput.removeEventListener('input', this.updateUpperCaseFromTotal)
|
|
|
totalInput.removeEventListener('change', this.updateUpperCaseFromTotal)
|
|
|
totalInput.removeEventListener('blur', this.updateUpperCaseFromTotal)
|
|
|
|
|
|
totalInput.addEventListener('input', this.updateUpperCaseFromTotal)
|
|
|
totalInput.addEventListener('change', this.updateUpperCaseFromTotal)
|
|
|
totalInput.addEventListener('blur', this.updateUpperCaseFromTotal)
|
|
|
}
|
|
|
|
|
|
// 初始计算一次
|
|
|
this.calculateTotal()
|
|
|
},
|
|
|
caculateRoadDay() {
|
|
|
const sdateInput = this.$refs.printtable.querySelector('input[data-field^="sdate"]')
|
|
|
const edateInput = this.$refs.printtable.querySelector('input[data-field^="edate"]')
|
|
|
const sdate = sdateInput.value
|
|
|
const edate = edateInput.value
|
|
|
if (sdate && edate) {
|
|
|
const s = new Date(sdate)
|
|
|
const e = new Date(edate)
|
|
|
// 计算天数差
|
|
|
const roadDay = Math.floor((e - s) / (1000 * 60 * 60 * 24)) + 1
|
|
|
console.log('roadDay', sdate, edate, roadDay)
|
|
|
const roadDayInput = this.$refs.printtable.querySelector('input[data-field="roadDay"]')
|
|
|
if (roadDayInput) {
|
|
|
roadDayInput.value = roadDay
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
calculateTotal() {
|
|
|
const dom = this.$refs.printtable
|
|
|
if (!dom) return
|
|
|
let wanTotal = 0
|
|
|
const wanAmountInputs = dom.querySelectorAll('input[data-field^="wan"]')
|
|
|
wanAmountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
wanTotal += value
|
|
|
})
|
|
|
|
|
|
const wanInput = dom.querySelector('input[data-field="wTotal"]')
|
|
|
if (wanInput) {
|
|
|
wanInput.value = wanTotal===0?'0':wanTotal
|
|
|
}
|
|
|
|
|
|
let qianTotal = 0
|
|
|
const qianAmountInputs = dom.querySelectorAll('input[data-field^="qian"]')
|
|
|
qianAmountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
qianTotal += value
|
|
|
})
|
|
|
|
|
|
const qianInput = dom.querySelector('input[data-field="qTotal"]')
|
|
|
if (qianInput) {
|
|
|
qianInput.value = qianTotal===0?'0':qianTotal
|
|
|
}
|
|
|
|
|
|
let baiTotal = 0
|
|
|
const baiAmountInputs = dom.querySelectorAll('input[data-field^="bai"]')
|
|
|
baiAmountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
baiTotal += value
|
|
|
})
|
|
|
|
|
|
const baiInput = dom.querySelector('input[data-field="bTotal"]')
|
|
|
if (baiInput) {
|
|
|
baiInput.value = baiTotal===0?'0':baiTotal
|
|
|
}
|
|
|
|
|
|
let shiTotal = 0
|
|
|
const shiAmountInputs = dom.querySelectorAll('input[data-field^="shi"]')
|
|
|
shiAmountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
shiTotal += value
|
|
|
})
|
|
|
|
|
|
const shiInput = dom.querySelector('input[data-field="sTotal"]')
|
|
|
if (shiInput) {
|
|
|
shiInput.value = shiTotal===0?'0':shiTotal
|
|
|
}
|
|
|
|
|
|
let yuanTotal = 0
|
|
|
const yuanAmountInputs = dom.querySelectorAll('input[data-field^="yuan"]')
|
|
|
yuanAmountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
yuanTotal += value
|
|
|
})
|
|
|
|
|
|
const yuanInput = dom.querySelector('input[data-field="yTotal"]')
|
|
|
if (yuanInput) {
|
|
|
yuanInput.value = yuanTotal===0?'0':yuanTotal
|
|
|
}
|
|
|
|
|
|
let jiaoTotal = 0
|
|
|
const jiaoAmountInputs = dom.querySelectorAll('input[data-field^="jiao"]')
|
|
|
jiaoAmountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
jiaoTotal += value
|
|
|
})
|
|
|
|
|
|
const jiaoInput = dom.querySelector('input[data-field="jTotal"]')
|
|
|
if (jiaoInput) {
|
|
|
jiaoInput.value = jiaoTotal===0?'0':jiaoTotal
|
|
|
}
|
|
|
|
|
|
let fenTotal = 0
|
|
|
const fenAmountInputs = dom.querySelectorAll('input[data-field^="fen"]')
|
|
|
fenAmountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
fenTotal += value
|
|
|
})
|
|
|
|
|
|
const fenInput = dom.querySelector('input[data-field="fTotal"]')
|
|
|
if (fenInput) {
|
|
|
fenInput.value = fenTotal===0?'0':fenTotal
|
|
|
}
|
|
|
|
|
|
// 统计各位后,进行进位处理
|
|
|
if (fenTotal >= 10) {
|
|
|
jiaoTotal += Math.floor(fenTotal / 10);
|
|
|
fenTotal = fenTotal % 10;
|
|
|
}
|
|
|
if (jiaoTotal >= 10) {
|
|
|
yuanTotal += Math.floor(jiaoTotal / 10);
|
|
|
jiaoTotal = jiaoTotal % 10;
|
|
|
}
|
|
|
if (yuanTotal >= 10) {
|
|
|
shiTotal += Math.floor(yuanTotal / 10);
|
|
|
yuanTotal = yuanTotal % 10;
|
|
|
}
|
|
|
if (shiTotal >= 10) {
|
|
|
baiTotal += Math.floor(shiTotal / 10);
|
|
|
shiTotal = shiTotal % 10;
|
|
|
}
|
|
|
if (baiTotal >= 10) {
|
|
|
qianTotal += Math.floor(baiTotal / 10);
|
|
|
baiTotal = baiTotal % 10;
|
|
|
}
|
|
|
if (qianTotal >= 10) {
|
|
|
wanTotal += Math.floor(qianTotal / 10);
|
|
|
qianTotal = qianTotal % 10;
|
|
|
}
|
|
|
|
|
|
// 进位后同步更新input显示
|
|
|
// 通用解决方案:根据实际数值决定是否显示前导零
|
|
|
const totalAmount = wanTotal * 10000 + qianTotal * 1000 + baiTotal * 100 + shiTotal * 10 + yuanTotal + jiaoTotal * 0.1 + fenTotal * 0.01;
|
|
|
|
|
|
if (wanInput) {
|
|
|
// 如果总金额小于10000,不显示万位
|
|
|
wanInput.value = totalAmount >= 10000 ? (wanTotal === 0 ? '0' : wanTotal) : '';
|
|
|
}
|
|
|
if (qianInput) {
|
|
|
// 如果总金额小于1000,不显示千位
|
|
|
qianInput.value = totalAmount >= 1000 ? (qianTotal === 0 ? '0' : qianTotal) : '';
|
|
|
}
|
|
|
if (baiInput) {
|
|
|
// 如果总金额小于100,不显示百位
|
|
|
baiInput.value = totalAmount >= 100 ? (baiTotal === 0 ? '0' : baiTotal) : '';
|
|
|
}
|
|
|
if (shiInput) {
|
|
|
// 如果总金额小于10,不显示十位
|
|
|
shiInput.value = totalAmount >= 10 ? (shiTotal === 0 ? '0' : shiTotal) : '';
|
|
|
}
|
|
|
if (yuanInput) {
|
|
|
// 如果总金额小于1,不显示元位
|
|
|
yuanInput.value = totalAmount >= 1 ? (yuanTotal === 0 ? '0' : yuanTotal) : '';
|
|
|
}
|
|
|
if (jiaoInput) {
|
|
|
// 如果总金额小于0.1,不显示角位
|
|
|
jiaoInput.value = totalAmount >= 0.1 ? (jiaoTotal === 0 ? '0' : jiaoTotal) : '';
|
|
|
}
|
|
|
if (fenInput) {
|
|
|
// 如果总金额小于0.01,不显示分位
|
|
|
fenInput.value = totalAmount >= 0.01 ? (fenTotal === 0 ? '0' : fenTotal) : '';
|
|
|
}
|
|
|
|
|
|
let otherTotal = wanTotal * 10000 + qianTotal * 1000 + baiTotal * 100 + shiTotal * 10 + yuanTotal + jiaoTotal * 0.1 + fenTotal * 0.01
|
|
|
|
|
|
let total = 0
|
|
|
// 只计算以 amount 开头的输入框
|
|
|
const amountInputs = dom.querySelectorAll('input[data-field^="amount"]')
|
|
|
console.log('计算总金额,找到输入框数量:', amountInputs.length)
|
|
|
|
|
|
amountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
console.log('输入框值:', input.getAttribute('data-field'), value)
|
|
|
total += value
|
|
|
})
|
|
|
|
|
|
console.log('计算得到的总金额:', total)
|
|
|
|
|
|
// 更新总金额输入框
|
|
|
const totalInput = dom.querySelector('input[data-field="total"]')
|
|
|
if (totalInput) {
|
|
|
totalInput.value = total.toFixed(2)
|
|
|
console.log('更新总金额输入框:', totalInput.value)
|
|
|
}
|
|
|
|
|
|
// 更新大写金额
|
|
|
const upperCaseInput = dom.querySelector('input[data-field="upperCaseAmount"]')
|
|
|
if (upperCaseInput) {
|
|
|
upperCaseInput.value = numberToChinese(total)
|
|
|
console.log('更新大写金额:', upperCaseInput.value)
|
|
|
}
|
|
|
|
|
|
if (otherTotal !== 0) {
|
|
|
upperCaseInput.value = numberToChinese(otherTotal)
|
|
|
}
|
|
|
},
|
|
|
updateUpperCaseFromTotal() {
|
|
|
const dom = this.$refs.printtable
|
|
|
if (!dom) return
|
|
|
|
|
|
const totalInput = dom.querySelector('input[data-field="total"]')
|
|
|
const upperCaseInput = dom.querySelector('input[data-field="upperCaseAmount"]')
|
|
|
|
|
|
if (totalInput && upperCaseInput) {
|
|
|
const total = parseFloat(totalInput.value) || 0
|
|
|
upperCaseInput.value = numberToChinese(total)
|
|
|
console.log('从总金额更新大写金额:', total, upperCaseInput.value)
|
|
|
}
|
|
|
},
|
|
|
replaceControls(element) {
|
|
|
const inputs = element.getElementsByTagName('input')
|
|
|
Array.from(inputs).forEach(input => {
|
|
|
if (input.type === 'checkbox' || input.type === 'radio') {
|
|
|
if (input.type === 'radio') {
|
|
|
// 找到同组radio中被选中的
|
|
|
const name = input.name
|
|
|
const checkedRadio = element.querySelector(`input[type="radio"][name="${name}"]:checked`)
|
|
|
if (checkedRadio) {
|
|
|
// 找到包含radio组的td
|
|
|
const td = checkedRadio.closest('td')
|
|
|
if (td) {
|
|
|
// 找到隐藏的div
|
|
|
const hiddenDiv = td.querySelector('div[style*="display: none"]')
|
|
|
if (hiddenDiv) {
|
|
|
hiddenDiv.textContent = checkedRadio.value
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
const span = document.createElement('span')
|
|
|
let displayText = input.value || ''
|
|
|
if (input.type === 'date') {
|
|
|
displayText = input.value ? new Date(input.value).toLocaleDateString() : ''
|
|
|
}
|
|
|
span.textContent = displayText
|
|
|
const style = window.getComputedStyle(input)
|
|
|
// 先复制所有样式
|
|
|
span.style.cssText = style.cssText
|
|
|
;[
|
|
|
'width',
|
|
|
'height',
|
|
|
'padding',
|
|
|
'margin',
|
|
|
'font',
|
|
|
'fontSize',
|
|
|
'fontFamily',
|
|
|
'lineHeight',
|
|
|
'verticalAlign',
|
|
|
'border',
|
|
|
'background',
|
|
|
'color',
|
|
|
'boxSizing'
|
|
|
].forEach(key => {
|
|
|
span.style[key] = style[key]
|
|
|
})
|
|
|
// 确保width和height与Input控件保持一致
|
|
|
span.style.width = style.width//'100%'
|
|
|
span.style.height = style.height
|
|
|
span.style.whiteSpace = 'normal'
|
|
|
span.style.wordBreak = 'break-all'
|
|
|
span.style.overflowWrap = 'break-word'
|
|
|
span.style.display = 'block'
|
|
|
span.style.textAlign = 'center'
|
|
|
span.style.verticalAlign = 'middle'
|
|
|
input.parentNode.replaceChild(span, input)
|
|
|
})
|
|
|
|
|
|
const selects = element.getElementsByTagName('select')
|
|
|
Array.from(selects).forEach(select => {
|
|
|
const span = document.createElement('span')
|
|
|
span.textContent = select.options[select.selectedIndex]?.text || ''
|
|
|
const style = window.getComputedStyle(select)
|
|
|
// 先复制所有样式
|
|
|
span.style.cssText = style.cssText
|
|
|
;[
|
|
|
'width',
|
|
|
'height',
|
|
|
'padding',
|
|
|
'margin',
|
|
|
'font',
|
|
|
'fontSize',
|
|
|
'fontFamily',
|
|
|
'lineHeight',
|
|
|
'verticalAlign',
|
|
|
'border',
|
|
|
'background',
|
|
|
'color',
|
|
|
'boxSizing'
|
|
|
].forEach(key => {
|
|
|
span.style[key] = style[key]
|
|
|
})
|
|
|
// 确保width和height与select控件保持一致
|
|
|
span.style.width = style.width
|
|
|
span.style.height = style.height
|
|
|
span.style.display = 'block'
|
|
|
span.style.textAlign = 'center'
|
|
|
span.style.whiteSpace = 'pre-line' // 关键:自动换行
|
|
|
select.parentNode.replaceChild(span, select)
|
|
|
})
|
|
|
|
|
|
const textareas = element.getElementsByTagName('textarea')
|
|
|
Array.from(textareas).forEach(textarea => {
|
|
|
const span = document.createElement('span')
|
|
|
span.textContent = textarea.value || ''
|
|
|
const style = window.getComputedStyle(textarea)
|
|
|
// 先复制所有样式
|
|
|
span.style.cssText = style.cssText
|
|
|
;[
|
|
|
'width',
|
|
|
'height',
|
|
|
'padding',
|
|
|
'margin',
|
|
|
'font',
|
|
|
'fontSize',
|
|
|
'fontFamily',
|
|
|
'lineHeight',
|
|
|
'verticalAlign',
|
|
|
'border',
|
|
|
'background',
|
|
|
'color',
|
|
|
'boxSizing'
|
|
|
].forEach(key => {
|
|
|
span.style[key] = style[key]
|
|
|
})
|
|
|
// 确保width和height与textarea控件保持一致
|
|
|
span.style.width = style.width
|
|
|
span.style.height = style.height
|
|
|
span.style.display = 'block'
|
|
|
span.style.textAlign = 'center'
|
|
|
span.style.whiteSpace = 'pre-line' // 关键:自动换行
|
|
|
textarea.parentNode.replaceChild(span, textarea)
|
|
|
})
|
|
|
},
|
|
|
async print() {
|
|
|
try {
|
|
|
const tempContainer = document.createElement('div')
|
|
|
tempContainer.style.position = 'absolute'
|
|
|
tempContainer.style.left = '-9999px'
|
|
|
tempContainer.style.top = '-9999px'
|
|
|
document.body.appendChild(tempContainer)
|
|
|
|
|
|
const originalContent = this.$refs['printtable'].cloneNode(true)
|
|
|
tempContainer.appendChild(originalContent)
|
|
|
|
|
|
this.replaceControls(tempContainer)
|
|
|
|
|
|
const canvas = await html2canvas(tempContainer, {
|
|
|
backgroundColor: null,
|
|
|
useCORS: true
|
|
|
})
|
|
|
|
|
|
document.body.removeChild(tempContainer)
|
|
|
|
|
|
printJS({
|
|
|
printable: canvas.toDataURL(),
|
|
|
type: 'image',
|
|
|
documentTitle: `苏州市河道管理处${this.currentForm === 'pre' ? '事前审批表格' : this.currentForm === 'post' ? '事后支付表格' : '财务审核表'}`,
|
|
|
style: '@page{margin:auto;}'
|
|
|
})
|
|
|
} catch (error) {
|
|
|
console.error('打印失败:', error)
|
|
|
this.$Message.error('打印失败')
|
|
|
}
|
|
|
},
|
|
|
moneyFormat(val) {
|
|
|
if (!val && val !== 0) return '-'
|
|
|
return Number(val).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
|
|
|
},
|
|
|
printHtml() {
|
|
|
// 先同步用户输入到HTML
|
|
|
const dom = this.$refs.printtable
|
|
|
if (dom) {
|
|
|
// 获取所有输入控件
|
|
|
const inputs = dom.querySelectorAll('input, select, textarea')
|
|
|
inputs.forEach(input => {
|
|
|
const fieldName = input.getAttribute('data-field')
|
|
|
if (fieldName) {
|
|
|
if (input.type === 'checkbox' || input.type === 'radio') {
|
|
|
// 对于复选框和单选框,需要找到选中的值
|
|
|
const checkedInput = dom.querySelector(`[data-field="${fieldName}"]:checked`)
|
|
|
if (checkedInput) {
|
|
|
// 找到同组的所有radio
|
|
|
const name = checkedInput.name
|
|
|
const radioGroup = dom.querySelectorAll(`input[type="radio"][name="${name}"]`)
|
|
|
radioGroup.forEach(radio => {
|
|
|
// 移除所有radio的checked属性
|
|
|
radio.removeAttribute('checked')
|
|
|
})
|
|
|
// 设置选中radio的checked属性
|
|
|
checkedInput.setAttribute('checked', 'checked')
|
|
|
}
|
|
|
} else {
|
|
|
// 对于其他类型的输入,直接设置value
|
|
|
input.setAttribute('value', input.value)
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 使用同步后的HTML数据
|
|
|
const printNode = document.createElement('div')
|
|
|
printNode.innerHTML = dom.innerHTML
|
|
|
|
|
|
// 移除财务审核表
|
|
|
const financeTable = printNode.querySelector('.finance-review-table')
|
|
|
if (financeTable) {
|
|
|
financeTable.remove()
|
|
|
}
|
|
|
|
|
|
// 替换控件为纯文本(保留样式)
|
|
|
this.replaceControls(printNode)
|
|
|
console.log('printNode', printNode.innerHTML)
|
|
|
|
|
|
// 计算并更新总金额
|
|
|
const amountInputs = printNode.querySelectorAll('input[data-field^="amount"]')
|
|
|
let total = 0
|
|
|
amountInputs.forEach(input => {
|
|
|
const value = parseFloat(input.value) || 0
|
|
|
total += value
|
|
|
})
|
|
|
|
|
|
// 更新总金额显示
|
|
|
const totalInput = printNode.querySelector('input[data-field="total"]')
|
|
|
if (totalInput) {
|
|
|
totalInput.value = total.toFixed(2)
|
|
|
}
|
|
|
|
|
|
// 更新大写金额
|
|
|
const upperCaseInput = printNode.querySelector('input[data-field="upperCaseAmount"]')
|
|
|
if (upperCaseInput) {
|
|
|
upperCaseInput.value = numberToChinese(total)
|
|
|
}
|
|
|
|
|
|
const orientation = this.printOrientation || 'portrait';
|
|
|
const margin = orientation === 'portrait'
|
|
|
? '5mm 5mm 10mm 2mm' // 减少左右边距
|
|
|
: '5mm 5mm 10mm 5mm'; // 减少左右边距
|
|
|
const win = window.open('', '_blank')
|
|
|
// 动态计算宽高、缩放和平移
|
|
|
const isPortrait = orientation === 'portrait';
|
|
|
const pageWidth = isPortrait ? 290 : 297;
|
|
|
|
|
|
// 根据内容动态调整缩放和偏移
|
|
|
const hasTravelExpense = this.getForms && this.getForms.includes('差旅报销单');
|
|
|
const hasUtilityBill = this.getForms && this.getForms.includes('水电费结算单');
|
|
|
const hasReimbursementForm2 = this.getForms && this.getForms.includes('报销贴单2');
|
|
|
const scale = hasTravelExpense ? 0.66 : 0.9;
|
|
|
const offset = hasTravelExpense ? 62 : 5;
|
|
|
const translateX = ((pageWidth - pageWidth * scale) / 2 + offset).toFixed(2) + 'mm';
|
|
|
|
|
|
// 居中打印.
|
|
|
// table { width: 100%; border-collapse: collapse;table-layout: fixed; text-align: center; margin: 0 auto; }
|
|
|
// td { border: 1px solid #000; padding: 8px; min-width: 100px; word-break: break-all; text-align: center; vertical-align: middle; }
|
|
|
// th { text-align: center; vertical-align: middle; }
|
|
|
win.document.write(`
|
|
|
<html>
|
|
|
<head>
|
|
|
<title>打印</title>
|
|
|
<style>
|
|
|
@page { size: A4 ${orientation}; margin: ${margin}; }
|
|
|
body {
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
width: ${pageWidth}mm;
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
align-items: flex-start;
|
|
|
}
|
|
|
.white-container {
|
|
|
display: inline-block;
|
|
|
background: #fff;
|
|
|
box-sizing: border-box;
|
|
|
transform: scale(${scale}) translateX(${translateX});
|
|
|
transform-origin: top left;
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
}
|
|
|
.form-container { width: 100% !important; margin: 0 auto; }
|
|
|
table { width: 100%; border-collapse: collapse;table-layout: fixed; margin: 0 auto; }
|
|
|
td { border: 1px solid #000; padding: 8px; min-width: 100px; word-break: break-all; vertical-align: middle; }
|
|
|
th { vertical-align: middle; }
|
|
|
|
|
|
/* 资金划拨单最后一列宽度调整 */
|
|
|
${this.getForms && this.getForms.includes('资金划拨审批单') ? `
|
|
|
/* 改变表格布局方式 */
|
|
|
table {
|
|
|
table-layout: auto !important;
|
|
|
width: 100% !important;
|
|
|
}
|
|
|
|
|
|
/* 设置各列宽度比例 */
|
|
|
table td:nth-child(1) { width: 20% !important; }
|
|
|
table td:nth-child(2) { width: 20% !important; }
|
|
|
table td:nth-child(3) { width: 20% !important; }
|
|
|
table td:nth-child(4) {
|
|
|
width: 40% !important;
|
|
|
min-width: 500px !important;
|
|
|
max-width: none !important;
|
|
|
word-break: break-all !important;
|
|
|
white-space: normal !important;
|
|
|
overflow-wrap: break-word !important;
|
|
|
}
|
|
|
|
|
|
/* 处理跨列情况 */
|
|
|
table td[colspan] { width: auto !important; min-width: auto !important; }
|
|
|
|
|
|
/* 确保所有文本内容正常换行 */
|
|
|
table td * {
|
|
|
white-space: normal !important;
|
|
|
word-break: break-all !important;
|
|
|
overflow-wrap: break-word !important;
|
|
|
}
|
|
|
` : ''}
|
|
|
|
|
|
/* 水电费结算单特殊行高控制 */
|
|
|
${hasUtilityBill ? `
|
|
|
table td { height: 80px !important; min-height: 60px !important; line-height: 1.8 !important; }
|
|
|
table tr { height: 80px !important; min-height: 60px !important; }
|
|
|
` : ''}
|
|
|
|
|
|
/* 报销贴单2特殊行高控制 */
|
|
|
${hasReimbursementForm2 ? `
|
|
|
table td { height: 80px !important; min-height: 80px !important; line-height: 2.0 !important; }
|
|
|
table tr { height: 80px !important; min-height: 80px !important; }
|
|
|
` : ''}
|
|
|
|
|
|
@media print {
|
|
|
body {
|
|
|
width: ${pageWidth}mm;
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
align-items: flex-start;
|
|
|
}
|
|
|
.white-container {
|
|
|
transform: scale(${scale}) translateX(${translateX});
|
|
|
transform-origin: top left;
|
|
|
display: inline-block;
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<div class="white-container">
|
|
|
<div class="form-container">
|
|
|
${printNode.innerHTML}
|
|
|
</div>
|
|
|
</div>
|
|
|
</body>
|
|
|
</html>
|
|
|
`)
|
|
|
win.document.close()
|
|
|
win.focus()
|
|
|
win.print()
|
|
|
win.close()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
.form-switch {
|
|
|
margin-bottom: 20px;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
.white-container {
|
|
|
background: #fff;
|
|
|
padding: 20px;
|
|
|
}
|
|
|
|
|
|
.form-container {
|
|
|
position: relative;
|
|
|
width: 100%;
|
|
|
padding: 20px;
|
|
|
font-family: SimSun, serif;
|
|
|
}
|
|
|
|
|
|
.payment-form {
|
|
|
border: 1px solid #000;
|
|
|
padding: 20px;
|
|
|
}
|
|
|
|
|
|
.no-form-message {
|
|
|
text-align: center;
|
|
|
padding: 40px;
|
|
|
color: #999;
|
|
|
font-size: 16px;
|
|
|
}
|
|
|
|
|
|
.finance-review-table {
|
|
|
width: 100%;
|
|
|
border-collapse: collapse;
|
|
|
margin: 20px 0;
|
|
|
font-size: 15px;
|
|
|
background: #fff;
|
|
|
|
|
|
th, td {
|
|
|
border: 1px solid #e0e0e0;
|
|
|
padding: 10px 8px;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
th.finance-header-row {
|
|
|
background: #eaf3ff;
|
|
|
color: #2d8cf0;
|
|
|
font-size: 16px;
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
|
|
|
.sub-header {
|
|
|
background: #f5f7fa;
|
|
|
color: #333;
|
|
|
font-weight: 600;
|
|
|
width: 120px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.finance-review-header {
|
|
|
margin-bottom: 16px;
|
|
|
}
|
|
|
|
|
|
.payment-registration-row {
|
|
|
display: flex;
|
|
|
margin-bottom: 4px;
|
|
|
}
|
|
|
|
|
|
.payment-registration-row-title {
|
|
|
width: 100px;
|
|
|
font-weight: bold;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
.payment-registration-row-content {
|
|
|
flex: 1;
|
|
|
color: #666;
|
|
|
}
|
|
|
|
|
|
@media print {
|
|
|
.white-container {
|
|
|
padding: 0;
|
|
|
}
|
|
|
.form-container {
|
|
|
padding: 0;
|
|
|
}
|
|
|
.payment-form {
|
|
|
border: 1px solid #000;
|
|
|
}
|
|
|
.no-print {
|
|
|
display: none !important;
|
|
|
}
|
|
|
}
|
|
|
</style>
|