4 Commits

Author SHA1 Message Date
6b600b44ca Merge remote-tracking branch 'origin/develop' into develop 2026-03-10 16:46:04 +08:00
b69f312611 refactor(router): 优化路由配置和打印功能实现
- 统一路由配置中的代码风格,移除多余空格
- 移除医生个人报卡管理菜单项
- 移除检查管理中的医生报告快捷访问路径
- 替换浏览器打印为hiprint打印方案
- 添加vue-plugin-hiprint依赖和相关配置
- 实现门诊挂号单的hiprint打印功能
- 优化WebView环境检测逻辑和错误处理
2026-03-10 16:28:41 +08:00
c65db9abc3 chore(release): bump version to 3.8.8 2026-03-10 15:40:17 +08:00
1b4ad5e710 feat(print): 修改门诊挂号保存打印模板与补打挂号一致
- 在 printUtils.js 中添加 printRegistrationReceipt 函数
- 使用与补打挂号相同的 HTML 打印模板 (去掉"补打"字样)
- 修改 chargeDialog.vue 中的 printReceipt 函数调用新的打印方法
- 打印内容包括:患者信息、挂号信息、费用信息、流水号、二维码

Ref: 门诊挂号界面保存挂号打印功能
2026-03-10 15:40:02 +08:00
8 changed files with 3998 additions and 830 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "openhis",
"version": "3.8.7",
"version": "3.8.8",
"description": "OpenHIS管理系统",
"author": "OpenHIS",
"license": "MIT",
@@ -12,7 +12,11 @@
"build:test": "vite build --mode test",
"build:dev": "vite build --mode dev",
"preview": "vite preview",
"build:spug": "vite build --mode spug"
"build:spug": "vite build --mode spug",
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"test:ui": "vitest --ui"
},
"repository": {
"type": "git",
@@ -58,9 +62,14 @@
"vue-router": "^4.3.0"
},
"devDependencies": {
"@playwright/test": "^1.58.2",
"@types/node": "^25.0.1",
"@vitejs/plugin-vue": "4.5.0",
"@vue/compiler-sfc": "3.3.9",
"@vue/test-utils": "^2.4.6",
"happy-dom": "^20.8.3",
"jsdom": "^28.1.0",
"pg": "^8.18.0",
"sass": "1.69.5",
"typescript": "^5.9.3",
"unplugin-auto-import": "0.17.1",
@@ -68,6 +77,8 @@
"vite": "5.0.4",
"vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-mcp": "^0.3.2",
"vitest": "^4.0.18",
"vue-tsc": "^3.1.8"
}
}

View File

@@ -80,10 +80,15 @@ setTimeout(() => {
const app = createApp(App);
if (chrome.webview !== undefined) {
// 如果是webview环境挂载CSharpAccessor对象到vue实例上
const csAccessor = chrome.webview.hostObjects.CSharpAccessor;
app.config.globalProperties.csAccessor = csAccessor;
// 检查是否在 WebView 环境中(使用可选链避免 ReferenceError
if (typeof window !== 'undefined' && window.chrome?.webview !== undefined) {
// 如果是 webview 环境,挂载 CSharpAccessor 对象到 vue 实例上
try {
const csAccessor = window.chrome.webview.hostObjects.CSharpAccessor;
app.config.globalProperties.csAccessor = csAccessor;
} catch (e) {
console.warn('WebView CSharpAccessor 不可用:', e);
}
}
// 全局方法挂载

View File

@@ -1,4 +1,4 @@
import { createWebHistory, createRouter } from 'vue-router'
import {createWebHistory, createRouter} from 'vue-router'
/* Layout */
import Layout from '@/layout'
@@ -61,7 +61,7 @@ export const constantRoutes = [
path: '/index',
component: () => import('@/views/index'),
name: 'Index',
meta: { title: '首页', icon: 'dashboard', affix: true }
meta: {title: '首页', icon: 'dashboard', affix: true}
}
]
},
@@ -75,7 +75,7 @@ export const constantRoutes = [
path: 'profile',
component: () => import('@/views/system/user/profile/index'),
name: 'Profile',
meta: { title: '个人中心', icon: 'user' }
meta: {title: '个人中心', icon: 'user'}
}
]
},
@@ -89,7 +89,7 @@ export const constantRoutes = [
path: '',
component: () => import('@/views/maintainSystem/Inspection/PackageManagement.vue'),
name: 'DirectPackageManagement',
meta: { title: '套餐管理' }
meta: {title: '套餐管理'}
}
]
}
@@ -108,7 +108,7 @@ export const dynamicRoutes = [
path: 'set/:tenantId(\\d+)',
component: () => import('@/views/system/tenant/setUser'),
name: 'SetUser',
meta: { title: '所属用户', activeMenu: '/system/tenant' }
meta: {title: '所属用户', activeMenu: '/system/tenant'}
}
]
},
@@ -122,7 +122,7 @@ export const dynamicRoutes = [
path: 'set/:tenantId(\\d+)',
component: () => import('@/views/system/tenant/setContract'),
name: 'SetContract',
meta: { title: '合同管理', activeMenu: '/system/tenant' }
meta: {title: '合同管理', activeMenu: '/system/tenant'}
}
]
},
@@ -136,7 +136,7 @@ export const dynamicRoutes = [
path: 'role/:userId(\\d+)',
component: () => import('@/views/system/user/authRole'),
name: 'AuthRole',
meta: { title: '分配角色', activeMenu: '/system/user' }
meta: {title: '分配角色', activeMenu: '/system/user'}
}
]
},
@@ -150,7 +150,7 @@ export const dynamicRoutes = [
path: 'user/:roleId(\\d+)',
component: () => import('@/views/system/role/authUser'),
name: 'AuthUser',
meta: { title: '分配用户', activeMenu: '/system/role' }
meta: {title: '分配用户', activeMenu: '/system/role'}
}
]
},
@@ -159,25 +159,25 @@ export const dynamicRoutes = [
component: Layout,
redirect: '/monitor/operlog',
name: 'Monitor',
meta: { title: '系统监控', icon: 'monitor' },
meta: {title: '系统监控', icon: 'monitor'},
children: [
{
path: 'operlog',
component: () => import('@/views/monitor/operlog/index.vue'),
name: 'Operlog',
meta: { title: '操作日志', icon: 'operlog', permissions: ['monitor:operlog:list'] }
meta: {title: '操作日志', icon: 'operlog', permissions: ['monitor:operlog:list']}
},
{
path: 'logininfor',
component: () => import('@/views/monitor/logininfor/index.vue'),
name: 'Logininfor',
meta: { title: '登录日志', icon: 'logininfor', permissions: ['monitor:logininfor:list'] }
meta: {title: '登录日志', icon: 'logininfor', permissions: ['monitor:logininfor:list']}
},
{
path: 'job',
component: () => import('@/views/monitor/job/index.vue'),
name: 'Job',
meta: { title: '定时任务', icon: 'job', permissions: ['monitor:job:list'] }
meta: {title: '定时任务', icon: 'job', permissions: ['monitor:job:list']}
}
]
},
@@ -186,13 +186,13 @@ export const dynamicRoutes = [
component: Layout,
redirect: '/tool/gen',
name: 'Tool',
meta: { title: '系统工具', icon: 'tool' },
meta: {title: '系统工具', icon: 'tool'},
children: [
{
path: 'gen',
component: () => import('@/views/tool/gen/index.vue'),
name: 'Gen',
meta: { title: '代码生成', icon: 'gen', permissions: ['tool:gen:list'] }
meta: {title: '代码生成', icon: 'gen', permissions: ['tool:gen:list']}
}
]
},
@@ -206,7 +206,7 @@ export const dynamicRoutes = [
path: 'index/:jobId(\\d+)',
component: () => import('@/views/monitor/job/log'),
name: 'JobLog',
meta: { title: '调度日志', activeMenu: '/monitor/job' }
meta: {title: '调度日志', activeMenu: '/monitor/job'}
}
]
},
@@ -220,7 +220,7 @@ export const dynamicRoutes = [
path: 'index/:tableId(\\d+)',
component: () => import('@/views/tool/gen/editTable'),
name: 'GenEdit',
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
meta: {title: '修改生成配置', activeMenu: '/tool/gen'}
}
]
},
@@ -233,7 +233,10 @@ export const dynamicRoutes = [
path: '',
component: () => import('@/views/helpcenter/index.vue'),
name: 'HelpCenter',
meta: {title: '帮助中心', link: '/help-center/vuepress-theme-vdoing-doc/docs/.vuepress/dist/pages/520e67/index.html'},
meta: {
title: '帮助中心',
link: '/help-center/vuepress-theme-vdoing-doc/docs/.vuepress/dist/pages/520e67/index.html'
},
},
],
},
@@ -242,19 +245,13 @@ export const dynamicRoutes = [
component: Layout,
redirect: '/doctorstation/index',
name: 'DoctorStation',
meta: { title: '医生工作站', icon: 'operation' },
meta: {title: '医生工作站', icon: 'operation'},
children: [
{
{
path: 'pending-emr',
component: () => import('@/views/doctorstation/pendingEmr.vue'),
name: 'PendingEmr',
meta: { title: '待写病历', icon: 'document', permissions: ['doctorstation:pending-emr:view'] }
},
{
path: 'my-card-management',
component: () => import('@/views/doctorstation/mycardmanagement/index.vue'),
name: 'MyCardManagement',
meta: { title: '医生个人报卡管理', icon: 'document', permissions: ['doctorstation:my-card-management:view'] }
meta: {title: '待写病历', icon: 'document', permissions: ['doctorstation:pending-emr:view']}
}
]
},
@@ -262,19 +259,19 @@ export const dynamicRoutes = [
path: '/features',
component: Layout,
name: 'Features',
meta: { title: '全部功能', icon: 'menu' },
meta: {title: '全部功能', icon: 'menu'},
children: [
{
path: '',
component: () => import('@/views/features/index.vue'),
name: 'FeaturesIndex',
meta: { title: '功能列表', icon: 'menu' }
meta: {title: '功能列表', icon: 'menu'}
},
{
path: 'config',
component: () => import('@/views/features/config.vue'),
name: 'FeaturesConfig',
meta: { title: '功能配置', icon: 'setting' }
meta: {title: '功能配置', icon: 'setting'}
}
]
},
@@ -282,13 +279,13 @@ export const dynamicRoutes = [
path: '/todo',
component: Layout,
name: 'Todo',
meta: { title: '待办事项', icon: 'todo' },
meta: {title: '待办事项', icon: 'todo'},
children: [
{
path: '',
component: () => import('@/views/todo/index.vue'),
name: 'TodoIndex',
meta: { title: '待办列表', icon: 'todo' }
meta: {title: '待办列表', icon: 'todo'}
}
]
},
@@ -296,13 +293,13 @@ export const dynamicRoutes = [
path: '/appoinmentmanage',
component: Layout,
name: 'AppoinmentManage',
meta: { title: '预约管理', icon: 'appointment' },
meta: {title: '预约管理', icon: 'appointment'},
children: [
{
path: 'deptManage',
component: () => import('@/views/appoinmentmanage/deptManage/index.vue'),
name: 'DeptManage',
meta: { title: '科室排班管理', icon: 'calendar' }
meta: {title: '科室排班管理', icon: 'calendar'}
}
]
},
@@ -310,13 +307,13 @@ export const dynamicRoutes = [
path: '/clinicmanagement',
component: Layout,
name: 'ClinicManagement',
meta: { title: '门诊管理', icon: 'operation' },
meta: {title: '门诊管理', icon: 'operation'},
children: [
{
path: 'dayEnd',
component: () => import('@/views/clinicmanagement/dayEnd/index.vue'),
name: 'DayEnd',
meta: { title: '门诊日结', icon: 'document' }
meta: {title: '门诊日结', icon: 'document'}
}
]
},
@@ -324,19 +321,19 @@ export const dynamicRoutes = [
path: '/consultationmanagement',
component: Layout,
name: 'ConsultationManagement',
meta: { title: '会诊管理', icon: 'operation' },
meta: {title: '会诊管理', icon: 'operation'},
children: [
{
path: 'consultationapplication',
component: () => import('@/views/consultationmanagement/consultationapplication/index.vue'),
name: 'ConsultationApplication',
meta: { title: '门诊会诊申请管理', icon: 'document' }
meta: {title: '门诊会诊申请管理', icon: 'document'}
},
{
path: 'consultationconfirmation',
component: () => import('@/views/consultationmanagement/consultationconfirmation/index.vue'),
name: 'ConsultationConfirmation',
meta: { title: '门诊会诊申请确认', icon: 'document' }
meta: {title: '门诊会诊申请确认', icon: 'document'}
}
]
},
@@ -344,13 +341,13 @@ export const dynamicRoutes = [
path: '/medicationmanagement',
component: Layout,
name: 'MedicationManagement',
meta: { title: '药房管理', icon: 'medication' },
meta: {title: '药房管理', icon: 'medication'},
children: [
{
path: 'dayEndSettlement',
component: () => import('@/views/medicationmanagement/dayEndSettlement/index.vue'),
name: 'DayEndSettlement',
meta: { title: '日结结算单管理', icon: 'document' }
meta: {title: '日结结算单管理', icon: 'document'}
}
]
},
@@ -359,63 +356,49 @@ export const dynamicRoutes = [
component: Layout,
redirect: '/inspection/report',
name: 'Inspection',
meta: { title: '检查管理', icon: 'inspection' },
meta: {title: '检查管理', icon: 'inspection'},
children: [
{
path: 'report',
component: () => import('@/views/inspection/report/index.vue'),
name: 'Report',
meta: { title: '检查报告', icon: 'document' }
meta: {title: '检查报告', icon: 'document'}
},
{
path: 'sampleType',
component: () => import('@/views/inspection/sampleType/index.vue'),
name: 'SampleType',
meta: { title: '样本类型', icon: 'sample' }
meta: {title: '样本类型', icon: 'sample'}
},
{
path: 'observation',
component: () => import('@/views/inspection/observation/index.vue'),
name: 'Observation',
meta: { title: '观测记录', icon: 'observation' }
meta: {title: '观测记录', icon: 'observation'}
},
{
path: 'lisconfig',
component: () => import('@/views/inspection/lisconfig/index.vue'),
name: 'LisConfig',
meta: { title: 'LIS 配置', icon: 'setting' }
meta: {title: 'LIS 配置', icon: 'setting'}
},
{
path: 'instrument',
component: () => import('@/views/inspection/instrument/index.vue'),
name: 'Instrument',
meta: { title: '仪器管理', icon: 'instrument' }
meta: {title: '仪器管理', icon: 'instrument'}
},
{
path: 'groupRec',
component: () => import('@/views/inspection/groupRec/index.vue'),
name: 'GroupRec',
meta: { title: '组合记录', icon: 'group' }
meta: {title: '组合记录', icon: 'group'}
},
{
path: 'sampleCollection',
component: () => import('@/views/inspection/sampleCollection/index.vue'),
name: 'SampleCollection',
meta: { title: '样本采集', icon: 'collection' }
}
]
},
// 医生报告页面 - 快捷访问路径
{
path: '/doctorreport',
component: Layout,
hidden: true,
children: [
{
path: '',
component: () => import('@/views/inspection/report/index.vue'),
name: 'DoctorReport',
meta: { title: '医生报告', activeMenu: '/inspection/report' }
meta: {title: '样本采集', icon: 'collection'}
}
]
}
@@ -438,7 +421,7 @@ const router = createRouter({
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
return {top: 0}
}
},
});

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(

View File

@@ -118,141 +118,12 @@
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button @click="selectDialogVisible = false">取消(C)</el-button>
<el-button type="primary" @click="handleConfirmSelect" :disabled="!selectedRecord">确认(O)</el-button>
</div>
</template>
</el-dialog>
<!-- 打印预览对话框 -->
<el-dialog
title="打印预览"
v-model="printPreviewVisible"
width="600px"
append-to-body
:close-on-click-modal="false"
class="print-preview-dialog"
>
<div id="print-content" class="print-content">
<!-- 打印内容 -->
<div class="print-header">
<div class="reprint-label-left">补打</div>
<div class="header-content">
<div class="document-title">门诊预约挂号凭条</div>
<div class="print-time">打印时间: {{ form.printTime }}</div>
</div>
</div>
<div class="print-section">
<div class="section-title">患者基本信息</div>
<div class="info-row">
<span class="label">患者姓名:</span>
<span class="value">{{ form.name || '-' }}</span>
</div>
<div class="info-row">
<span class="label">就诊卡号:</span>
<span class="value">{{ form.cardNo || '-' }}</span>
</div>
<div class="info-row">
<span class="label">身份证号:</span>
<span class="value">{{ form.idCard || '-' }}</span>
</div>
<div class="info-row">
<span class="label">联系电话:</span>
<span class="value">{{ form.phone || '-' }}</span>
</div>
</div>
<div class="print-section">
<div class="section-title">预约详情</div>
<div class="info-row">
<span class="label">就诊科室:</span>
<span class="value">{{ form.organizationName || '-' }}</span>
</div>
<div class="info-row">
<span class="label">医生姓名:</span>
<span class="value">{{ form.practitionerName || '-' }}</span>
</div>
<div class="info-row">
<span class="label">预约时间:</span>
<span class="value">{{ form.visitTime || '-' }}</span>
</div>
<div class="info-row">
<span class="label">就诊地点:</span>
<span class="value">{{ form.visitLocation || '-' }}</span>
</div>
<div class="info-row">
<span class="label">预约状态:</span>
<span class="value">{{ form.statusText || '-' }}</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(form.price || 0).toFixed(2) }}</td>
<td>¥{{ parseFloat(form.price || 0).toFixed(2) }}</td>
</tr>
<tr v-if="parseFloat(form.activityPrice || 0) > 0">
<td>诊疗费</td>
<td>1</td>
<td>¥{{ parseFloat(form.activityPrice || 0).toFixed(2) }}</td>
<td>¥{{ parseFloat(form.activityPrice || 0).toFixed(2) }}</td>
</tr>
<tr v-if="parseFloat(form.medicalRecordFee || 0) > 0">
<td>病历费</td>
<td>1</td>
<td>¥{{ parseFloat(form.medicalRecordFee || 0).toFixed(2) }}</td>
<td>¥{{ parseFloat(form.medicalRecordFee || 0).toFixed(2) }}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3" class="total-label">合计:</td>
<td class="total-value">¥{{ parseFloat(form.totalPrice || 0).toFixed(2) }}</td>
</tr>
</tfoot>
</table>
</div>
<!-- 流水号显示在左下角 -->
<div class="serial-number-bottom-left">
<span class="serial-label">流水号:</span>
<span class="serial-value">{{ form.serialNo || '-' }}</span>
</div>
<div class="print-footer">
<div class="reminder">温馨提示: 请妥善保管此凭条就诊时请携带</div>
</div>
<!-- 二维码区域 -->
<div class="qr-code-section">
<div class="qr-code-container">
<div id="qrcode" ref="qrcodeRef"></div>
<div class="qr-code-label">扫码查看挂号信息</div>
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="printPreviewVisible = false">关闭</el-button>
<el-button type="primary" @click="handleBrowserPrint">打印</el-button>
</div>
</template>
<el-button @click="selectDialogVisible = false">取消 (C)</el-button>
<el-button type="primary" @click="handleConfirmSelect" :disabled="!selectedRecord">确认 (O)</el-button>
</div>
</template>
</el-dialog>
</el-dialog>
</template>
@@ -262,8 +133,12 @@ import {getCurrentInstance, reactive, ref, watch, nextTick, onMounted} from 'vue
import {getOutpatientRegistrationCurrent, reprintRegistration} from './outpatientregistration';
import {parseTime} from '@/utils/his';
import {formatDateStr} from '@/utils/index';
import {hiprint} from 'vue-plugin-hiprint';
import outpatientRegistrationTemplate from '@/components/Print/OutpatientRegistration.json';
import useUserStore from '@/store/modules/user';
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const props = defineProps({
open: {
@@ -281,8 +156,6 @@ const selectDialogVisible = ref(false);
const recordList = ref([]);
const selectedRecord = ref(null);
const currentRecord = ref(null); // 保存当前选择的记录,用于打印
const printPreviewVisible = ref(false); // 打印预览对话框显示状态
const qrcodeRef = ref(null); // 二维码容器引用
const searchForm = reactive({
cardNo: '',
@@ -334,23 +207,6 @@ watch(dialogVisible, (newVal) => {
}
});
// 监听打印预览对话框显示状态,生成二维码
watch(printPreviewVisible, (newVal) => {
if (newVal) {
// 对话框打开后等待DOM更新完成再生成二维码
nextTick(() => {
setTimeout(() => {
generateQRCode();
}, 200);
});
} else {
// 对话框关闭时清空二维码
const qrcodeElement = document.getElementById('qrcode');
if (qrcodeElement) {
qrcodeElement.innerHTML = '';
}
}
});
// 搜索挂号记录并确认补打
async function handleSearch() {
@@ -655,254 +511,100 @@ function resetSearch() {
searchForm.cardNo = '';
}
// 生成二维码
async function generateQRCode() {
nextTick(async () => {
const qrcodeElement = document.getElementById('qrcode');
if (!qrcodeElement) {
console.warn('二维码容器不存在');
return;
}
// 清空之前的二维码
qrcodeElement.innerHTML = '';
try {
// 动态导入 qrcode 库
const QRCode = await import('qrcode');
// 构建二维码内容(包含关键就诊信息)
const qrData = {
type: 'outpatient_registration',
encounterId: form.encounterId || '',
cardNo: form.cardNo || '',
serialNo: form.serialNo || '',
patientName: form.name || '',
visitTime: form.visitTime || '',
organizationName: form.organizationName || ''
};
// 将对象转换为JSON字符串作为二维码内容
const qrText = JSON.stringify(qrData);
// 使用 qrcode 库生成二维码(生成为 data URL
const qrDataUrl = await QRCode.default.toDataURL(qrText, {
width: 120,
margin: 1,
color: {
dark: '#000000',
light: '#ffffff'
}
});
// 创建 img 元素显示二维码
const img = document.createElement('img');
img.src = qrDataUrl;
img.alt = '二维码';
img.style.display = 'block';
img.style.margin = '0 auto';
qrcodeElement.appendChild(img);
} catch (error) {
console.error('生成二维码失败:', error);
qrcodeElement.innerHTML = '<div style="text-align:center;color:#999;padding:20px;font-size:12px;">二维码生成失败</div>';
}
});
}
// 显示打印预览
// 显示打印预览(使用 hiprint 打印)
function showPrintPreview() {
// 直接使用浏览器打印预览,避免 hiprint 连接错误
// 因为 hiprint 需要本地服务运行,如果服务未运行会导致连接失败
// 确保 loading 已关闭
loading.value = false;
// 验证表单数据是否已正确填充
console.log('showPrintPreview form:', form); // 调试日志
console.log('showPrintPreview currentRecord:', currentRecord.value); // 调试日志
console.log('showPrintPreview form:', form);
console.log('showPrintPreview currentRecord:', currentRecord.value);
// 如果 form 的关键字段为空,尝试从 currentRecord 重新填充
if (!form.name && currentRecord.value) {
console.log('重新填充表单数据...');
fillForm(currentRecord.value);
}
// 显示打印预览对话框
printPreviewVisible.value = true;
// 使用 hiprint 打印
printByHiprint();
}
// 浏览器打印
function handleBrowserPrint() {
const printContent = document.getElementById('print-content');
if (!printContent) {
proxy.$modal.msgError('打印内容不存在');
return;
/**
* 使用 hiprint 打印门诊挂号单(补打)
*/
function printByHiprint() {
try {
// 构建打印数据
const printData = {
patientName: form.name || '-',
sex: form.gender || '-',
age: form.age || '-',
personType: '自费',
busNo: form.cardNo || '-',
organizationName: form.organizationName || '-',
practitionerName: form.practitionerName || '-',
healthcareName: '挂号',
chargeTime: form.printTime || formatDateStr(new Date(), 'YYYY-MM-DD HH:mm:ss'),
cashier: userStore.name || '',
chargeItem: [
{
chargeItemName: '挂号费',
quantityValue: '1',
totalPrice: parseFloat(form.price || 0).toFixed(2),
dirClass: 1
},
...(parseFloat(form.activityPrice || 0) > 0 ? [{
chargeItemName: '诊疗费',
quantityValue: '1',
totalPrice: parseFloat(form.activityPrice || 0).toFixed(2),
dirClass: 1
}] : []),
...(parseFloat(form.medicalRecordFee || 0) > 0 ? [{
chargeItemName: '病历费',
quantityValue: '1',
totalPrice: parseFloat(form.medicalRecordFee || 0).toFixed(2),
dirClass: 1
}] : [])
],
displayAmount123: '¥' + parseFloat(form.totalPrice || 0).toFixed(2),
FULAMT_OWNPAY_AMT: '¥' + parseFloat(form.totalPrice || 0).toFixed(2),
SELF_CASH_VALUE: '¥' + parseFloat(form.totalPrice || 0).toFixed(2),
pictureUrl: ''
};
const result = {
data: [printData]
};
console.log('补打挂号打印数据:', printData);
// 处理模板(替换医院名称)
const printElements = JSON.parse(
JSON.stringify(outpatientRegistrationTemplate).replace(/{{HOSPITAL_NAME}}/g, userStore.hospitalName)
);
// 创建 hiprint 模板并打印
const hiprintTemplate = new hiprint.PrintTemplate({ template: printElements });
// 打印成功回调
hiprintTemplate.on('printSuccess', function (e) {
console.log('补打挂号单打印成功', e);
proxy.$modal.msgSuccess('打印成功');
dialogVisible.value = false;
});
// 打印失败回调
hiprintTemplate.on('printError', function (e) {
console.error('补打挂号单打印失败', e);
proxy.$modal.msgError('打印失败:' + (e.message || '未知错误'));
});
// 执行打印
hiprintTemplate.print2(result.data[0], {
title: '门诊挂号单(补打)',
});
} catch (error) {
console.error('hiprint 打印挂号单失败:', error);
proxy.$modal.msgError('打印失败:' + (error.message || '未知错误'));
}
// 创建新窗口用于打印
const printWindow = window.open('', '_blank');
if (!printWindow) {
proxy.$modal.msgError('无法打开打印窗口,请检查浏览器弹窗设置');
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;
}
.reprint-label-left {
position: absolute;
top: 0;
left: 0;
color: red;
font-size: 16px;
font-weight: bold;
}
.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;
}
.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 {
display: flex;
justify-content: center;
align-items: center;
}
.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>
${printContent.innerHTML}
</body>
</html>
`);
printWindow.document.close();
// 等待内容加载完成后打印
printWindow.onload = function() {
setTimeout(() => {
printWindow.print();
// 打印后关闭窗口(可选)
// printWindow.close();
}, 250);
};
}
// 选择挂号记录
@@ -941,9 +643,9 @@ async function handleConfirmSelect() {
await handleSubmit();
} catch (error) {
console.error('确认选择记录失败:', error);
proxy.$modal.msgError('处理失败: ' + (error.message || '未知错误'));
proxy.$modal.msgError('处理失败' + (error.message || '未知错误'));
loading.value = false;
}
}
}
</script>
@@ -966,174 +668,4 @@ async function handleConfirmSelect() {
color: #333;
}
/* 打印预览对话框样式 */
.print-preview-dialog {
:deep(.el-dialog__body) {
padding: 20px;
max-height: 70vh;
overflow-y: auto;
}
}
.print-content {
background: white;
padding: 20px;
font-family: Arial, sans-serif;
}
.print-header {
margin-bottom: 20px;
position: relative;
}
.reprint-label-left {
position: absolute;
top: 0;
left: 0;
color: red;
font-size: 16px;
font-weight: bold;
}
.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;
}
.info-row .label {
display: inline-block;
width: 100px;
font-weight: bold;
}
.info-row .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 {
display: flex;
justify-content: center;
align-items: center;
}
.qr-code-label {
font-size: 12px;
color: #666;
text-align: center;
}
@media print {
.qr-code-section {
page-break-inside: avoid;
}
}
</style>

View File

@@ -645,6 +645,8 @@ import useUserStore from '@/store/modules/user';
import {formatDateStr} from '@/utils/index';
import {isValidCNPhoneNumber} from '../../../utils/validate';
import {ElMessage} from 'element-plus';
import {hiprint} from 'vue-plugin-hiprint';
import outpatientRegistrationTemplate from '@/components/Print/OutpatientRegistration.json';
const patientInfo = ref({});
const eventType = ref(0);
@@ -1396,7 +1398,7 @@ function handleAdd() {
console.log('isValidCNPhoneNumber=======>', isValidCNPhoneNumber(form.value.phone));
transformedData.value = transformFormData(form.value);
console.log(transformedData, 'transformedData门诊挂号');
console.log(transformedData, 'transformedData 门诊挂号');
chargeItemIdList.value = [];
// patientInfo.value.patientId = form.value.patientId;
patientInfo.value = {
@@ -1441,6 +1443,10 @@ function handleAdd() {
patientInfo.value.busNo = res.data.busNo || '';
readCardLoading.value = false;
openDialog.value = true;
// 保存成功后使用 hiprint 打印挂号单
printRegistrationByHiprint(res.data);
// chargeItemIdList.value = res.data;
// patientInfo.value.encounterId = res.data.encounterId[0];
// precharge({
@@ -1470,6 +1476,69 @@ function handleAdd() {
});
}
/**
* 使用 hiprint 打印门诊挂号单
* @param {Object} data 挂号返回的数据
*/
function printRegistrationByHiprint(data) {
try {
// 构建打印数据
const printData = {
patientName: patientInfo.value.patientName || form.value.name || '-',
sex: patientInfo.value.genderEnum_enumText || form.value.genderEnum_enumText || '-',
age: patientInfo.value.age || form.value.age || '-',
personType: patientInfo.value.contractName || '自费',
busNo: data.busNo || registerBusNo.value || '-',
organizationName: patientInfo.value.organizationName || '-',
practitionerName: patientInfo.value.practitionerName || '-',
healthcareName: healthcareList.value.find(h => h.id === form.value.serviceTypeId)?.name || '-',
chargeTime: formatDateStr(new Date(), 'YYYY-MM-DD HH:mm:ss'),
cashier: userStore.name || '',
chargeItem: data.chargeItemList ? data.chargeItemList.map(item => ({
chargeItemName: item.itemName || item.name || '-',
quantityValue: item.quantity || '1',
totalPrice: item.price || item.totalPrice || '0',
dirClass: item.dirClass || 1
})) : [],
displayAmount123: '¥' + (data.psnCashPay || 0).toFixed(2),
FULAMT_OWNPAY_AMT: '¥' + (data.psnCashPay || 0).toFixed(2),
SELF_CASH_VALUE: '¥' + (data.psnCashPay || 0).toFixed(2),
pictureUrl: '', // 如需发票二维码可补充
};
const result = {
data: [printData]
};
console.log('挂号打印数据:', printData);
// 处理模板(替换医院名称)
const printElements = JSON.parse(
JSON.stringify(outpatientRegistrationTemplate).replace(/{{HOSPITAL_NAME}}/g, userStore.hospitalName)
);
// 创建 hiprint 模板并打印
const hiprintTemplate = new hiprint.PrintTemplate({ template: printElements });
// 打印成功回调
hiprintTemplate.on('printSuccess', function (e) {
console.log('挂号单打印成功', e);
});
// 打印失败回调
hiprintTemplate.on('printError', function (e) {
console.error('挂号单打印失败', e);
});
// 执行打印
hiprintTemplate.print2(result.data[0], {
title: '门诊挂号单',
});
} catch (error) {
console.error('hiprint 打印挂号单失败:', error);
}
}
/**
* 姓名表单获取焦点打开列表
*/