feat(print): 修改门诊挂号保存打印模板与补打挂号一致

- 在 printUtils.js 中添加 printRegistrationReceipt 函数
- 使用与补打挂号相同的 HTML 打印模板 (去掉"补打"字样)
- 修改 chargeDialog.vue 中的 printReceipt 函数调用新的打印方法
- 打印内容包括:患者信息、挂号信息、费用信息、流水号、二维码

Ref: 门诊挂号界面保存挂号打印功能
This commit is contained in:
2026-03-10 15:40:02 +08:00
parent e46e2be830
commit 1b4ad5e710
2 changed files with 230 additions and 180 deletions

View File

@@ -412,6 +412,211 @@ export function previewPrint(elementDom) {
}
}
/**
* 打印门诊挂号收据(使用浏览器打印,模板与补打挂号一致)
* @param {Object} data 打印数据
* @param {Object} options 打印选项
* @returns {Promise} 打印结果 Promise
*/
export function printRegistrationReceipt(data, options = {}) {
return new Promise((resolve, reject) => {
try {
// 构建打印内容的 HTML
const printContent = `
<div class="print-header">
<div class="header-content">
<div class="document-title">门诊预约挂号凭条</div>
<div class="print-time">打印时间:${data.printTime || new Date().toLocaleString()}</div>
</div>
</div>
<div class="print-section">
<div class="section-title">患者基本信息</div>
<div class="info-row">
<span class="label">患者姓名:</span>
<span class="value">${data.patientName || '-'}</span>
</div>
<div class="info-row">
<span class="label">就诊卡号:</span>
<span class="value">${data.cardNo || data.busNo || '-'}</span>
</div>
<div class="info-row">
<span class="label">身份证号:</span>
<span class="value">${data.idCard ? maskIdCard(data.idCard) : '-'}</span>
</div>
<div class="info-row">
<span class="label">联系电话:</span>
<span class="value">${data.phone || '-'}</span>
</div>
</div>
<div class="print-section">
<div class="section-title">挂号信息</div>
<div class="info-row">
<span class="label">就诊科室:</span>
<span class="value">${data.organizationName || '-'}</span>
</div>
<div class="info-row">
<span class="label">医生姓名:</span>
<span class="value">${data.practitionerName || '-'}</span>
</div>
<div class="info-row">
<span class="label">挂号类型:</span>
<span class="value">${data.healthcareName || '-'}</span>
</div>
<div class="info-row">
<span class="label">挂号时间:</span>
<span class="value">${data.visitTime || data.chargeTime || '-'}</span>
</div>
</div>
<div class="print-section">
<div class="section-title">费用信息</div>
<table class="fee-table">
<thead>
<tr>
<th>项目</th>
<th>数量</th>
<th>单价</th>
<th>金额</th>
</tr>
</thead>
<tbody>
<tr>
<td>挂号费</td>
<td>1</td>
<td>¥${parseFloat(data.price || 0).toFixed(2)}</td>
<td>¥${parseFloat(data.price || 0).toFixed(2)}</td>
</tr>
${parseFloat(data.activityPrice || 0) > 0 ? `
<tr>
<td>诊疗费</td>
<td>1</td>
<td>¥${parseFloat(data.activityPrice || 0).toFixed(2)}</td>
<td>¥${parseFloat(data.activityPrice || 0).toFixed(2)}</td>
</tr>` : ''}
${parseFloat(data.medicalRecordFee || 0) > 0 ? `
<tr>
<td>病历费</td>
<td>1</td>
<td>¥${parseFloat(data.medicalRecordFee || 0).toFixed(2)}</td>
<td>¥${parseFloat(data.medicalRecordFee || 0).toFixed(2)}</td>
</tr>` : ''}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="total-label">合计:</td>
<td class="total-value">¥${parseFloat(data.totalPrice || data.amount || 0).toFixed(2)}</td>
</tr>
</tfoot>
</table>
</div>
<!-- 流水号显示在左下角 -->
<div class="serial-number-bottom-left">
<span class="serial-label">流水号:</span>
<span class="serial-value">${data.serialNo || data.encounterId || '-'}</span>
</div>
<div class="print-footer">
<div class="reminder">温馨提示:请妥善保管此凭条,就诊时请携带。</div>
</div>
<!-- 二维码区域 -->
<div class="qr-code-section">
<div class="qr-code-container">
<div id="qrcode-print" class="qrcode-print"></div>
<div class="qr-code-label">扫码查看挂号信息</div>
</div>
</div>
`;
// 创建新窗口用于打印
const printWindow = window.open('', '_blank');
if (!printWindow) {
reject(new Error('无法打开打印窗口,请检查浏览器弹窗设置'));
return;
}
// 写入打印内容
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>门诊预约挂号凭条</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; margin: 0; }
.print-header { margin-bottom: 20px; position: relative; }
.header-content { text-align: center; }
.document-title { font-size: 16px; font-weight: bold; margin-bottom: 10px; }
.print-time { font-size: 12px; color: #666; text-align: right; }
.print-section { margin-bottom: 20px; }
.section-title { font-size: 14px; font-weight: bold; margin-bottom: 10px; border-bottom: 1px solid #ddd; padding-bottom: 5px; }
.info-row { margin-bottom: 8px; font-size: 13px; }
.label { display: inline-block; width: 100px; font-weight: bold; }
.value { display: inline-block; }
.fee-table { width: 100%; border-collapse: collapse; margin-top: 10px; }
.fee-table th, .fee-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.fee-table th { background-color: #f5f5f5; font-weight: bold; }
.total-label { font-weight: bold; text-align: right; }
.total-value { font-weight: bold; color: red; }
.serial-number-bottom-left { position: absolute; bottom: 20px; left: 20px; font-size: 14px; font-weight: bold; }
.serial-number-bottom-left .serial-label { font-weight: bold; margin-right: 5px; }
.serial-number-bottom-left .serial-value { font-weight: bold; color: #333; }
.print-content { position: relative; min-height: 500px; padding-bottom: 60px; }
.print-footer { margin-top: 20px; font-size: 12px; color: #666; }
.reminder { text-align: center; padding: 10px; background-color: #f9f9f9; border-radius: 4px; }
.qr-code-section { margin-top: 20px; display: flex; justify-content: center; align-items: center; padding: 15px; }
.qr-code-container { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.qrcode-print { width: 120px; height: 120px; }
.qr-code-label { font-size: 12px; color: #666; text-align: center; }
@media print { body { padding: 0; } .qr-code-section { page-break-inside: avoid; } }
</style>
</head>
<body>
<div class="print-content">
${printContent}
</div>
</body>
</html>
`);
printWindow.document.close();
printWindow.onload = function() {
setTimeout(() => {
printWindow.print();
resolve({ success: true, message: '打印窗口已打开' });
}, 250);
};
} catch (error) {
console.error('打印门诊挂号收据失败:', error);
reject(error);
}
});
}
/**
* 脱敏身份证号
* @param {string} idCard 身份证号
* @returns {string} 脱敏后的身份证号
*/
function maskIdCard(idCard) {
if (!idCard) return '';
if (idCard.length >= 10) {
const prefix = idCard.substring(0, 6);
const suffix = idCard.substring(idCard.length - 4);
const stars = '*'.repeat(Math.max(0, idCard.length - 10));
return prefix + stars + suffix;
} else if (idCard.length >= 6) {
const prefix = idCard.substring(0, 3);
const suffix = idCard.substring(idCard.length - 1);
return prefix + '*'.repeat(idCard.length - 4) + suffix;
}
return idCard;
}
// 默认导出简化的打印方法
export default {
print: simplePrint,

View File

@@ -114,7 +114,7 @@ import {savePayment, wxPay, WxPayResult} from './outpatientregistration';
import {computed, getCurrentInstance, nextTick, reactive, ref, watch} from 'vue';
import {Delete} from '@element-plus/icons-vue';
import {debounce} from 'lodash-es';
import printUtils, {PRINT_TEMPLATE} from '@/utils/printUtils';
import printUtils, {PRINT_TEMPLATE, printRegistrationReceipt} from '@/utils/printUtils';
// 获取费用性质文本
const getFeeTypeText = computed(() => {
@@ -202,196 +202,41 @@ watch(
const emit = defineEmits(['close']);
// 根据printUtils实现的打印方法
// 根据 printUtils 实现的打印方法 - 使用与补打挂号相同的模板 (去掉"补打"字样)
async function printReceipt(param) {
console.log('打印收费小票数据:', param);
console.log('打印挂号收据数据:', param);
console.log('患者信息:', props.patientInfo);
try {
// 构造打印数据
// 构造打印数据 - 使用与补打挂号相同的格式
const printData = {
data: [
{
...param,
// 基础支付类型
YB_FUND_PAY: param.detail?.find((t) => t.payEnum === 100000)?.amount ?? 0, // 基金支付总额
SELF_PAY: param.detail?.find((t) => t.payEnum === 200000)?.amount ?? 0, // 个人负担总金额
OTHER_PAY: param.detail?.find((t) => t.payEnum === 300000)?.amount ?? 0, // 其他(如医院负担金额)
// 基本医保统筹基金支出
YB_TC_FUND_AMOUNT: param.detail?.find((t) => t.payEnum === 110000)?.amount ?? 0, // 基本医保统筹基金支出
YB_BC_FUND_AMOUNT: param.detail?.find((t) => t.payEnum === 120000)?.amount ?? 0, // 补充医疗保险基金支出
YB_JZ_FUND_AMOUNT: param.detail?.find((t) => t.payEnum === 130000)?.amount ?? 0, // 医疗救助基金支出
YB_OTHER_AMOUNT: param.detail?.find((t) => t.payEnum === 140000)?.amount ?? 0, // 其他支出
// 职工基本医疗保险
YB_TC_ZG_FUND_VALUE: param.detail?.find((t) => t.payEnum === 110100)?.amount ?? 0, // 职工基本医疗保险
YB_TC_JM_FUND_VALUE: param.detail?.find((t) => t.payEnum === 110200)?.amount ?? 0, // 居民基本医疗保险
// 补充医疗保险基金支出细分
YB_BC_JM_DB_VALUE: param.detail?.find((t) => t.payEnum === 120100)?.amount ?? 0, // 全体参保人的居民大病保险
YB_BC_DE_BZ_VALUE: param.detail?.find((t) => t.payEnum === 120200)?.amount ?? 0, // 大额医疗费用补助
YB_BC_ZG_DE_BZ_VALUE: param.detail?.find((t) => t.payEnum === 120300)?.amount ?? 0, // 企业职工大额医疗费用补助
YB_BC_GWY_BZ_VALUE: param.detail?.find((t) => t.payEnum === 120400)?.amount ?? 0, // 公务员医疗补助
// 其他支出细分
OTHER_PAY_DD_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300001)?.amount ?? 0, // 兜底基金支出
OTHER_PAY_YW_SH_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300002)?.amount ?? 0, // 意外伤害基金支出
OTHER_PAY_LX_YL_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300003)?.amount ?? 0, // 离休人员医疗保障金支出
OTHER_PAY_LX_YH_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300004)?.amount ?? 0, // 离休人员优惠金支出
OTHER_PAY_CZ_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300005)?.amount ?? 0, // 财政基金支出
OTHER_PAY_CZ_YZ_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300006)?.amount ?? 0, // 财政预支支出
OTHER_PAY_ZG_DB_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300007)?.amount ?? 0, // 职工大病基金支出
OTHER_PAY_EY_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300008)?.amount ?? 0, // 二乙基金支出
OTHER_PAY_QX_JZ_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300009)?.amount ?? 0, // 倾斜救助支出
OTHER_PAY_YL_JZ_FUND_VALUE: param.detail?.find((t) => t.payEnum === 300010)?.amount ?? 0, // 医疗救助再救助基金
HOSP_PART_AMT: param.detail?.find((t) => t.payEnum === 300011)?.amount ?? 0, // 医院负担金额
// 医保结算返回值 - 修复运算符优先级问题,添加括号确保正确拼接'元'
FULAMT_OWNPAY_AMT: (param.detail?.find((t) => t.payEnum === 1)?.amount ?? 0) + '元', // 全自费金额
OVERLMT_SELFPAY: (param.detail?.find((t) => t.payEnum === 3)?.amount ?? 0) + '元', // 超限价自费费用
PRESELFPAY_AMT: (param.detail?.find((t) => t.payEnum === 4)?.amount ?? 0) + '元', // 先行自付金额
INSCP_SCP_AMT: (param.detail?.find((t) => t.payEnum === 5)?.amount ?? 0) + '元', // 符合政策范围金额
ACT_PAY_DEDC: (param.detail?.find((t) => t.payEnum === 6)?.amount ?? 0) + '元', // 实际支付起付线
POOL_PROP_SELFPAY: (param.detail?.find((t) => t.payEnum === 7)?.amount ?? 0) + '元', // 基本医疗保险统筹基金支付比例
BALC: (param.detail?.find((t) => t.payEnum === 8)?.amount ?? 0) + '元', // 余额
// 特殊支付方式
SELF_YB_ZH_PAY:
(param.detail?.find((t) => t.payEnum === 210000)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 210000)?.amount ?? 0) + '元'
: '', // 个人医保账户支付
SELF_YB_ZH_GJ_VALUE:
(param.detail?.find((t) => t.payEnum === 210100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 210100)?.amount ?? 0) + '元'
: '', // 账户共济支付金额
SELF_CASH_PAY:
(param.detail?.find((t) => t.payEnum === 220000)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 220000)?.amount ?? 0) + '元'
: '', // 个人现金支付金额
SELF_VX_PAY:
(param.detail?.find((t) => t.payEnum === 230000)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 230000)?.amount ?? 0) + '元'
: '', // 微信支付金额
SELF_ALI_PAY:
(param.detail?.find((t) => t.payEnum === 240000)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 240000)?.amount ?? 0) + '元'
: '', // 阿里支付金额
// 现金支付细分
SELF_CASH_VALUE:
(param.detail?.find((t) => t.payEnum === 220400)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 220400)?.amount ?? 0) + '元'
: '', // 个人现金支付金额(现金)
SELF_CASH_VX_VALUE:
(param.detail?.find((t) => t.payEnum === 220100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 220100)?.amount ?? 0) + '元'
: '', // 个人现金支付金额(微信)
SELF_CASH_ALI_VALUE:
(param.detail?.find((t) => t.payEnum === 220200)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 220200)?.amount ?? 0) + '元'
: '', // 个人现金支付金额(支付宝)
SELF_CASH_UNION_VALUE:
(param.detail?.find((t) => t.payEnum === 220300)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 220300)?.amount ?? 0) + '元'
: '', // 个人现金支付金额(银联)
// 基金类型(扩展)
BIRTH_FUND:
(param.detail?.find((t) => t.payEnum === 510100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 510100)?.amount ?? 0) + '元'
: '', // 生育基金
RETIREE_MEDICAL:
(param.detail?.find((t) => t.payEnum === 340100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 340100)?.amount ?? 0) + '元'
: '', // 离休人员医疗保障基金
URBAN_BASIC_MEDICAL:
(param.detail?.find((t) => t.payEnum === 390100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 390100)?.amount ?? 0) + '元'
: '', // 城乡居民基本医疗保险基金
URBAN_SERIOUS_ILLNESS:
(param.detail?.find((t) => t.payEnum === 390200)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 390200)?.amount ?? 0) + '元'
: '', // 城乡居民大病医疗保险基金
MEDICAL_ASSISTANCE:
(param.detail?.find((t) => t.payEnum === 610100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 610100)?.amount ?? 0) + '元'
: '', // 医疗救助基金
GOVERNMENT_SUBSIDY:
(param.detail?.find((t) => t.payEnum === 640100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 640100)?.amount ?? 0) + '元'
: '', // 政府兜底基金
ACCIDENT_INSURANCE:
(param.detail?.find((t) => t.payEnum === 390400)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 390400)?.amount ?? 0) + '元'
: '', // 意外伤害基金
CARE_INSURANCE:
(param.detail?.find((t) => t.payEnum === 620100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 620100)?.amount ?? 0) + '元'
: '', // 照护保险基金
FINANCIAL_FUND:
(param.detail?.find((t) => t.payEnum === 360100)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 360100)?.amount ?? 0) + '元'
: '', // 财政基金
HOSPITAL_ADVANCE:
(param.detail?.find((t) => t.payEnum === 999900)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 999900)?.amount ?? 0) + '元'
: '', // 医院垫付
SUPPLEMENTARY_INSURANCE:
(param.detail?.find((t) => t.payEnum === 390300)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 390300)?.amount ?? 0) + '元'
: '', // 城乡居民大病补充保险基金
HEALTHCARE_PREPAYMENT:
(param.detail?.find((t) => t.payEnum === 360300)?.amount ?? 0) > 0
? (param.detail?.find((t) => t.payEnum === 360300)?.amount ?? 0) + '元'
: '', // 保健预支基金
//微信刷卡支付
SELF_CASH_VX_VALUE: (() => {
// const cashValue = param.detail?.find((t) => t.payEnum === 220400)?.amount ?? 0;
const vxValue = param.detail?.find((t) => t.payEnum === 220100)?.amount ?? 0;
const unionValue = param.detail?.find((t) => t.payEnum === 220300)?.amount ?? 0;
const aliValue = param.detail?.find((t) => t.payEnum === 220200)?.amount ?? 0;
return (Number(vxValue) + Number(unionValue) + Number(aliValue)).toFixed(2) + '元';
})(),
// 患者信息
patientName: param.patientName || '',
sex: param.sex === 1 ? '女' : param.sex === 0 ? '男' : param.sex || '',
age: param.age ? param.age + '岁' : '',
personType: param.contractName, //病人类型
// 挂号和就诊信息
encounterId: props.patientInfo?.encounterId || '',
busNo: props.patientInfo?.busNo || '',
Mr_QR_Code: param.regNo || props.registerBusNo,
// 科室和医生信息
organizationName: props.orgName || props.patientInfo?.organizationName || '',
practitionerName: props.patientInfo?.practitionerName || '',
healthcareName: props.patientInfo?.healthcareName || '',
// 费用信息
fixmedinsName: param.fixmedinsName
? param.fixmedinsName + '门诊收费明细'
: '门诊收费明细',
// 收费员
cashier: param.paymentEmployee,
// 收费时间
chargeTime: new Date().toLocaleString(),
//电子收据二维码
pictureUrl: param.pictureUrl || 'https://chinaebill.com/img/xiaochengxu.png',
},
],
patientName: props.patientInfo?.patientName || props.patientInfo?.name || '',
cardNo: props.patientInfo?.busNo || param.busNo || '',
idCard: param.idCard || '',
phone: props.patientInfo?.phone || '',
organizationName: props.orgName || props.patientInfo?.organizationName || '',
practitionerName: props.patientInfo?.practitionerName || '',
healthcareName: props.patientInfo?.healthcareName || '',
visitTime: new Date().toLocaleString(),
price: param.totalPrice || props.totalAmount || 0,
activityPrice: 0,
medicalRecordFee: 0,
totalPrice: param.totalPrice || props.totalAmount || 0,
serialNo: props.patientInfo?.encounterId || param.encounterId || '',
encounterId: props.patientInfo?.encounterId || param.encounterId || '',
printTime: new Date().toLocaleString(),
};
// 选择门诊手术计费打印模板(含流程图)
console.log('printDataprintDataprintDataprintDataprintData', printData.data[0]);
await printUtils.print(PRINT_TEMPLATE.OUTPATIENT_SURGERY_CHARGE, printData.data[0]);
console.log('printReceipt printData', printData);
// 使用与补打挂号相同的打印模板 (不带"补打"字样)
await printRegistrationReceipt(printData);
console.log('打印成功');
} catch (error) {
console.error('打印失败:', error);
proxy.$modal.msgError('打印失败: ' + error.message);
proxy.$modal.msgError('打印失败' + error.message);
}
}
function handleWxPay() {
console.log('开始微信支付,当前支付详情:', formData.selfPay);
console.log(