|
|
|
|
|
<template>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<xy-dialog title="打印预览" :is-show.sync="isShow" :width="90" @on-ok="printHtml" ok-text="打印">
|
|
|
|
|
|
<template v-slot:normalContent>
|
|
|
|
|
|
<div class="form-switch">
|
|
|
|
|
|
<RadioGroup v-model="currentForm" type="button">
|
|
|
|
|
|
<!-- <Radio label="pre" :disabled="!getBeforeForms">事前审批表格</Radio> -->
|
|
|
|
|
|
<!-- <Radio label="finance" :disabled="!fundLog">财务审核表</Radio> -->
|
|
|
|
|
|
<Radio label="post" :disabled="!getForms">事后支付表格2</Radio>
|
|
|
|
|
|
</RadioGroup>
|
|
|
|
|
|
</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>
|
|
|
|
|
|
<div v-else class="no-form-message">暂无事前审批表格内容</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Post-payment Form -->
|
|
|
|
|
|
<div v-else-if="currentForm === 'post'" class="payment-form">
|
|
|
|
|
|
<!-- 财务审核表内容放到事后支付表头部 -->
|
|
|
|
|
|
<table class="finance-review-table">
|
|
|
|
|
|
<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>
|
|
|
|
|
|
<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"
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'PrintPaymentForm',
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
isShow: false,
|
|
|
|
|
|
currentForm: 'post',
|
|
|
|
|
|
fundLog: null
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
getBeforeForms() {
|
|
|
|
|
|
return this.fundLog && this.fundLog.contract && this.fundLog.contract.before_forms
|
|
|
|
|
|
},
|
|
|
|
|
|
getForms() {
|
|
|
|
|
|
return this.fundLog && this.fundLog.contract && this.fundLog.contract.forms
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
async getDetailFundLog(id) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await detailFundLog({ id })
|
|
|
|
|
|
this.fundLog = res
|
|
|
|
|
|
// 移除自动设置 currentForm 的逻辑,让外部控制
|
|
|
|
|
|
// if (!this.getBeforeForms) {
|
|
|
|
|
|
// this.currentForm = 'post'
|
|
|
|
|
|
// }
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取付款详情失败:', error)
|
|
|
|
|
|
this.$Message.error('获取付款详情失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
replaceControls(element) {
|
|
|
|
|
|
// 替换所有输入框(文本、数字、日期)为纯文本
|
|
|
|
|
|
const inputs = element.getElementsByTagName('input');
|
|
|
|
|
|
Array.from(inputs).forEach(input => {
|
|
|
|
|
|
const span = document.createElement('span');
|
|
|
|
|
|
let displayText = input.value || '';
|
|
|
|
|
|
if (input.type === 'checkbox' || input.type === 'radio') {
|
|
|
|
|
|
const checkedInput = element.querySelector(`input[name="${input.name}"]:checked`);
|
|
|
|
|
|
if (checkedInput) {
|
|
|
|
|
|
const label = element.querySelector(`label[for="${checkedInput.id}"]`);
|
|
|
|
|
|
displayText = label ? label.textContent : checkedInput.value || '';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
displayText = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
} else 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];
|
|
|
|
|
|
});
|
|
|
|
|
|
// 全部居中对齐,充满td
|
|
|
|
|
|
span.style.width = '100%';
|
|
|
|
|
|
span.style.display = 'block';
|
|
|
|
|
|
span.style.textAlign = 'center';
|
|
|
|
|
|
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];
|
|
|
|
|
|
});
|
|
|
|
|
|
span.style.width = '100%';
|
|
|
|
|
|
span.style.display = 'block';
|
|
|
|
|
|
span.style.textAlign = 'center';
|
|
|
|
|
|
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];
|
|
|
|
|
|
});
|
|
|
|
|
|
span.style.width = '100%';
|
|
|
|
|
|
span.style.display = 'block';
|
|
|
|
|
|
span.style.textAlign = 'center';
|
|
|
|
|
|
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() {
|
|
|
|
|
|
// 克隆打印区域
|
|
|
|
|
|
const printNode = this.$refs.printtable.cloneNode(true);
|
|
|
|
|
|
// 替换控件为纯文本(保留样式)
|
|
|
|
|
|
this.replaceControls(printNode);
|
|
|
|
|
|
|
|
|
|
|
|
const win = window.open('', '_blank');
|
|
|
|
|
|
win.document.write(`
|
|
|
|
|
|
<html>
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<title>打印</title>
|
|
|
|
|
|
<style>
|
|
|
|
|
|
@page { size: A4; margin: 10mm; }
|
|
|
|
|
|
body { margin: 0; padding: 0; }
|
|
|
|
|
|
.white-container, .form-container { width: 794px !important; margin: 0 auto; }
|
|
|
|
|
|
</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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|