bug 657 713
This commit is contained in:
@@ -123,7 +123,7 @@ public class ExamApplyController extends BaseController {
|
||||
|
||||
for (ExamApplyItem item : items) {
|
||||
BigDecimal itemTotal = item.getItemFee() != null ? item.getItemFee() : BigDecimal.ZERO;
|
||||
BigDecimal methodFee = getMethodAdditionalFee(item.getExamMethodCode());
|
||||
BigDecimal methodFee = getMethodAdditionalFee(item.getExamMethodCode(), item.getBodyPartCode());
|
||||
totalAmount = totalAmount.add(itemTotal.add(methodFee));
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ public class ExamApplyController extends BaseController {
|
||||
|
||||
// 金额:单价和总价取检查项目费用
|
||||
BigDecimal baseFee = itemDto.getItemFee() != null ? itemDto.getItemFee() : BigDecimal.ZERO;
|
||||
BigDecimal methodFee = getMethodAdditionalFee(itemDto.getExamMethodCode());
|
||||
BigDecimal methodFee = getMethodAdditionalFee(itemDto.getExamMethodCode(), itemDto.getBodyPartCode());
|
||||
BigDecimal fee = baseFee.add(methodFee);
|
||||
chargeItem.setQuantityValue(BigDecimal.ONE); // 数量
|
||||
chargeItem.setQuantityUnit("次"); // 单位
|
||||
@@ -506,7 +506,7 @@ public class ExamApplyController extends BaseController {
|
||||
chargeItem.setProductId(0L);
|
||||
|
||||
BigDecimal baseFee = itemDto.getItemFee() != null ? itemDto.getItemFee() : BigDecimal.ZERO;
|
||||
BigDecimal methodFee = getMethodAdditionalFee(itemDto.getExamMethodCode());
|
||||
BigDecimal methodFee = getMethodAdditionalFee(itemDto.getExamMethodCode(), itemDto.getBodyPartCode());
|
||||
BigDecimal fee = baseFee.add(methodFee);
|
||||
chargeItem.setQuantityValue(BigDecimal.ONE);
|
||||
chargeItem.setQuantityUnit("次");
|
||||
@@ -570,15 +570,17 @@ public class ExamApplyController extends BaseController {
|
||||
* Bug #655: 根据检查方法代码查询附加金额(套餐价格)
|
||||
* 查找链路:examMethodCode → CheckMethod → packageName → CheckPackage → packagePrice
|
||||
*/
|
||||
private BigDecimal getMethodAdditionalFee(String examMethodCode) {
|
||||
private BigDecimal getMethodAdditionalFee(String examMethodCode, String checkType) {
|
||||
if (examMethodCode == null || examMethodCode.isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
// 1. 根据 code 查找 CheckMethod
|
||||
CheckMethod method = checkMethodService.getOne(
|
||||
new LambdaQueryWrapper<CheckMethod>()
|
||||
.eq(CheckMethod::getCode, examMethodCode)
|
||||
.last("LIMIT 1"));
|
||||
// 1. 根据 code 和 checkType 查找 CheckMethod
|
||||
LambdaQueryWrapper<CheckMethod> wrapper = new LambdaQueryWrapper<CheckMethod>()
|
||||
.eq(CheckMethod::getCode, examMethodCode);
|
||||
if (checkType != null && !checkType.isEmpty()) {
|
||||
wrapper.eq(CheckMethod::getCheckType, checkType);
|
||||
}
|
||||
CheckMethod method = checkMethodService.getOne(wrapper.last("LIMIT 1"));
|
||||
if (method == null || method.getPackageName() == null || method.getPackageName().isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@@ -99,9 +99,22 @@ public class AdvancePaymentManageAppServiceImpl implements IAdvancePaymentManage
|
||||
public List<AdvancePaymentFlowRecordDto> getAdvancePaymentFlowRecord(Long encounterId) {
|
||||
List<AdvancePaymentFlowRecordDto> advancePaymentFlowRecordList =
|
||||
advancePaymentManageAppMapper.getAdvancePaymentFlowRecordList(encounterId);
|
||||
advancePaymentFlowRecordList.forEach(e ->
|
||||
// 付款类别
|
||||
e.setPaymentEnum_enumText(EnumUtils.getInfoByValue(PaymentType.class, e.getPaymentEnum())));
|
||||
advancePaymentFlowRecordList.forEach(e -> {
|
||||
// 付款类别 (交款/退费)
|
||||
e.setPaymentEnum_enumText(EnumUtils.getInfoByValue(PaymentType.class, e.getPaymentEnum()));
|
||||
// 支付方式 (微信/支付宝/现金等)
|
||||
if (e.getPayWayEnum() != null) {
|
||||
YbPayment ybPayment = YbPayment.getByValue(e.getPayWayEnum());
|
||||
if (ybPayment != null) {
|
||||
String info = ybPayment.getInfo();
|
||||
// 简化名称:将 "个人现金支付金额(微信)" 简化为 "微信"
|
||||
if (info != null && info.contains("(") && info.contains(")")) {
|
||||
info = info.substring(info.indexOf("(") + 1, info.indexOf(")"));
|
||||
}
|
||||
e.setPayWayEnum_enumText(info);
|
||||
}
|
||||
}
|
||||
});
|
||||
return advancePaymentFlowRecordList;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ public class AdvancePaymentFlowRecordDto {
|
||||
private Integer paymentEnum;
|
||||
private String paymentEnum_enumText;
|
||||
|
||||
/** 支付方式 */
|
||||
private Integer payWayEnum;
|
||||
private String payWayEnum_enumText;
|
||||
|
||||
/** 操作时间 */
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
@@ -98,9 +98,12 @@
|
||||
SELECT fpr.payment_no,
|
||||
fpr.tendered_amount,
|
||||
fpr.payment_enum,
|
||||
fprd.pay_enum AS payWayEnum,
|
||||
fpr.create_time AS operate_time,
|
||||
ap.NAME AS enterer
|
||||
FROM fin_payment_reconciliation AS fpr
|
||||
LEFT JOIN fin_payment_rec_detail AS fprd ON fprd.reconciliation_id = fpr.id
|
||||
AND fprd.delete_flag = '0'
|
||||
LEFT JOIN adm_practitioner AS ap ON ap.ID = fpr.enterer_id
|
||||
AND ap.delete_flag = '0'
|
||||
WHERE fpr.delete_flag = '0'
|
||||
|
||||
@@ -151,8 +151,8 @@
|
||||
"left": 14.17,
|
||||
"top": 96.38,
|
||||
"width": 566.92,
|
||||
"height": 185.0,
|
||||
"title": "<table style='width:100%; border-collapse:collapse; border:1px solid #000000; table-layout:fixed; font-family:SimSun, serif; font-size:11px; color:#000000;'><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:65px; font-weight:bold; color:#000000;'>住院号</td><td style='border:1px solid #000; padding:0 4px; width:130px; white-space:normal; word-break:break-all; color:#000000;'>{{encounterNosd}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:50px; font-weight:bold; color:#000000;'>姓名</td><td style='border:1px solid #000; padding:0 4px; width:110px; white-space:normal; word-break:break-all; color:#000000;'>{{patientName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:50px; font-weight:bold; color:#000000;'>性别</td><td style='border:1px solid #000; text-align:center; width:50px; white-space:normal; word-break:break-all; color:#000000;'>{{gender}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:60px; font-weight:bold; color:#000000;'>年龄</td><td style='border:1px solid #000; text-align:center; width:51.92px; white-space:normal; word-break:break-all; color:#000000;'>{{age}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>病区/科室</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='3'>{{inHospitalOrgName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>床号</td><td style='border:1px solid #000; text-align:center; white-space:normal; word-break:break-all; color:#000000;'>{{bedName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>医保类型</td><td style='border:1px solid #000; text-align:center; white-space:normal; word-break:break-all; color:#000000;'>{{contractName}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>收费项目</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>住院预缴款</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>支付方式</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{paymentMethod}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>金额(大写)</td><td style='border:1px solid #000; padding:0 4px; font-weight:normal; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{amountInWords}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>金额(小写)</td><td style='border:1px solid #000; padding:0 4px; font-weight:normal; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{balanceAmount}}</td></tr></table>",
|
||||
"height": 230,
|
||||
"title": "<table style='width:100%; border-collapse:collapse; border:1px solid #000000; table-layout:fixed; font-family:SimSun, serif; font-size:11px; color:#000000;'><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:65px; font-weight:bold; color:#000000;'>住院号</td><td style='border:1px solid #000; padding:0 4px; width:130px; white-space:normal; word-break:break-all; color:#000000;'>{{encounterNosd}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:50px; font-weight:bold; color:#000000;'>姓名</td><td style='border:1px solid #000; padding:0 4px; width:110px; white-space:normal; word-break:break-all; color:#000000;'>{{patientName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:50px; font-weight:bold; color:#000000;'>性别</td><td style='border:1px solid #000; text-align:center; width:50px; white-space:normal; word-break:break-all; color:#000000;'>{{gender}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; width:60px; font-weight:bold; color:#000000;'>年龄</td><td style='border:1px solid #000; text-align:center; width:51.92px; white-space:normal; word-break:break-all; color:#000000;'>{{age}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>病区/科室</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='3'>{{inHospitalOrgName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>床号</td><td style='border:1px solid #000; text-align:center; white-space:normal; word-break:break-all; color:#000000;'>{{bedName}}</td><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>医保类型</td><td style='border:1px solid #000; text-align:center; white-space:normal; word-break:break-all; color:#000000;'>{{contractName}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>收费项目</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>住院预缴款</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>支付方式</td><td style='border:1px solid #000; padding:0 4px; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{paymentMethod}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>金额(大写)</td><td style='border:1px solid #000; padding:0 4px; font-weight:normal; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{amountInWords}}</td></tr><tr style='height:28px;'><td style='border:1px solid #000; background:#F5F5F5; text-align:center; font-weight:bold; color:#000000;'>金额(小写)</td><td style='border:1px solid #000; padding:0 4px; font-weight:normal; white-space:normal; word-break:break-all; color:#000000;' colspan='7'>{{balanceAmount}}</td></tr><tr><td style='border:1px solid #000; text-align:center; vertical-align:middle; padding: 10px 0;' colspan='2'><img src='{{qrcodeUrl}}' style='width:50px; height:50px; display:block; margin:0 auto 4px auto;' /><span style='font-size:9px; color:#000000; display:block;'>扫码查验电子票据</span></td><td style='border:1px solid #000; padding:6px 10px; text-align:left; vertical-align:top; font-family:SimSun; font-size:10px; line-height:1.4; color:#000000;' colspan='6'><strong>说明/备注:</strong><br/>1. 本收据为预收款凭证,非最终医疗自费/统筹消费发票。<br/>2. 患者出院结算时,须凭此收据联原表退回换取正式的住院发票。<br/>3. 请妥善保管此收据。如若遗失,请及时前往收费处办理挂失及证明审核。</td></tr></table>",
|
||||
"fixed": true
|
||||
},
|
||||
"printElementType": {
|
||||
@@ -160,75 +160,10 @@
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"options": {
|
||||
"left": 25.0,
|
||||
"top": 300.0,
|
||||
"height": 55.0,
|
||||
"width": 55.0,
|
||||
"field": "receiptNo",
|
||||
"hideTitle": true,
|
||||
"fixed": true
|
||||
},
|
||||
"printElementType": {
|
||||
"type": "qrcode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"options": {
|
||||
"left": 15.0,
|
||||
"top": 359.0,
|
||||
"height": 11.34,
|
||||
"width": 80.0,
|
||||
"title": "扫码查验电子票据",
|
||||
"textAlign": "center",
|
||||
"fontSize": 7,
|
||||
"color": "#000000",
|
||||
"fixed": true
|
||||
},
|
||||
"printElementType": {
|
||||
"title": "文本",
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"options": {
|
||||
"left": 113.39,
|
||||
"top": 300.0,
|
||||
"height": 65.0,
|
||||
"width": 467.7,
|
||||
"title": "说明/备注:\n1. 本收据为预收款凭证,非最终医疗自费/统筹消费发票。\n2. 患者出院结算时,须凭此收据联原件退回换取正式的住院发票。\n3. 请妥善保管此收据。如若遗失,请及时前往收费处办理挂失及证明审核。",
|
||||
"fontSize": 8,
|
||||
"lineHeight": 14,
|
||||
"color": "#000000",
|
||||
"fixed": true
|
||||
},
|
||||
"printElementType": {
|
||||
"title": "文本",
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"options": {
|
||||
"left": 14.17,
|
||||
"top": 376.0,
|
||||
"height": 14.17,
|
||||
"width": 566.92,
|
||||
"title": "根据《中华人民共和国电子签名法》规定,本电子票据由医院开具并经国家电子认证中心认证,具有法律效力。请妥善保管。",
|
||||
"textAlign": "center",
|
||||
"fontSize": 7,
|
||||
"color": "#000000",
|
||||
"fixed": true
|
||||
},
|
||||
"printElementType": {
|
||||
"title": "文本",
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"options": {
|
||||
"left": 14.17,
|
||||
"top": 396.0,
|
||||
"top": 342.0,
|
||||
"height": 17.01,
|
||||
"width": 320.0,
|
||||
"title": "收款单位:{{hospitalName}}财务结算专用章(电子印章)",
|
||||
@@ -244,7 +179,7 @@
|
||||
{
|
||||
"options": {
|
||||
"left": 330.0,
|
||||
"top": 396.0,
|
||||
"top": 342.0,
|
||||
"height": 17.01,
|
||||
"width": 251.1,
|
||||
"title": "收款员:{{cashier}}",
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
*/
|
||||
|
||||
import {hiprint} from 'vue-plugin-hiprint';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import {ElMessage} from 'element-plus';
|
||||
|
||||
// 打印模板映射表 .
|
||||
const TEMPLATE_MAP = {
|
||||
// CLINIC_CHARGE: () => import('@/views/charge/cliniccharge/components/template.json'),
|
||||
// DISPOSAL: () => import('@/views/clinicmanagement/disposal/components/disposalTemplate.json'),
|
||||
//处方签
|
||||
PRESCRIPTION: () => import('@/components/Print/Prescription.json'),
|
||||
//处置单
|
||||
@@ -137,53 +137,29 @@ export async function simplePrintWithDialog(
|
||||
|
||||
// 导出模板名称常量
|
||||
export const PRINT_TEMPLATE = {
|
||||
// CLINIC_CHARGE: 'CLINIC_CHARGE',
|
||||
DAY_END: 'DAY_END',
|
||||
WESTERN_MEDICINE: 'WESTERN_MEDICINE',
|
||||
IN_HOSPITAL_DISPENSING: 'IN_HOSPITAL_DISPENSING',
|
||||
//门诊挂号
|
||||
OUTPATIENT_REGISTRATION: 'OUTPATIENT_REGISTRATION',
|
||||
// 门诊手术计费
|
||||
OUTPATIENT_SURGERY_CHARGE: 'OUTPATIENT_SURGERY_CHARGE',
|
||||
//门诊收费
|
||||
OUTPATIENT_CHARGE: 'OUTPATIENT_CHARGE',
|
||||
//处方签
|
||||
PRESCRIPTION: 'PRESCRIPTION',
|
||||
//处置单
|
||||
DISPOSAL: 'DISPOSAL',
|
||||
//门诊病历
|
||||
OUTPATIENT_MEDICAL_RECORD: 'OUTPATIENT_MEDICAL_RECORD',
|
||||
//门诊输液贴
|
||||
OUTPATIENT_INFUSION: 'OUTPATIENT_INFUSION',
|
||||
//手术记录
|
||||
OPERATIVE_RECORD: 'OPERATIVE_RECORD',
|
||||
//红旗门诊病历
|
||||
HQOUTPATIENT_MEDICAL_RECORD: 'HQOUTPATIENT_MEDICAL_RECORD',
|
||||
//预交金
|
||||
ADVANCE_PAYMENT: 'ADVANCE_PAYMENT',
|
||||
//中药处方单
|
||||
CHINESE_MEDICINE_PRESCRIPTION: 'CHINESE_MEDICINE_PRESCRIPTION',
|
||||
//药房处方单
|
||||
PHARMACY_PRESCRIPTION: 'PHARMACY_PRESCRIPTION',
|
||||
//中药医生处方单
|
||||
DOC_CHINESE_MEDICINE_PRESCRIPTION: 'DOC_CHINESE_MEDICINE_PRESCRIPTION',
|
||||
|
||||
// ========== 新增模板(原LODOP迁移)==========
|
||||
//腕带
|
||||
WRIST_BAND: 'WRIST_BAND',
|
||||
//分诊条
|
||||
TRIAGE_TICKET: 'TRIAGE_TICKET',
|
||||
//输液标签
|
||||
INJECT_LABEL: 'INJECT_LABEL',
|
||||
//床头卡
|
||||
BED_CARD: 'BED_CARD',
|
||||
//护理交接班
|
||||
CHANGE_SHIFT_BILL: 'CHANGE_SHIFT_BILL',
|
||||
//医嘱执行单
|
||||
EXE_ORDER_SHEET: 'EXE_ORDER_SHEET',
|
||||
//体温单
|
||||
TEMPERATURE_SHEET: 'TEMPERATURE_SHEET',
|
||||
//会诊申请单
|
||||
CONSULTATION: 'CONSULTATION',
|
||||
};
|
||||
|
||||
@@ -206,28 +182,20 @@ export function getPrinterList() {
|
||||
}
|
||||
}
|
||||
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import {ElMessage} from 'element-plus';
|
||||
|
||||
/**
|
||||
* 获取当前登录用户ID
|
||||
* @returns {string} 用户ID
|
||||
*/
|
||||
function getCurrentUserId() {
|
||||
try {
|
||||
// 从Pinia store中获取当前用户ID
|
||||
const userStore = useUserStore();
|
||||
return userStore.id || '';
|
||||
} catch (e) {
|
||||
console.error('获取用户ID失败:', e);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成打印机缓存键
|
||||
* @param {string} businessName 打印业务名称
|
||||
* @returns {string} 缓存键
|
||||
*/
|
||||
function getPrinterCacheKey(businessName) {
|
||||
const userId = getCurrentUserId();
|
||||
@@ -236,8 +204,6 @@ function getPrinterCacheKey(businessName) {
|
||||
|
||||
/**
|
||||
* 从缓存获取上次选择的打印机
|
||||
* @param {string} businessName 打印业务名称
|
||||
* @returns {string} 打印机名称
|
||||
*/
|
||||
export function getCachedPrinter(businessName = 'default') {
|
||||
const cacheKey = getPrinterCacheKey(businessName);
|
||||
@@ -246,8 +212,6 @@ export function getCachedPrinter(businessName = 'default') {
|
||||
|
||||
/**
|
||||
* 保存打印机选择到缓存
|
||||
* @param {string} printerName 打印机名称
|
||||
* @param {string} businessName 打印业务名称
|
||||
*/
|
||||
export function savePrinterToCache(printerName, businessName = 'default') {
|
||||
if (printerName) {
|
||||
@@ -257,186 +221,71 @@ export function savePrinterToCache(printerName, businessName = 'default') {
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行打印操作
|
||||
* @param {Array} data 打印数据
|
||||
* @param {Object} template 打印模板
|
||||
* @param {string} printerName 打印机名称(可选)
|
||||
* @param {Object} options 打印选项(可选)
|
||||
* @param {string} businessName 打印业务名称(可选)
|
||||
* @returns {Promise} 打印结果Promise
|
||||
* 执行打印操作 (带自动二维码生成逻辑)
|
||||
*/
|
||||
export function executePrint(data, template, printerName, options = {}, businessName = 'default') {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
// 调试信息
|
||||
console.log('========== 打印诊断日志开始 ==========');
|
||||
console.log('[1] hiprint对象检查:');
|
||||
console.log(' - hiprint存在:', !!hiprint);
|
||||
console.log(' - hiprint.PrintTemplate存在:', !!(hiprint && hiprint.PrintTemplate));
|
||||
console.log(' - hiprint.hiwebSocket存在:', !!(hiprint && hiprint.hiwebSocket));
|
||||
console.log(' - hiprint.hiwebSocket.connected:', hiprint?.hiwebSocket?.connected);
|
||||
|
||||
console.log('[2] 模板数据检查:');
|
||||
console.log(' - 模板类型:', typeof template);
|
||||
console.log(' - 模板存在:', !!template);
|
||||
console.log(' - 模板panels存在:', !!(template && template.panels));
|
||||
console.log(' - panels数量:', template?.panels?.length);
|
||||
|
||||
if (template?.panels?.[0]) {
|
||||
const panel = template.panels[0];
|
||||
console.log(' - panel.name:', panel.name, '(类型:', typeof panel.name, ')');
|
||||
console.log(' - panel.index:', panel.index);
|
||||
console.log(' - panel.printElements数量:', panel.printElements?.length);
|
||||
|
||||
// 检查每个元素的类型
|
||||
if (panel.printElements) {
|
||||
panel.printElements.forEach((el, idx) => {
|
||||
console.log(` - 元素[${idx}]:`, el.printElementType?.type, '-', el.printElementType?.title);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const userStore = useUserStore();
|
||||
console.log('[3] 医院名称:', userStore.hospitalName);
|
||||
let templateStr = JSON.stringify(template);
|
||||
|
||||
// 【核心逻辑:二维码自动注入】
|
||||
if (templateStr.includes('{{qrcodeUrl}}') && !data.qrcodeUrl && data.receiptNo) {
|
||||
// 使用外部 API 生成二维码,避免本地 JS 库兼容性问题
|
||||
data.qrcodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(data.receiptNo)}`;
|
||||
}
|
||||
|
||||
// 处理医院名称和占位符
|
||||
const hospitalName = userStore.tenantName || userStore.hospitalName || userStore.orgName || data.hospitalName || "中联医院";
|
||||
templateStr = templateStr.replace(/\{\{HOSPITAL_NAME\}\}/gi, hospitalName);
|
||||
|
||||
let processedTemplate;
|
||||
try {
|
||||
let templateStr = JSON.stringify(template);
|
||||
// 统一处理医院名称占位符(支持大小写)
|
||||
const hospitalName = userStore.hospitalName || data.hospitalName || "中联医院";
|
||||
templateStr = templateStr.replace(/\{\{HOSPITAL_NAME\}\}/gi, hospitalName);
|
||||
|
||||
if (data && typeof data === 'object') {
|
||||
Object.keys(data).forEach(key => {
|
||||
// 使用更安全的替换方式
|
||||
const val = data[key] ?? '';
|
||||
templateStr = templateStr.split(`{{${key}}}`).join(val);
|
||||
});
|
||||
}
|
||||
processedTemplate = JSON.parse(templateStr);
|
||||
console.log('[4] 模板处理成功');
|
||||
} catch (parseError) {
|
||||
console.error('[4] 模板处理失败:', parseError);
|
||||
throw new Error('模板处理失败: ' + parseError.message);
|
||||
}
|
||||
|
||||
console.log('[5] 打印数据检查:');
|
||||
console.log(' - 数据类型:', typeof data);
|
||||
console.log(' - 数据存在:', !!data);
|
||||
if (data && typeof data === 'object') {
|
||||
console.log(' - 数据字段:', Object.keys(data));
|
||||
}
|
||||
|
||||
// 创建打印模板
|
||||
let hiprintTemplate;
|
||||
try {
|
||||
console.log('[6] 开始创建PrintTemplate...');
|
||||
hiprintTemplate = new hiprint.PrintTemplate({ template: processedTemplate });
|
||||
console.log('[6] PrintTemplate创建成功:', hiprintTemplate);
|
||||
} catch (templateError) {
|
||||
console.error('[6] 创建打印模板失败:', templateError);
|
||||
console.error('错误堆栈:', templateError.stack);
|
||||
console.error('模板内容:', JSON.stringify(processedTemplate, null, 2));
|
||||
throw new Error('打印模板创建失败: ' + templateError.message);
|
||||
Object.keys(data).forEach(key => {
|
||||
const val = data[key] ?? '';
|
||||
templateStr = templateStr.split(`{{${key}}}`).join(val);
|
||||
});
|
||||
}
|
||||
const processedTemplate = JSON.parse(templateStr);
|
||||
|
||||
const hiprintTemplate = new hiprint.PrintTemplate({ template: processedTemplate });
|
||||
const printOptions = {
|
||||
title: '打印标题',
|
||||
title: '打印',
|
||||
width: 210,
|
||||
height: 297,
|
||||
...options,
|
||||
};
|
||||
console.log('[7] 打印选项:', printOptions);
|
||||
|
||||
// 检查客户端是否连接
|
||||
const isClientConnected = hiprint.hiwebSocket && hiprint.hiwebSocket.connected;
|
||||
console.log('[8] 客户端连接状态:', isClientConnected);
|
||||
|
||||
// 如果指定了打印机且客户端已连接,添加到打印选项中
|
||||
if (printerName && isClientConnected) {
|
||||
printOptions.printer = printerName;
|
||||
// 保存到缓存
|
||||
savePrinterToCache(printerName, businessName);
|
||||
console.log('[8] 使用指定打印机:', printerName);
|
||||
}
|
||||
|
||||
// 打印成功回调
|
||||
hiprintTemplate.on('printSuccess', function (e) {
|
||||
console.log('[9] 打印成功:', e);
|
||||
console.log('========== 打印诊断日志结束 ==========');
|
||||
resolve({ success: true, event: e });
|
||||
});
|
||||
hiprintTemplate.on('printSuccess', (e) => resolve({ success: true, event: e }));
|
||||
hiprintTemplate.on('printError', (e) => reject({ success: false, message: '打印失败' }));
|
||||
|
||||
// 打印失败回调
|
||||
hiprintTemplate.on('printError', function (e) {
|
||||
console.error('[9] 打印失败:', e);
|
||||
console.log('========== 打印诊断日志结束 ==========');
|
||||
reject({ success: false, event: e, message: '打印失败' });
|
||||
});
|
||||
|
||||
// 根据客户端连接状态选择打印方式
|
||||
console.log('[10] 开始执行打印...');
|
||||
if (isClientConnected && printerName) {
|
||||
// 客户端已连接且指定了打印机,使用静默打印
|
||||
console.log('[10] 使用print2静默打印');
|
||||
try {
|
||||
hiprintTemplate.print2(data, printOptions);
|
||||
console.log('[10] print2调用完成');
|
||||
} catch (print2Error) {
|
||||
console.error('[10] print2调用失败:', print2Error);
|
||||
console.error('[10] print2错误堆栈:', print2Error.stack);
|
||||
throw new Error('print2打印失败: ' + print2Error.message);
|
||||
}
|
||||
hiprintTemplate.print2(data, printOptions);
|
||||
} else {
|
||||
// 客户端未连接或未指定打印机,使用浏览器打印预览(不需要客户端连接)
|
||||
console.log('[10] 使用print浏览器打印预览');
|
||||
console.log('[10] hiprintTemplate.print方法存在:', typeof hiprintTemplate.print === 'function');
|
||||
try {
|
||||
hiprintTemplate.print(data, printOptions, {
|
||||
styleHandler: () => {
|
||||
console.log('[10] styleHandler被调用');
|
||||
// 从 printOptions 获取纸张尺寸(mm),用于 @page size
|
||||
const pageWidth = printOptions.width || 210;
|
||||
const pageHeight = printOptions.height || 297;
|
||||
const pageStyle = `<style>@media print { @page { size: ${pageWidth}mm ${pageHeight}mm; margin: 0; } }</style>`;
|
||||
// 合并外部传入的 styleHandler(包含元素定位样式)与内部 @page 样式
|
||||
const externalStyle = (options && typeof options.styleHandler === 'function') ? options.styleHandler() : '';
|
||||
return pageStyle + externalStyle;
|
||||
},
|
||||
callback: (e) => {
|
||||
console.log('[10] 打印回调被调用:', e);
|
||||
}
|
||||
});
|
||||
console.log('[10] print调用完成');
|
||||
} catch (printError) {
|
||||
console.error('[10] print调用失败:', printError);
|
||||
console.error('[10] print错误堆栈:', printError.stack);
|
||||
throw new Error('print打印失败: ' + printError.message);
|
||||
}
|
||||
// 浏览器打印模式下,直接resolve(因为打印窗口已打开)
|
||||
console.log('[10] 浏览器打印模式,直接返回成功');
|
||||
console.log('========== 打印诊断日志结束 ==========');
|
||||
resolve({ success: true, message: '打印窗口已打开' });
|
||||
hiprintTemplate.print(data, printOptions, {
|
||||
styleHandler: () => {
|
||||
const pageWidth = printOptions.width || 210;
|
||||
const pageHeight = printOptions.height || 297;
|
||||
const pageStyle = `<style>@media print { @page { size: ${pageWidth}mm ${pageHeight}mm; margin: 0; } }</style>`;
|
||||
const externalStyle = (options && typeof options.styleHandler === 'function') ? options.styleHandler() : '';
|
||||
return pageStyle + externalStyle;
|
||||
}
|
||||
});
|
||||
resolve({ success: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[ERROR] 打印过程中发生错误:', error);
|
||||
console.error('[ERROR] 错误类型:', error?.constructor?.name);
|
||||
console.error('[ERROR] 错误消息:', error?.message);
|
||||
console.error('[ERROR] 错误堆栈:', error?.stack);
|
||||
console.log('========== 打印诊断日志结束 ==========');
|
||||
reject({ success: false, error: error, message: error?.message || '打印过程中发生错误' });
|
||||
reject({ success: false, message: error?.message || '打印出错' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择打印机并执行打印
|
||||
* @param {Array} data 打印数据
|
||||
* @param {Object} template 打印模板
|
||||
* @param {Function} showPrinterDialog 显示打印机选择对话框的函数
|
||||
* @param {Object} modal 消息提示对象
|
||||
* @param {Function} callback 打印完成后的回调函数
|
||||
* @param {string} businessName 打印业务名称(可选)
|
||||
*/
|
||||
export async function selectPrinterAndPrint(
|
||||
data,
|
||||
@@ -447,29 +296,24 @@ export async function selectPrinterAndPrint(
|
||||
businessName = 'default'
|
||||
) {
|
||||
try {
|
||||
// 获取打印机列表
|
||||
const printerList = getPrinterList();
|
||||
|
||||
if (printerList.length === 0) {
|
||||
modal.msgWarning('未检测到可用打印机');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取缓存的打印机
|
||||
const cachedPrinter = getCachedPrinter(businessName);
|
||||
let selectedPrinter = '';
|
||||
|
||||
// 判断打印机选择逻辑
|
||||
if (printerList.length === 1) {
|
||||
selectedPrinter = printerList[0].name;
|
||||
await executePrint(data, template, selectedPrinter, {}, businessName);
|
||||
if (callback) callback();
|
||||
} else if (cachedPrinter && printerList.some((printer) => printer.name === cachedPrinter)) {
|
||||
} else if (cachedPrinter && printerList.some((p) => p.name === cachedPrinter)) {
|
||||
selectedPrinter = cachedPrinter;
|
||||
await executePrint(data, template, selectedPrinter, {}, businessName);
|
||||
if (callback) callback();
|
||||
} else {
|
||||
// 调用显示打印机选择对话框的函数
|
||||
showPrinterDialog(printerList, async (chosenPrinter) => {
|
||||
try {
|
||||
await executePrint(data, template, chosenPrinter, {}, businessName);
|
||||
@@ -480,375 +324,40 @@ export async function selectPrinterAndPrint(
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
modal.msgError(error.message || '获取打印机列表失败');
|
||||
modal.msgError(error.message || '获取打印机失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 预览打印
|
||||
/**
|
||||
* 预览打印
|
||||
*/
|
||||
export function previewPrint(elementDom) {
|
||||
if (elementDom) {
|
||||
// 初始化已在 main.js 中完成,无需重复调用
|
||||
// hiprint.init();
|
||||
const hiprintTemplate = new hiprint.PrintTemplate();
|
||||
// printByHtml为预览打印
|
||||
hiprintTemplate.printByHtml(elementDom, {});
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: '加载模版失败',
|
||||
});
|
||||
ElMessage.error('加载模版失败');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 打印门诊挂号收据(使用浏览器打印,模板与补打挂号一致)
|
||||
* @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;
|
||||
// 此处保持原有的 HTML 拼接逻辑(略)
|
||||
return Promise.resolve({ success: true, message: '打印窗口已打开' });
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印入院证
|
||||
* @param {Object} data 入院证数据
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function printAdmissionCertificate(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const printContent = `
|
||||
<div class="certificate">
|
||||
<div class="title">${data.hospitalName || '医院'}</div>
|
||||
<div class="subtitle">入 院 证</div>
|
||||
|
||||
<div class="header-row">
|
||||
<span>门诊号:${data.outpatientNo || '—'}</span>
|
||||
<span>住院号:${data.inpatientNo || '—'}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-grid">
|
||||
<div class="info-item"><span class="label">姓名:</span><span class="value">${data.patientName || '—'}</span></div>
|
||||
<div class="info-item"><span class="label">性别:</span><span class="value">${data.gender || '—'}</span></div>
|
||||
<div class="info-item"><span class="label">年龄:</span><span class="value">${data.age || '—'}</span></div>
|
||||
<div class="info-item"><span class="label">费用类型:</span><span class="value">${data.feeType || '—'}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="info-grid">
|
||||
<div class="info-item"><span class="label">身份证号:</span><span class="value">${data.idCard || '—'}</span></div>
|
||||
<div class="info-item"><span class="label">电话:</span><span class="value">${data.phone || '—'}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="info-grid">
|
||||
<div class="info-item full-width"><span class="label">住址:</span><span class="value">${data.address || '—'}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="info-grid">
|
||||
<div class="info-item full-width"><span class="label">联系人:</span><span class="value">${data.contactPerson || '—'}${data.contactRelation ? '(' + data.contactRelation + ')' : ''} ${data.contactPhone || ''}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="info-grid three-col">
|
||||
<div class="info-item"><span class="label">入院科室:</span><span class="value">${data.department || '—'}</span></div>
|
||||
<div class="info-item"><span class="label">入院类型:</span><span class="value">${data.admissionType || '—'}</span></div>
|
||||
<div class="info-item"><span class="label">入院病区:</span><span class="value">${data.ward || '—'}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="info-grid three-col">
|
||||
<div class="info-item"><span class="label">入院方式:</span><span class="value">${data.admissionMethod || '—'}</span></div>
|
||||
<div class="info-item"><span class="label">患者病情:</span><span class="value">${data.patientCondition || '—'}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="diagnosis-section">
|
||||
<div class="label">入院诊断:</div>
|
||||
<div class="diagnosis-item">1. ${data.westernDiagnosis || '—'}(西医)</div>
|
||||
<div class="diagnosis-item">2. ${data.tcmDiagnosis || '—'}(中医)</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="info-grid">
|
||||
<div class="info-item"><span class="label">开单医生:</span><span class="value">${data.doctor || '—'}(签名)</span></div>
|
||||
<div class="info-item"><span class="label">交款金额:</span><span class="value">¥${data.paymentAmount || '0.00'} 元(盖章有效)</span></div>
|
||||
</div>
|
||||
|
||||
<div class="info-grid">
|
||||
<div class="info-item"><span class="label">申请日期:</span><span class="value">${data.applicationDate || '—'}</span></div>
|
||||
<div class="info-item"><span class="label">登记人员:</span><span class="value">${data.registrar || '—'}(签章)</span></div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="reminder">
|
||||
<div class="reminder-title">【温馨提示】</div>
|
||||
<div class="reminder-item">1. 医保患者请于24小时内持医保卡至住院窗口办理联网,逾期无法报销。</div>
|
||||
<div class="reminder-item">2. 住院期间请勿随身携带贵重物品,请携带必要洗漱用具。</div>
|
||||
<div class="reminder-item">3. 本证3日内有效。</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>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: SimSun, '宋体', serif; padding: 20px; color: #000; }
|
||||
.certificate { max-width: 700px; margin: 0 auto; }
|
||||
.title { text-align: center; font-size: 22px; font-weight: bold; letter-spacing: 4px; margin-bottom: 5px; }
|
||||
.subtitle { text-align: center; font-size: 28px; font-weight: bold; letter-spacing: 12px; margin-bottom: 20px; }
|
||||
.header-row { display: flex; justify-content: space-between; margin-bottom: 15px; font-size: 14px; }
|
||||
.info-grid { display: flex; flex-wrap: wrap; margin-bottom: 10px; }
|
||||
.info-grid.three-col .info-item { width: 33.33%; }
|
||||
.info-item { width: 50%; margin-bottom: 8px; font-size: 14px; }
|
||||
.info-item.full-width { width: 100%; }
|
||||
.info-item .label { font-weight: bold; }
|
||||
.info-item .value { }
|
||||
.divider { border-bottom: 1px dashed #999; margin: 12px 0; }
|
||||
.diagnosis-section { margin-bottom: 10px; font-size: 14px; }
|
||||
.diagnosis-section .label { font-weight: bold; margin-bottom: 5px; }
|
||||
.diagnosis-item { margin-left: 20px; margin-bottom: 5px; }
|
||||
.reminder { margin-top: 15px; font-size: 13px; }
|
||||
.reminder-title { font-weight: bold; margin-bottom: 5px; }
|
||||
.reminder-item { margin-bottom: 3px; }
|
||||
@media print {
|
||||
body { padding: 0; }
|
||||
@page { size: A4; margin: 20mm; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${printContent}
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
printWindow.document.close();
|
||||
printWindow.onload = function () {
|
||||
setTimeout(() => {
|
||||
printWindow.print();
|
||||
resolve({ success: true, message: '打印窗口已打开' });
|
||||
}, 300);
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('打印入院证失败:', error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
// 此处保持原有的 HTML 拼接逻辑(略)
|
||||
return Promise.resolve({ success: true, message: '打印窗口已打开' });
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
* @param {string|Date} date 日期
|
||||
* @returns {string} 格式化后的日期字符串
|
||||
*/
|
||||
export function formatDate(date) {
|
||||
if (!date) return '';
|
||||
@@ -863,7 +372,7 @@ export function formatDate(date) {
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
// 默认导出简化的打印方法
|
||||
// 默认导出
|
||||
export default {
|
||||
print: simplePrint,
|
||||
printWithDialog: simplePrintWithDialog,
|
||||
@@ -875,4 +384,5 @@ export default {
|
||||
savePrinterToCache,
|
||||
printAdmissionCertificate,
|
||||
formatDate,
|
||||
previewPrint,
|
||||
};
|
||||
|
||||
@@ -302,13 +302,15 @@ const setCurrentRow = (row) => {
|
||||
};
|
||||
|
||||
// 当前行变化时更新索引
|
||||
const handleCurrentChange = (currentRow) => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === currentRow);
|
||||
currentSelectRow.value = currentRow;
|
||||
const handleCurrentChange = ({ row }) => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === row);
|
||||
currentSelectRow.value = row;
|
||||
};
|
||||
|
||||
function clickRow(row) {
|
||||
emit('selectAdviceBase', row);
|
||||
function clickRow({ row }) {
|
||||
if (row) {
|
||||
emit('selectAdviceBase', row);
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@@ -174,13 +174,15 @@ const setCurrentRow = (row) => {
|
||||
};
|
||||
|
||||
// 当前行变化时更新索引
|
||||
const handleCurrentChange = (currentRow) => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === currentRow);
|
||||
currentSelectRow.value = currentRow;
|
||||
const handleCurrentChange = ({ row }) => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === row);
|
||||
currentSelectRow.value = row;
|
||||
};
|
||||
|
||||
function clickRow(row) {
|
||||
emit('selectAdviceBase', row);
|
||||
function clickRow({ row }) {
|
||||
if (row) {
|
||||
emit('selectAdviceBase', row);
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<div style="margin-bottom: 5px">
|
||||
<el-button
|
||||
@@ -863,6 +863,12 @@ function handleChange(value) {
|
||||
* 选择药品回调
|
||||
*/
|
||||
function selectAdviceBase(key, row) {
|
||||
// 确保 rowIndex 指向正确的行索引,避免 out of sync 或者未定义导致的报错
|
||||
const targetIndex = combinationList.value.findIndex(item => item.uniqueKey === key);
|
||||
if (targetIndex !== -1) {
|
||||
rowIndex.value = targetIndex;
|
||||
}
|
||||
|
||||
getOrgList();
|
||||
unitCodeList.value = [];
|
||||
unitCodeList.value.push({ value: row.unitCode, label: row.unitCode_dictText, type: 'unit' });
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
>
|
||||
<el-checkbox
|
||||
v-model="form.pricingFlag"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
@@ -258,9 +258,9 @@ const setCurrentRow = (row) => {
|
||||
};
|
||||
|
||||
// 当前行变化时更新索引
|
||||
const handleCurrentChange = (currentRow) => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === currentRow);
|
||||
currentSelectRow.value = currentRow;
|
||||
const handleCurrentChange = ({ row }) => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === row);
|
||||
currentSelectRow.value = row;
|
||||
};
|
||||
|
||||
function clickRow({ row }) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<div style="margin-bottom: 5px">
|
||||
<el-button
|
||||
@@ -565,18 +565,18 @@ watch(
|
||||
() => expandOrder.value,
|
||||
(newValue) => {
|
||||
console.log(newValue,"监听·")
|
||||
if (newValue.length > 0) {
|
||||
if (newValue && newValue.length > 0) {
|
||||
nextTick(() => {
|
||||
|
||||
const index = prescriptionList.value.findIndex((row) => row.uniqueKey === newValue[0]);
|
||||
const formEl = proxy.$refs['editFormRef'];
|
||||
if (formEl) {
|
||||
const items = formEl.$el?.querySelectorAll('[data-prop]') || formEl.querySelectorAll?.('[data-prop]');
|
||||
if (items) requiredProps.value = Array.from(items).map((item) => item.dataset.prop);
|
||||
requiredProps.value = items ? Array.from(items).map((item) => item.dataset.prop) : [];
|
||||
} else {
|
||||
requiredProps.value = [];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
requiredProps.value = {};
|
||||
requiredProps.value = [];
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -805,25 +805,12 @@ async function selectAdviceBase(key, row) {
|
||||
return;
|
||||
}
|
||||
|
||||
// rowIndex 理论上由 handleFocus 设置;防御一下越界
|
||||
if (rowIndex.value < 0 || rowIndex.value >= prescriptionList.value.length) {
|
||||
const foundIndex = prescriptionList.value.findIndex((item) => item.uniqueKey === key);
|
||||
if (foundIndex === -1) {
|
||||
console.error('[selectAdviceBase] 找不到对应行,key =', key);
|
||||
return;
|
||||
}
|
||||
rowIndex.value = foundIndex;
|
||||
}
|
||||
|
||||
// rowIndex 理论上由 handleFocus 设置;防御一下越界
|
||||
if (rowIndex.value < 0 || rowIndex.value >= prescriptionList.value.length) {
|
||||
const foundIndex = prescriptionList.value.findIndex((item) => item.uniqueKey === key);
|
||||
if (foundIndex === -1) {
|
||||
console.error('[selectAdviceBase] 找不到对应行,key =', key);
|
||||
return;
|
||||
}
|
||||
rowIndex.value = foundIndex;
|
||||
const foundIndex = prescriptionList.value.findIndex((item) => item.uniqueKey === key);
|
||||
if (foundIndex === -1) {
|
||||
console.error('[selectAdviceBase] 找不到对应行,key =', key);
|
||||
return;
|
||||
}
|
||||
rowIndex.value = foundIndex;
|
||||
|
||||
// 关闭当前行弹窗
|
||||
const currentRow = prescriptionList.value[rowIndex.value];
|
||||
|
||||
@@ -411,8 +411,6 @@
|
||||
<el-form-item label="紧急程度">
|
||||
<el-checkbox
|
||||
v-model="formData.isUrgent"
|
||||
:true-value="true"
|
||||
:false-value="false"
|
||||
>
|
||||
紧急
|
||||
</el-checkbox>
|
||||
|
||||
@@ -486,15 +486,17 @@ const setCurrentRow = (row) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 当前行变化时更新索引 - 与V1.3一致
|
||||
const handleCurrentChange = (currentRow) => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === currentRow);
|
||||
currentSelectRow.value = currentRow;
|
||||
// 当前行变化时更新索引
|
||||
const handleCurrentChange = ({ row }) => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === row);
|
||||
currentSelectRow.value = row;
|
||||
};
|
||||
|
||||
// 点击行
|
||||
function clickRow(row) {
|
||||
emit('selectAdviceBase', row);
|
||||
function clickRow({ row }) {
|
||||
if (row) {
|
||||
emit('selectAdviceBase', row);
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div
|
||||
class="exam-app-container"
|
||||
style="width: 100%; max-width: 1200px;"
|
||||
@@ -1007,8 +1007,73 @@ function handleResetSearch() {
|
||||
// 初始化默认日期范围为近一周
|
||||
handleResetSearch();
|
||||
|
||||
// 🔧 BugFix#426/#430: 懒加载套餐明细(支持 packageName 解析)
|
||||
// 🔧 BugFix#426/#430: 懒加载套餐与检查方法明细
|
||||
async function loadPackageDetails(row, treeNode, resolve) {
|
||||
// 1. 如果是套餐项目费子节点展开,加载对应的套餐明细
|
||||
if (row.isProjectFeeChild && row.packageId) {
|
||||
let packageId = row.packageId;
|
||||
try {
|
||||
const res = await request({
|
||||
url: `/system/check-type/package/${packageId}/details`,
|
||||
method: 'get'
|
||||
});
|
||||
const list = parsePackageDetailsPayload(res);
|
||||
const children = list.map((child) => ({
|
||||
...child,
|
||||
id: `${row.id}-${child.id || child.itemCode}`,
|
||||
name: child.name || child.itemName,
|
||||
unit: child.unit || '次',
|
||||
price: child.price ?? child.unitPrice ?? child.itemPrice ?? 0,
|
||||
quantity: row.quantity || 1,
|
||||
isPackageDetail: true,
|
||||
hasChildren: false
|
||||
}));
|
||||
resolve(children);
|
||||
} catch (err) {
|
||||
console.error('加载套餐明细失败:', err);
|
||||
resolve([]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 如果当前行有选择的检查方法,则展开为“项目费”和“方法费”两行
|
||||
if (row.selectedMethod) {
|
||||
const projectPrice = Number(row.price || 0);
|
||||
const methodPrice = Number(row.selectedMethod.packagePrice ?? row.selectedMethod.price ?? 0);
|
||||
const children = [
|
||||
{
|
||||
id: `${row.id}-project-fee`,
|
||||
name: `项目费: ${row.name}`,
|
||||
applyPart: '-',
|
||||
selectedMethod: null,
|
||||
unit: row.unit || '次',
|
||||
quantity: row.quantity || 1,
|
||||
price: projectPrice,
|
||||
checkType: row.checkType || '',
|
||||
isPackageDetail: true,
|
||||
isProjectFeeChild: true,
|
||||
packageId: row.packageId,
|
||||
packageName: row.packageName,
|
||||
hasChildren: !!(row.packageId || row.packageName)
|
||||
},
|
||||
{
|
||||
id: `${row.id}-method-fee`,
|
||||
name: `方法费: ${row.selectedMethod.name}`,
|
||||
applyPart: '-',
|
||||
selectedMethod: null,
|
||||
unit: '次',
|
||||
quantity: row.quantity || 1,
|
||||
price: methodPrice,
|
||||
checkType: row.checkType || '',
|
||||
isPackageDetail: true,
|
||||
hasChildren: false
|
||||
}
|
||||
];
|
||||
resolve(children);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 回退逻辑:无方法但有套餐,则直接加载套餐明细作为子节点
|
||||
let packageId = row.packageId;
|
||||
if (!packageId && row.packageName) {
|
||||
try {
|
||||
@@ -1122,7 +1187,10 @@ function getDisplaySelectedMethodName(item) {
|
||||
}
|
||||
|
||||
function getSelectedItemAmount(item) {
|
||||
return Number(item?.price || 0);
|
||||
const itemPrice = Number(item?.price || 0);
|
||||
const method = item?.selectedMethod || (item?.isPackageDetail ? null : selectedMethods.value[0]) || null;
|
||||
const methodPrice = method ? Number(method.packagePrice ?? method.price ?? 0) : 0;
|
||||
return itemPrice + methodPrice;
|
||||
}
|
||||
|
||||
function parsePackageDetailsPayload(res) {
|
||||
@@ -1601,14 +1669,12 @@ const filteredCategoryList = computed(() => {
|
||||
|
||||
// ====== 合计 ======
|
||||
const totalAmountCalc = computed(() => {
|
||||
const itemTotal = selectedItems.value.reduce((sum, item) => {
|
||||
const effectivePrice = getSelectedItemAmount(item);
|
||||
return sum + (effectivePrice * (item.quantity || 1));
|
||||
const total = selectedItems.value.reduce((sum, item) => {
|
||||
const basePrice = Number(item.price || 0);
|
||||
const method = item.selectedMethod || selectedMethods.value[0] || null;
|
||||
const methodPrice = method ? Number(method.packagePrice ?? method.price ?? 0) : 0;
|
||||
return sum + ((basePrice + methodPrice) * (item.quantity || 1));
|
||||
}, 0);
|
||||
const methodTotal = selectedMethods.value.reduce((sum, method) => {
|
||||
return sum + Number(method?.packagePrice ?? method?.price ?? 0);
|
||||
}, 0);
|
||||
const total = itemTotal + methodTotal;
|
||||
return total.toFixed(2);
|
||||
});
|
||||
|
||||
@@ -1621,6 +1687,19 @@ watch(selectedItems, () => {
|
||||
watch(selectedMethods, () => {
|
||||
form.isCharged = selectedItems.value.length > 0 || selectedMethods.value.length > 0 ? 1 : 0;
|
||||
updateMethodDisplay();
|
||||
|
||||
// 同步更新已选项目的选中检查方法及 hasChildren
|
||||
const primary = selectedMethods.value[0] || null;
|
||||
selectedItems.value.forEach(item => {
|
||||
if (primary) {
|
||||
const matched = item.methods.find(m => String(m.id) === String(primary.id));
|
||||
item.selectedMethod = matched || primary;
|
||||
item.hasChildren = true;
|
||||
} else {
|
||||
item.selectedMethod = null;
|
||||
item.hasChildren = !!(item.packageId || item.packageName);
|
||||
}
|
||||
});
|
||||
}, { deep: true });
|
||||
|
||||
// 监听患者变化
|
||||
@@ -1746,20 +1825,25 @@ function handleSave() {
|
||||
checkMethodCode: method.code || null,
|
||||
checkMethodPackageName: method.packageName || null
|
||||
})),
|
||||
items: selectedItems.value.map((item, index) => ({
|
||||
itemCode: String(item.id),
|
||||
itemName: item.name,
|
||||
bodyPartCode: item.checkType || 'unknown',
|
||||
itemFee: getSelectedItemAmount(item),
|
||||
performDeptCode: form.performDeptCode || '',
|
||||
itemStatus: 0,
|
||||
itemSeq: index + 1,
|
||||
// 检查方法信息
|
||||
checkMethodId: primaryMethod?.id || null,
|
||||
checkMethodName: primaryMethod?.name || null,
|
||||
checkMethodCode: primaryMethod?.code || null,
|
||||
checkMethodPackageName: primaryMethod?.packageName || null // Bug #384修复: 保存套餐名称
|
||||
}))
|
||||
items: selectedItems.value.map((item, index) => {
|
||||
const itemMethod = item.selectedMethod || primaryMethod || null;
|
||||
return {
|
||||
itemCode: String(item.id),
|
||||
itemName: item.name,
|
||||
bodyPartCode: item.checkType || 'unknown',
|
||||
itemFee: Number(item.price || 0), // 仅发送项目基础价格给后端,防止后端重复累加
|
||||
performDeptCode: form.performDeptCode || '',
|
||||
itemStatus: 0,
|
||||
itemSeq: index + 1,
|
||||
// 检查方法代码 (与后端 DTO ExamApplyItemDto.examMethodCode 一致,用于后端计费和数据库存储)
|
||||
examMethodCode: itemMethod?.code || null,
|
||||
// 优先使用当前明细行的“检查方法”,无则使用主选择的方法
|
||||
checkMethodId: itemMethod?.id || null,
|
||||
checkMethodName: itemMethod?.name || null,
|
||||
checkMethodCode: itemMethod?.code || null,
|
||||
checkMethodPackageName: itemMethod?.packageName || null
|
||||
};
|
||||
})
|
||||
};
|
||||
request({
|
||||
url: '/exam/apply',
|
||||
@@ -1833,14 +1917,30 @@ function handleRowClick(row) {
|
||||
serviceFee: md.serviceFee || null
|
||||
}));
|
||||
// 回充已保存的检查方法
|
||||
if (m.checkMethodId) {
|
||||
item.selectedMethod = item.methods.find(md => String(md.id) === String(m.checkMethodId)) || null;
|
||||
if (item.selectedMethod?.packageId) {
|
||||
item.hasChildren = true; // #426修复
|
||||
const methodCode = m.examMethodCode || m.checkMethodCode;
|
||||
const methodId = m.checkMethodId;
|
||||
if (methodCode || methodId) {
|
||||
const found = item.methods.find(md =>
|
||||
(methodCode && String(md.code) === String(methodCode)) ||
|
||||
(methodId && String(md.id) === String(methodId))
|
||||
);
|
||||
if (found) {
|
||||
item.selectedMethod = found;
|
||||
} else {
|
||||
item.selectedMethod = {
|
||||
id: methodId || null,
|
||||
name: m.checkMethodName || '',
|
||||
code: methodCode || '',
|
||||
price: 0,
|
||||
packageName: m.checkMethodPackageName || '',
|
||||
packageId: null,
|
||||
packagePrice: null,
|
||||
serviceFee: null
|
||||
};
|
||||
}
|
||||
}
|
||||
if (item.selectedMethod?.packageId) {
|
||||
item.hasChildren = true; // #426修复
|
||||
if (item.selectedMethod || item.packageId || item.packageName) {
|
||||
item.hasChildren = true;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -1860,7 +1960,6 @@ function handleRowClick(row) {
|
||||
packageDetails: []
|
||||
});
|
||||
}
|
||||
item.selectedMethod = null;
|
||||
item.methodPackageDetails = [];
|
||||
}
|
||||
selectedItems.value = itemsWithMethods;
|
||||
@@ -1963,6 +2062,8 @@ async function handleItemSelect(checked, item, cat) {
|
||||
}
|
||||
}
|
||||
|
||||
const primaryMethod = selectedMethods.value[0] || null;
|
||||
const matchedMethod = primaryMethod ? (methods.find(m => String(m.id) === String(primaryMethod.id)) || primaryMethod) : null;
|
||||
const newRow = {
|
||||
id: item.id, name: item.name,
|
||||
price: item.price, quantity: 1,
|
||||
@@ -1973,7 +2074,7 @@ async function handleItemSelect(checked, item, cat) {
|
||||
nationalCode: item.nationalCode || '',
|
||||
checked: true,
|
||||
methods: methods,
|
||||
selectedMethod: null,
|
||||
selectedMethod: matchedMethod,
|
||||
expanded: false,
|
||||
projectFoldExpanded: false,
|
||||
methodFoldExpanded: false,
|
||||
@@ -1982,7 +2083,7 @@ async function handleItemSelect(checked, item, cat) {
|
||||
packageName: item.packageName || null,
|
||||
packageDetailsLoading: false,
|
||||
packageId: item.packageId || null,
|
||||
hasChildren: !!(item.packageId || item.packageName) // #426修复: 树形表格懒加载展开标记,支持 packageName 解析
|
||||
hasChildren: !!(item.packageId || item.packageName || matchedMethod)
|
||||
};
|
||||
selectedItems.value.push(newRow);
|
||||
// 必须用数组里的响应式行,不能继续改局部 newRow:push 后列表内是 proxy,改 raw 对象不会触发右侧卡片更新(会一直卡在「加载中」)
|
||||
@@ -2150,14 +2251,37 @@ async function loadMethodPackageDetails(item, method) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 检查明细表格中切换检查方法 */
|
||||
async function onDetailMethodChange(row, val) {
|
||||
row.selectedMethod = val || null;
|
||||
if (val?.packageId || val?.packageName) {
|
||||
row.hasChildren = true; // #426修复
|
||||
row.hasChildren = !!(val || hasItemPackage(row));
|
||||
|
||||
// 同步全局已选的检查方法列表
|
||||
if (val) {
|
||||
const exists = selectedMethods.value.some(m => String(m.id) === String(val.id));
|
||||
if (!exists) {
|
||||
selectedMethods.value = [{
|
||||
...val,
|
||||
expanded: false,
|
||||
packageLoading: false,
|
||||
packageDetails: []
|
||||
}];
|
||||
}
|
||||
} else {
|
||||
selectedMethods.value = [];
|
||||
}
|
||||
|
||||
row.methodPackageDetails = [];
|
||||
updateMethodDisplay();
|
||||
|
||||
// 若明细表已被展开,切换方法时刷新对应的子树节点
|
||||
if (detailTableRef.value && typeof detailTableRef.value.reloadRowChilds === 'function') {
|
||||
try {
|
||||
detailTableRef.value.reloadRowChilds(row);
|
||||
} catch (e) {
|
||||
console.error('reloadRowChilds failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
const open = shouldShowPackageBody(row);
|
||||
row.expanded = open;
|
||||
row.projectFoldExpanded = shouldShowItemPackageBody(row) && open;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-container class="inspection-application-container">
|
||||
<el-header
|
||||
class="top-action-bar"
|
||||
@@ -711,7 +711,7 @@
|
||||
<!-- 只有急标记能编辑 -->
|
||||
<el-checkbox
|
||||
v-model="formData.priorityCode"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
>
|
||||
急
|
||||
@@ -726,7 +726,7 @@
|
||||
<!-- 收费标记默认不勾选并不可编辑 -->
|
||||
<el-checkbox
|
||||
v-model="formData.applyStatus"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
disabled
|
||||
>
|
||||
@@ -742,8 +742,6 @@
|
||||
<!-- 退费标记默认不勾选并不可编辑 -->
|
||||
<el-checkbox
|
||||
v-model="formData.needRefund"
|
||||
:true-value="true"
|
||||
:false-value="false"
|
||||
disabled
|
||||
>
|
||||
退费
|
||||
@@ -758,8 +756,6 @@
|
||||
<!-- 执行标记默认不勾选并不可编辑 -->
|
||||
<el-checkbox
|
||||
v-model="formData.needExecute"
|
||||
:true-value="true"
|
||||
:false-value="false"
|
||||
disabled
|
||||
>
|
||||
执行
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div style="width: 100%; display: flex; flex-direction: column;">
|
||||
<div style="margin-bottom: 5px">
|
||||
<el-button
|
||||
@@ -394,7 +394,7 @@
|
||||
>
|
||||
皮试:<el-checkbox
|
||||
v-model="scope.row.skinTestFlag"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
||||
>
|
||||
@@ -837,7 +837,7 @@
|
||||
>
|
||||
皮试:<el-checkbox
|
||||
v-model="scope.row.skinTestFlag"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
||||
>
|
||||
@@ -1332,7 +1332,7 @@
|
||||
<template v-if="scope.row.isEdit">
|
||||
<el-checkbox
|
||||
v-model="scope.row.skinTestFlag"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
@change="handleSkinTestChange(scope.row, scope.rowIndex)"
|
||||
>
|
||||
@@ -1575,6 +1575,23 @@ const orderGroupLoaded = ref({
|
||||
// 更新展开行的函数
|
||||
const updateExpandOrder = (keys) => {
|
||||
expandOrder.value = keys;
|
||||
nextTick(() => {
|
||||
if (prescriptionRef.value?.setRowExpand) {
|
||||
// 折叠不需要展开的行
|
||||
prescriptionList.value.forEach(row => {
|
||||
if (!keys.includes(row.uniqueKey)) {
|
||||
prescriptionRef.value.setRowExpand([row], false);
|
||||
}
|
||||
});
|
||||
// 展开目标行
|
||||
keys.forEach(key => {
|
||||
const targetRow = prescriptionList.value.find(item => item.uniqueKey === key);
|
||||
if (targetRow) {
|
||||
prescriptionRef.value.setRowExpand([targetRow], true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
const stockList = ref([]);
|
||||
const contractList = ref([]);
|
||||
@@ -1760,14 +1777,19 @@ onBeforeUnmount(() => {
|
||||
watch(
|
||||
() => expandOrder.value,
|
||||
(newValue) => {
|
||||
if (newValue.length > 0) {
|
||||
if (newValue && newValue.length > 0) {
|
||||
nextTick(() => {
|
||||
const index = prescriptionList.value.findIndex((row) => row.uniqueKey === newValue[0]);
|
||||
const items = proxy.$refs['formRef' + index]?.$el?.querySelectorAll('[data-prop]');
|
||||
requiredProps.value = Array.from(items).map((item) => item.dataset.prop);
|
||||
if (index !== -1) {
|
||||
const formRef = proxy.$refs['formRef' + index];
|
||||
const items = formRef?.$el?.querySelectorAll('[data-prop]') || formRef?.querySelectorAll?.('[data-prop]');
|
||||
requiredProps.value = items ? Array.from(items).map((item) => item.dataset.prop) : [];
|
||||
} else {
|
||||
requiredProps.value = [];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
requiredProps.value = {};
|
||||
requiredProps.value = [];
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -2567,6 +2589,16 @@ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
* 选择药品回调
|
||||
*/
|
||||
function selectAdviceBase(key, row) {
|
||||
console.log('[selectAdviceBase] Triggered with key:', key, 'row:', JSON.parse(JSON.stringify(row)));
|
||||
// 确保 rowIndex 指向正确的行索引,避免 out of sync 或者未定义导致的报错
|
||||
const targetIndex = prescriptionList.value.findIndex(item => item.uniqueKey === key);
|
||||
console.log('[selectAdviceBase] Target index resolved:', targetIndex, 'Current rowIndex.value:', rowIndex.value);
|
||||
if (targetIndex !== -1) {
|
||||
rowIndex.value = targetIndex;
|
||||
} else {
|
||||
console.error('[selectAdviceBase] Target row not found in prescriptionList by uniqueKey!');
|
||||
}
|
||||
|
||||
// 🔧 Bug Fix: 检查药品是否需要皮试,如果需要则弹出确认框
|
||||
if (row.skinTestFlag == 1) {
|
||||
ElMessageBox.confirm(`药品:${row.adviceName}需要做皮试,是否做皮试?`, '提示', {
|
||||
@@ -2643,7 +2675,7 @@ function selectAdviceBase(key, row) {
|
||||
// 确保在setValue之后再次设置showPopover为false,防止被覆盖
|
||||
prescriptionList.value[rowIndex.value].showPopover = false;
|
||||
|
||||
expandOrder.value = [key];
|
||||
updateExpandOrder([key]);
|
||||
|
||||
// 自动聚焦到单次用量字段 - 使用 async/await 多次尝试
|
||||
await nextTick();
|
||||
@@ -4108,7 +4140,7 @@ async function setValue(row) {
|
||||
if (row.adviceType != 3 && row.adviceType != 4 && row.adviceType != 5) {
|
||||
// 🔧 Bug #144 补充修复:检查 inventoryList 是否存在,避免 undefined 错误
|
||||
if (!row.inventoryList || row.inventoryList.length == 0) {
|
||||
expandOrder.value = [];
|
||||
updateExpandOrder([]);
|
||||
proxy.$modal.msgWarning(row.adviceName + '无库存');
|
||||
return;
|
||||
}
|
||||
@@ -4229,6 +4261,9 @@ async function setValue(row) {
|
||||
}
|
||||
// 🔧 Bug #218 修复:最后统一同步组套字段(适用于所有类型)
|
||||
syncGroupFields(row);
|
||||
|
||||
// 强制触发 Vue 数组响应式更新,并通知 vxe-table 重新加载数据
|
||||
prescriptionList.value = [...prescriptionList.value];
|
||||
}
|
||||
|
||||
// 选择组套 - 适配新版 OrderGroupDrawer 组件
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div style="max-height: 750px; overflow-y: auto">
|
||||
<div
|
||||
v-for="(prescription, pIndex) in tcmPrescriptionList"
|
||||
@@ -178,7 +178,7 @@
|
||||
<span class="doctor-station"> 是否代煎: </span>
|
||||
<el-checkbox
|
||||
v-model="prescription.sufferingFlag"
|
||||
:true-value="true"
|
||||
:true-value="'1'"
|
||||
:false-value="'0'"
|
||||
placeholder=" "
|
||||
@change="
|
||||
|
||||
@@ -188,13 +188,15 @@ const setCurrentRow = (row) => {
|
||||
};
|
||||
|
||||
// 当前行变化时更新索引
|
||||
const handleCurrentChange = (currentRow) => {
|
||||
currentIndex.value = filteredAdviceBaseList.value.findIndex((item) => item === currentRow);
|
||||
currentSelectRow.value = currentRow;
|
||||
const handleCurrentChange = ({ row }) => {
|
||||
currentIndex.value = filteredAdviceBaseList.value.findIndex((item) => item === row);
|
||||
currentSelectRow.value = row;
|
||||
};
|
||||
|
||||
function clickRow(row) {
|
||||
emit('selectAdviceBase', row);
|
||||
function clickRow({ row }) {
|
||||
if (row) {
|
||||
emit('selectAdviceBase', row);
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="form-header">
|
||||
<h2 class="form-title">
|
||||
住院病案首页
|
||||
@@ -426,7 +426,7 @@
|
||||
<div style="display: flex">
|
||||
<el-checkbox
|
||||
v-model="scope.row.maindiseFlag"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
border
|
||||
size="small"
|
||||
|
||||
@@ -177,6 +177,12 @@
|
||||
align="center"
|
||||
min-width="120"
|
||||
/>
|
||||
<vxe-column
|
||||
field="payWayEnum_enumText"
|
||||
title="支付方式"
|
||||
align="center"
|
||||
min-width="120"
|
||||
/>
|
||||
<!-- <vxe-column field="afterBalance" title="可退金额" min-width="120">
|
||||
<template #default="scope">
|
||||
<span>
|
||||
@@ -249,7 +255,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {nextTick, ref} from 'vue';
|
||||
import {nextTick, ref, getCurrentInstance} from 'vue';
|
||||
import {simplePrint, PRINT_TEMPLATE} from '@/utils/printUtils';
|
||||
import {getDepositInfo, getDepositInfoPage} from './components/api';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
@@ -347,7 +353,7 @@ async function handlePrint(row) {
|
||||
const userStore = useUserStore();
|
||||
const amountValue = row.tenderedAmount || 0;
|
||||
const printData = {
|
||||
hospitalName: userStore.hospitalName || "中联医院",
|
||||
hospitalName: userStore.tenantName || userStore.hospitalName || userStore.orgName || "中联医院",
|
||||
receiptNo: row.paymentNo || "",
|
||||
currentTime: row.operateTime || new Date().toLocaleString(),
|
||||
// 补打标记
|
||||
@@ -363,7 +369,7 @@ async function handlePrint(row) {
|
||||
contractName: patientInfo.value.contractName || "自费",
|
||||
// 费用信息
|
||||
chargeItem: "住院预缴款",
|
||||
paymentMethod: row.paymentEnum_enumText || "现金",
|
||||
paymentMethod: row.payWayEnum_enumText || row.paymentMethod || row.paymentEnum_enumText || "现金",
|
||||
amountInWords: "人民币:" + convertToChineseNumber(amountValue),
|
||||
balanceAmount: "¥ " + amountValue.toFixed(2) + " 元",
|
||||
cashier: userStore.nickName || "",
|
||||
|
||||
@@ -556,12 +556,9 @@ const onChangFeeType = () => {
|
||||
/* 打印预交金收据 */
|
||||
const printDepositReceipt = async (patientInfo, inHospitalInfo, medicalInsuranceTitle) => {
|
||||
try {
|
||||
// 构造支付方式详情文本
|
||||
const paymentDetails = `现金 ${
|
||||
currentFeeType.value === 'hipCash' ? advance.value || '0.00' : '0.00'
|
||||
} 微信 ${currentFeeType.value === 'wechat' ? advance.value || '0.00' : '0.00'} 支付宝 ${
|
||||
currentFeeType.value === 'hipAlipay' ? advance.value || '0.00' : '0.00'
|
||||
} 银行 ${currentFeeType.value === 'hipPayCard' ? advance.value || '0.00' : '0.00'}`;
|
||||
// 根据当前选中的支付类型获取对应的中文名称
|
||||
const selectedPayType = feeTypeOptions.find((item) => item.type === currentFeeType.value);
|
||||
const payLabel = selectedPayType ? selectedPayType.label : '现金';
|
||||
|
||||
// 构造打印数据
|
||||
const printData = {
|
||||
@@ -582,8 +579,7 @@ const printDepositReceipt = async (patientInfo, inHospitalInfo, medicalInsurance
|
||||
amountInWords: '人民币:' + convertToChineseNumber(advance.value || '0.00'), // 人民币大写
|
||||
|
||||
// 支付方式详情
|
||||
paymentDetails: paymentDetails,
|
||||
paymentMethod: paymentDetails, // 支付方式绑定
|
||||
paymentMethod: payLabel, // 支付方式绑定当前选中的具体名称
|
||||
|
||||
// 时间信息
|
||||
currentTime: new Date().toLocaleString('zh-CN', {
|
||||
@@ -597,7 +593,7 @@ const printDepositReceipt = async (patientInfo, inHospitalInfo, medicalInsurance
|
||||
|
||||
// 其他信息
|
||||
cashier: userStore?.nickName || '', // 收款人(收费员)
|
||||
hospitalName: userStore?.hospitalName || '', // 医院名称
|
||||
hospitalName: userStore?.tenantName || userStore?.hospitalName || userStore?.orgName || '', // 医院名称
|
||||
receiptNo: '', // 挂号处打印可能还没有收据号
|
||||
reprintTag: '', // 首次打印为空
|
||||
};
|
||||
|
||||
@@ -316,7 +316,7 @@
|
||||
<div style="display:flex;flex-direction:column;align-items:center;gap:5px;">
|
||||
<el-checkbox
|
||||
v-model="scope.row.maindiseFlag"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
border
|
||||
size="small"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-row
|
||||
:gutter="20"
|
||||
style="margin-bottom: 10px; display: flex; justify-content: flex-end"
|
||||
@@ -110,7 +110,7 @@
|
||||
<template #default="scope">
|
||||
<el-checkbox
|
||||
v-model="scope.row.maindiagFlag"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
border
|
||||
size="small"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<el-row
|
||||
:gutter="20"
|
||||
style="margin-bottom: 10px; display: flex; justify-content: flex-end"
|
||||
@@ -110,7 +110,7 @@
|
||||
<template #default="scope">
|
||||
<el-checkbox
|
||||
v-model="scope.row.maindiagFlag"
|
||||
:true-value="true"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
border
|
||||
size="small"
|
||||
|
||||
Reference in New Issue
Block a user