refactor(router): 优化路由配置和打印功能实现

- 统一路由配置中的代码风格,移除多余空格
- 移除医生个人报卡管理菜单项
- 移除检查管理中的医生报告快捷访问路径
- 替换浏览器打印为hiprint打印方案
- 添加vue-plugin-hiprint依赖和相关配置
- 实现门诊挂号单的hiprint打印功能
- 优化WebView环境检测逻辑和错误处理
This commit is contained in:
2026-03-10 16:28:41 +08:00
parent c65db9abc3
commit b69f312611
4 changed files with 217 additions and 628 deletions

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

@@ -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);
}
}
/**
* 姓名表单获取焦点打开列表
*/