Merge branch 'develop' of https://gitea.gentronhealth.com/wangyizhe/his into develop
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# HealthLink-HIS 代码模块索引
|
||||
|
||||
> 供 LLM 快速定位代码。每个模块列出 Controller → Service → Mapper 关键文件。
|
||||
> 最后更新: 2026-06-15 06:00 (298 个 Controller)
|
||||
> 最后更新: 2026-06-15 12:00 (300 个 Controller)
|
||||
|
||||
## 关键词 → 模块速查
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -182,6 +182,10 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
// 提取requestStatus手动处理,支持COMPLETED(3)和CHECK_VERIFIED(10)同时查询
|
||||
Integer requestStatus = inpatientAdviceParam.getRequestStatus();
|
||||
inpatientAdviceParam.setRequestStatus(null);
|
||||
// deadline 不在 UNION 子查询结果列中,且不映射为查询过滤条件
|
||||
// 原因:end_time 是医嘱结束时间,长期医嘱的 end_time 远在 deadline 之后,
|
||||
// 使用 <= 过滤会排除所有长期医嘱,导致"未校对"tab 查询为空
|
||||
inpatientAdviceParam.setDeadline(null);
|
||||
// 构建查询条件
|
||||
QueryWrapper<InpatientAdviceParam> queryWrapper
|
||||
= HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null, null, null);
|
||||
@@ -508,7 +512,8 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
if (!deviceRequestList.isEmpty()) {
|
||||
// 更新耗材请求状态待发送
|
||||
deviceRequestService.updateDraftStatusBatch(
|
||||
deviceRequestList.stream().map(PerformInfoDto::getRequestId).toList());
|
||||
deviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(),
|
||||
practitionerId, checkDate, backReason);
|
||||
}
|
||||
return R.ok(null, "退回成功");
|
||||
}
|
||||
|
||||
@@ -242,6 +242,17 @@ public class InpatientAdviceDto {
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long performerCheckId;
|
||||
|
||||
/**
|
||||
* 退回原因
|
||||
*/
|
||||
private String reasonText;
|
||||
|
||||
/**
|
||||
* 校对时间/退回时间
|
||||
*/
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date checkTime;
|
||||
|
||||
/**
|
||||
* 药品/服务类型
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
-- Bug #613: 医嘱退回流程 - 耗材请求表增加退回相关字段
|
||||
-- 与 med_medication_request 和 wor_service_request 保持一致
|
||||
|
||||
ALTER TABLE wor_device_request
|
||||
ADD COLUMN IF NOT EXISTS back_reason VARCHAR(500),
|
||||
ADD COLUMN IF NOT EXISTS performer_check_id BIGINT,
|
||||
ADD COLUMN IF NOT EXISTS check_time TIMESTAMP;
|
||||
|
||||
COMMENT ON COLUMN wor_device_request.back_reason IS '退回原因';
|
||||
COMMENT ON COLUMN wor_device_request.performer_check_id IS '校对人/退回护士';
|
||||
COMMENT ON COLUMN wor_device_request.check_time IS '校对时间/退回时间';
|
||||
@@ -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'
|
||||
|
||||
@@ -153,6 +153,8 @@
|
||||
ii.balance_amount AS balance_amount,
|
||||
ii.account_id AS account_id,
|
||||
ii.performer_check_id,
|
||||
ii.reason_text,
|
||||
ii.check_time,
|
||||
ii.category_code,
|
||||
ii.dispense_status,
|
||||
ii.unit_price,
|
||||
@@ -171,6 +173,8 @@
|
||||
T1.infusion_flag AS inject_flag,
|
||||
T1.group_id AS group_id,
|
||||
T1.performer_check_id,
|
||||
T1.back_reason AS reason_text,
|
||||
T1.check_time AS check_time,
|
||||
T2."name" AS advice_name,
|
||||
T2.id AS item_id,
|
||||
T3.total_volume AS volume,
|
||||
@@ -317,6 +321,8 @@
|
||||
NULL::integer AS inject_flag,
|
||||
NULL::bigint AS group_id,
|
||||
T1.performer_check_id,
|
||||
T1.reason_text AS reason_text,
|
||||
T1.check_time AS check_time,
|
||||
T2."name" AS advice_name,
|
||||
T2.id AS item_id,
|
||||
NULL::varchar AS volume,
|
||||
@@ -452,6 +458,8 @@
|
||||
NULL::integer AS inject_flag,
|
||||
NULL::bigint AS group_id,
|
||||
T1.performer_check_id,
|
||||
T1.back_reason AS reason_text,
|
||||
T1.check_time AS check_time,
|
||||
T2."name" AS advice_name,
|
||||
T2.id AS item_id,
|
||||
NULL::varchar AS volume,
|
||||
|
||||
@@ -220,6 +220,7 @@
|
||||
T1.based_on_id AS based_on_id,
|
||||
T1.medication_id AS advice_definition_id,
|
||||
T1.content_json::jsonb ->> 'remark' AS remark,
|
||||
T1.back_reason AS reason_text,
|
||||
CASE WHEN T1.status_enum = 6 THEN T1.effective_dose_end ELSE NULL END AS stop_time,
|
||||
CASE WHEN T1.status_enum = 6 THEN T1.update_by ELSE NULL END AS stop_user_name
|
||||
FROM med_medication_request AS T1
|
||||
@@ -277,6 +278,7 @@
|
||||
T1.based_on_id AS based_on_id,
|
||||
T1.device_def_id AS advice_definition_id,
|
||||
T1.content_json::jsonb ->> 'remark' AS remark,
|
||||
T1.back_reason AS reason_text,
|
||||
NULL::timestamp AS stop_time,
|
||||
'' AS stop_user_name
|
||||
FROM wor_device_request AS T1
|
||||
@@ -331,6 +333,7 @@
|
||||
T1.based_on_id AS based_on_id,
|
||||
T1.activity_id AS advice_definition_id,
|
||||
T1.remark AS remark,
|
||||
T1.reason_text AS reason_text,
|
||||
CASE WHEN T1.status_enum = 6 THEN T1.occurrence_end_time ELSE NULL END AS stop_time,
|
||||
CASE WHEN T1.status_enum = 6 THEN T1.update_by ELSE NULL END AS stop_user_name
|
||||
FROM wor_service_request AS T1
|
||||
|
||||
@@ -174,4 +174,13 @@ public class DeviceRequest extends HisBaseEntity {
|
||||
* 生成来源
|
||||
*/
|
||||
private Integer generateSourceEnum;
|
||||
|
||||
/** 退回原因 */
|
||||
private String backReason = "";
|
||||
|
||||
/** 校对人 */
|
||||
private Long performerCheckId;
|
||||
|
||||
/** 校对时间 */
|
||||
private Date checkTime;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.administration.domain.Practitioner;
|
||||
import com.healthlink.his.workflow.domain.DeviceRequest;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -44,6 +45,16 @@ public interface IDeviceRequestService extends IService<DeviceRequest> {
|
||||
*/
|
||||
void updateDraftStatusBatch(List<Long> devReqIdList);
|
||||
|
||||
/**
|
||||
* 更新请求状态:待发送(含退回信息)
|
||||
*
|
||||
* @param devReqIdList 耗材请求id列表
|
||||
* @param practitionerId 退回护士/校对人
|
||||
* @param checkDate 退回时间/校对时间
|
||||
* @param backReason 退回原因
|
||||
*/
|
||||
void updateDraftStatusBatch(List<Long> devReqIdList, Long practitionerId, Date checkDate, String backReason);
|
||||
|
||||
/**
|
||||
* 更新请求状态:取消
|
||||
*
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.healthlink.his.workflow.mapper.DeviceRequestMapper;
|
||||
import com.healthlink.his.workflow.service.IDeviceRequestService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -77,6 +78,31 @@ public class DeviceRequestServiceImpl extends ServiceImpl<DeviceRequestMapper, D
|
||||
.set(DeviceRequest::getStatusEnum, RequestStatus.DRAFT.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新请求状态:待发送(含退回信息)
|
||||
*
|
||||
* @param devReqIdList 耗材请求id列表
|
||||
* @param practitionerId 退回护士/校对人
|
||||
* @param checkDate 退回时间/校对时间
|
||||
* @param backReason 退回原因
|
||||
*/
|
||||
@Override
|
||||
public void updateDraftStatusBatch(List<Long> devReqIdList, Long practitionerId, Date checkDate, String backReason) {
|
||||
LambdaUpdateWrapper<DeviceRequest> updateWrapper =
|
||||
new LambdaUpdateWrapper<DeviceRequest>().in(DeviceRequest::getId, devReqIdList)
|
||||
.set(DeviceRequest::getStatusEnum, RequestStatus.DRAFT.getValue());
|
||||
if (practitionerId != null) {
|
||||
updateWrapper.set(DeviceRequest::getPerformerCheckId, practitionerId);
|
||||
}
|
||||
if (checkDate != null) {
|
||||
updateWrapper.set(DeviceRequest::getCheckTime, checkDate);
|
||||
}
|
||||
if (backReason != null) {
|
||||
updateWrapper.set(DeviceRequest::getBackReason, backReason);
|
||||
}
|
||||
baseMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新请求状态:取消
|
||||
*
|
||||
|
||||
@@ -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
|
||||
@@ -260,7 +260,7 @@
|
||||
>
|
||||
<template #default="scope">
|
||||
<span v-if="!scope.row.isEdit">
|
||||
{{ scope.row.requesterId_dictText }}
|
||||
{{ getSignField(scope.row, 'signDoctorName') }}
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
@@ -272,7 +272,7 @@
|
||||
>
|
||||
<template #default="scope">
|
||||
<span v-if="!scope.row.isEdit">
|
||||
{{ scope.row.requestTime }}
|
||||
{{ getSignField(scope.row, 'signDate') }}
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
@@ -437,6 +437,8 @@ import {
|
||||
} from './api';
|
||||
import adviceBaseList from './adviceBaseList';
|
||||
import {getCurrentInstance, nextTick, ref, watch, computed} from 'vue';
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { parseTime } from '@/utils/his'
|
||||
|
||||
const emit = defineEmits(['selectDiagnosis']);
|
||||
const prescriptionList = ref([]);
|
||||
@@ -496,6 +498,27 @@ const editingRowIndex = computed(() => {
|
||||
const stockList = ref([]);
|
||||
const groupList = ref([])
|
||||
const { proxy } = getCurrentInstance();
|
||||
const userStore = useUserStore()
|
||||
|
||||
/**
|
||||
* 从 contentJson 中安全提取指定字段
|
||||
* @param {Object} row - 行数据
|
||||
* @param {string} field - 字段名,如 'signDate'、'signDoctorName'
|
||||
* @returns {string} 字段值或空字符串
|
||||
*/
|
||||
function getSignField(row, field) {
|
||||
if (!row) return ''
|
||||
// 🔧 优先读取顶层字段(计费签发 sign-advice 将签名存在顶层)
|
||||
if (row[field]) return row[field]
|
||||
// 回退到 contentJson 内部读取
|
||||
if (!row.contentJson) return ''
|
||||
try {
|
||||
const parsed = typeof row.contentJson === 'string' ? JSON.parse(row.contentJson) : row.contentJson
|
||||
return parsed[field] || ''
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
const inputRefs = ref({}); // 存储输入框实例
|
||||
const requiredProps = ref([]); // 存储必填项 prop 顺序
|
||||
const { method_code, unit_code, rate_code, distribution_category_code } = proxy.useDict(
|
||||
@@ -542,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 = [];
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -782,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];
|
||||
@@ -1208,10 +1218,16 @@ function handleSave() {
|
||||
return;
|
||||
}
|
||||
// 此处签发处方和单行保存处方传参相同,后台已经将传参存为JSON字符串,此处直接转换为JSON即可
|
||||
const signDoctor = userStore.name || userStore.nickName || ''
|
||||
const signTime = parseTime(new Date())
|
||||
let list = saveList.map((item) => {
|
||||
const parsedContent = item.contentJson ? JSON.parse(item.contentJson) : {};
|
||||
return {
|
||||
...parsedContent,
|
||||
// 签发生效时写入签名信息到 contentJson(与临时医嘱弹窗 confirmSign 保持一致)
|
||||
signDoctorName: signDoctor,
|
||||
signDate: signTime,
|
||||
executeTime: signTime,
|
||||
requestId: item.requestId,
|
||||
// 已有 requestId 的记录走 UPDATE 路径,新记录走 INSERT 路径
|
||||
dbOpType: item.requestId ? '2' : '1',
|
||||
@@ -1242,6 +1258,25 @@ function handleSave() {
|
||||
}).then((res) => {
|
||||
if (res.code === 200) {
|
||||
proxy.$modal.msgSuccess('保存成功');
|
||||
// 乐观更新:签发成功后立即更新本地行数据,确保签发时间/签发人立即可见
|
||||
// 即使后端 API 刷新返回的数据结构有延迟,前端也能立刻回显
|
||||
saveList.forEach(signedItem => {
|
||||
const row = prescriptionList.value.find(r => {
|
||||
if (signedItem.requestId) return r.requestId === signedItem.requestId
|
||||
return r.uniqueKey === signedItem.uniqueKey
|
||||
})
|
||||
if (row) {
|
||||
let contentJson = {}
|
||||
try {
|
||||
contentJson = typeof row.contentJson === 'string' ? JSON.parse(row.contentJson) : (row.contentJson || {})
|
||||
} catch (e) { /* ignore */ }
|
||||
contentJson.signDoctorName = signDoctor
|
||||
contentJson.signDate = signTime
|
||||
contentJson.executeTime = signTime
|
||||
row.contentJson = JSON.stringify(contentJson)
|
||||
row.statusEnum = 2
|
||||
}
|
||||
})
|
||||
getListInfo(false);
|
||||
prescriptionList.value.map(k=>{
|
||||
k.check = false
|
||||
@@ -1284,6 +1319,10 @@ function handleSaveSign(row, index) {
|
||||
row.encounterId = props.patientInfo.encounterId;
|
||||
row.accountId = props.patientInfo.accountId;
|
||||
const cleanRow = JSON.parse(JSON.stringify(row));
|
||||
// 保存为草稿时清除签名相关字段(签发时间/签发人仅在签发时才应写入 contentJson)
|
||||
delete cleanRow.signDoctorName
|
||||
delete cleanRow.signDate
|
||||
delete cleanRow.executeTime
|
||||
cleanRow.contentJson = JSON.stringify(cleanRow);
|
||||
cleanRow.dbOpType = cleanRow.requestId ? '2' : '1';
|
||||
cleanRow.minUnitQuantity = cleanRow.quantity * cleanRow.partPercent;
|
||||
|
||||
@@ -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
|
||||
>
|
||||
执行
|
||||
|
||||
@@ -3735,10 +3735,9 @@ function handleSaveBatch(prescriptionId) {
|
||||
prescription.accountId = finalAccountId;
|
||||
}
|
||||
|
||||
// 获取对应处方的展开状态
|
||||
const prescriptionExpandOrder = prescription.expandOrder || [];
|
||||
if (prescriptionExpandOrder.length > 0) {
|
||||
proxy.$modal.msgWarning('请先点击确定确认当前医嘱');
|
||||
// 🔧 Bug Fix #749: 检查是否有展开行未确认(使用组件级响应式变量 expandOrder.value)
|
||||
if (expandOrder.value.length > 0) {
|
||||
proxy.$modal.msgWarning('请先点击确定确认当前医嘱,或关闭展开行');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5590,3 +5589,7 @@ defineExpose({ getListInfo, getDiagnosisInfo });
|
||||
min-width: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
// 🔧 Bug Fix #749: 检查是否有展开行未确认(使用组件级响应式变量 expandOrder.value)
|
||||
if (expandOrder.value.length > 0) {
|
||||
proxy.$modal.msgWarning('请先点击确定确认当前医嘱,或关闭展开行');
|
||||
@@ -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"
|
||||
|
||||
@@ -365,6 +365,13 @@
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="退回原因" align="center" field="reasonText" width="160" show-overflow="title">
|
||||
<template #default="scope">
|
||||
<span v-if="!scope.row.isEdit" style="color: #F59E0B;">
|
||||
{{ scope.row.reasonText || '-' }}
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="诊断" align="center" field="diagnosisName" width="150">
|
||||
<template #default="scope">
|
||||
<span v-if="!scope.row.isEdit">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
label="临床医嘱"
|
||||
name="prescription"
|
||||
>
|
||||
<Advice ref="adviceRef" />
|
||||
<Advice ref="adviceRef" :patient-info="currentPatientInfo" />
|
||||
</el-tab-pane>
|
||||
<!-- <el-tab-pane label="医技报告" name="fourth">Task</el-tab-pane> -->
|
||||
<el-tab-pane
|
||||
|
||||
@@ -287,6 +287,19 @@
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
title="退回原因"
|
||||
field="reasonText"
|
||||
width="160"
|
||||
align="center"
|
||||
show-overflow="title"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span style="color: #F59E0B;">
|
||||
{{ scope.row.reasonText || '-' }}
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
title="诊断"
|
||||
field="diagnosis"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<script setup>
|
||||
import inPatientBarDoctorFold from '@/components/patientBar/inPatientBarDoctorFold.vue';
|
||||
import Details from './components/details.vue';
|
||||
import {patientInfo, updatePatientInfo} from '@/views/inpatientNurse/components/store/patient';
|
||||
import {patientInfo, updatePatientInfo} from '@/views/inpatientDoctor/home/store/patient.js';
|
||||
import PatientList from '@/components/PatientList/patient-list.vue';
|
||||
|
||||
// 处理患者选择
|
||||
|
||||
@@ -2436,18 +2436,24 @@ function handleMedicalAdvice(row) {
|
||||
const contentData = jsonContent ? JSON.parse(jsonContent) : {};
|
||||
const medicineName = contentData.adviceName || contentData.advice_name || item.adviceName || item.advice_name || '';
|
||||
const spec = contentData.volume || contentData.specification || item.volume || item.specification || '';
|
||||
const specMatch = spec.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/)
|
||||
// 🔧 BugFix: 提取并清洗单位。优先用正则从规格中解析,失败时回退到 contentData.doseUnitCode / unitCode
|
||||
const specMatch = spec.match(/([\d.]+)\s*([a-zA-Z\u4e00-\u9fa5]+)/)
|
||||
let specUnit = specMatch ? specMatch[2] : ''
|
||||
if (!specUnit) {
|
||||
specUnit = contentData.doseUnitCode || contentData.unitCode || contentData.unit || ''
|
||||
}
|
||||
// 清理多余符号:只保留字母、数字、中文
|
||||
specUnit = specUnit.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '')
|
||||
const specValue = specMatch ? parseFloat(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : ''
|
||||
const dosage = specValue * (contentData.quantity || item.quantity || 1)
|
||||
|
||||
// 🔧 用法编码归一化:旧格式(iv/po) → 字典兼容格式(404/1)
|
||||
const oldToNewUsage = { 'iv': '404', 'po': '1', 'im': '403', 'sc': '401', 'ivgtt': '405', 'ih': '5', 'it': '610', 'ip': '604', 'top': '6', 'pr': '2' }
|
||||
let usageCode = contentData.methodCode || 'iv'
|
||||
let usageLabel = getUsageLabel(usageCode)
|
||||
if (usageCode === 'iv') {
|
||||
if (medicineName.includes('注射液')) { usageCode = 'iv'; usageLabel = '静脉注射' }
|
||||
} else if (usageCode === 'po') {
|
||||
if (medicineName.includes('片') || medicineName.includes('胶囊')) { usageCode = 'po'; usageLabel = '口服' }
|
||||
if (oldToNewUsage[usageCode]) {
|
||||
usageCode = oldToNewUsage[usageCode]
|
||||
}
|
||||
let usageLabel = getUsageLabel(usageCode)
|
||||
|
||||
return {
|
||||
id: index + 1,
|
||||
@@ -2457,7 +2463,13 @@ function handleMedicalAdvice(row) {
|
||||
usage: usageCode,
|
||||
usageLabel,
|
||||
frequency: '立即',
|
||||
executeTime: '',
|
||||
// 🔧 BugFix: 执行时间优先从 contentJson 读取,兼容计费弹窗签发时签名字段在顶层的情况
|
||||
executeTime: contentData.executeTime || contentData.execute_time || contentData.signDate
|
||||
|| item.signDate || item.executeTime || item.execute_time || '',
|
||||
// 🔧 签发时间:从 contentJson 中提取,供医嘱弹窗表格展示
|
||||
signDate: contentData.signDate || item.signDate || '',
|
||||
// 🔧 签发人:从 contentJson 中提取,供医嘱弹窗表格展示
|
||||
signDoctorName: contentData.signDoctorName || item.signDoctorName || '',
|
||||
originalMedicine: {
|
||||
...item,
|
||||
medicineName: medicineName,
|
||||
@@ -2473,6 +2485,8 @@ function handleMedicalAdvice(row) {
|
||||
dosage: 1, unit: 'ml', usage: 'iv', usageLabel: '静脉注射',
|
||||
frequency: '立即',
|
||||
executeTime: '',
|
||||
signDate: '',
|
||||
signDoctorName: '',
|
||||
originalMedicine: {
|
||||
...item,
|
||||
medicineName: item.adviceName || item.advice_name || '',
|
||||
@@ -2599,21 +2613,31 @@ function handleTemporaryMedicalSubmit(data) {
|
||||
const contentData = jsonContent ? JSON.parse(jsonContent) : {}
|
||||
const medicineName = contentData.adviceName || contentData.advice_name || item.adviceName || item.advice_name || ''
|
||||
const spec = contentData.volume || contentData.specification || item.volume || item.specification || ''
|
||||
const specMatch = spec.match(/(\d+)(\D+)/)
|
||||
const specValue = specMatch ? parseInt(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : 'ml'
|
||||
const specMatch = spec.match(/([\d.]+)\s*([a-zA-Z\u4e00-\u9fa5]+)/)
|
||||
let specUnit = specMatch ? specMatch[2] : ''
|
||||
if (!specUnit) {
|
||||
specUnit = contentData.doseUnitCode || contentData.unitCode || contentData.unit || 'ml'
|
||||
}
|
||||
specUnit = specUnit.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '')
|
||||
const specValue = specMatch ? parseFloat(specMatch[1]) : 1
|
||||
const dosage = specValue * (contentData.quantity || item.quantity || 1)
|
||||
const oldToNewUsage2 = { 'iv': '404', 'po': '1', 'im': '403', 'sc': '401', 'ivgtt': '405', 'ih': '5', 'it': '610', 'ip': '604', 'top': '6', 'pr': '2' }
|
||||
let usageCode = contentData.methodCode || 'iv'
|
||||
if (oldToNewUsage2[usageCode]) { usageCode = oldToNewUsage2[usageCode] }
|
||||
return {
|
||||
id: index + 1, adviceName: medicineName, dosage, unit: specUnit,
|
||||
usage: usageCode, frequency: '立即',
|
||||
executeTime: '',
|
||||
executeTime: contentData.executeTime || contentData.execute_time || contentData.signDate
|
||||
|| item.signDate || item.executeTime || item.execute_time || '',
|
||||
signDate: contentData.signDate || item.signDate || '',
|
||||
signDoctorName: contentData.signDoctorName || item.signDoctorName || '',
|
||||
originalMedicine: { ...item, medicineName, specification: spec, quantity: contentData.quantity || item.quantity || 1, encounterId: row.visitId }
|
||||
}
|
||||
} catch (e) {
|
||||
return {
|
||||
id: index + 1, adviceName: item.adviceName || '', dosage: 1, unit: 'ml',
|
||||
usage: 'iv', frequency: '立即', executeTime: '',
|
||||
signDate: '', signDoctorName: '',
|
||||
originalMedicine: { ...item, medicineName: item.adviceName || '', specification: item.volume || '', quantity: item.quantity || 1, encounterId: row.visitId }
|
||||
}
|
||||
}
|
||||
@@ -2717,18 +2741,25 @@ function handleQuoteBilling() {
|
||||
const contentData = jsonContent ? JSON.parse(jsonContent) : {};
|
||||
const medicineName = contentData.adviceName || contentData.advice_name || item.adviceName || item.advice_name || '';
|
||||
const spec = contentData.volume || contentData.specification || item.volume || item.specification || '';
|
||||
const specMatch = spec.match(/(\d+)(\D+)/)
|
||||
const specValue = specMatch ? parseInt(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : 'ml'
|
||||
const specMatch = spec.match(/([\d.]+)\s*([a-zA-Z\u4e00-\u9fa5]+)/)
|
||||
let specUnit = specMatch ? specMatch[2] : ''
|
||||
if (!specUnit) {
|
||||
specUnit = contentData.doseUnitCode || contentData.unitCode || contentData.unit || 'ml'
|
||||
}
|
||||
specUnit = specUnit.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '')
|
||||
const specValue = specMatch ? parseFloat(specMatch[1]) : 1
|
||||
const dosage = specValue * (contentData.quantity || item.quantity || 1)
|
||||
const oldToNewUsage3 = { 'iv': '404', 'po': '1', 'im': '403', 'sc': '401', 'ivgtt': '405', 'ih': '5', 'it': '610', 'ip': '604', 'top': '6', 'pr': '2' }
|
||||
let usageCode = contentData.methodCode || 'iv'
|
||||
if (oldToNewUsage3[usageCode]) { usageCode = oldToNewUsage3[usageCode] }
|
||||
let usageLabel = getUsageLabel(usageCode)
|
||||
if (usageCode === 'iv' && medicineName.includes('注射液')) { usageLabel = '静脉注射' }
|
||||
else if (usageCode === 'po' && (medicineName.includes('片') || medicineName.includes('胶囊'))) { usageLabel = '口服' }
|
||||
return {
|
||||
id: index + 1, adviceName: medicineName, dosage, unit: specUnit,
|
||||
usage: usageCode, usageLabel, frequency: '立即',
|
||||
executeTime: '',
|
||||
executeTime: contentData.executeTime || contentData.execute_time || contentData.signDate
|
||||
|| item.signDate || item.executeTime || item.execute_time || '',
|
||||
signDate: contentData.signDate || item.signDate || '',
|
||||
signDoctorName: contentData.signDoctorName || item.signDoctorName || '',
|
||||
originalMedicine: {
|
||||
...item,
|
||||
medicineName: medicineName,
|
||||
@@ -2742,6 +2773,7 @@ function handleQuoteBilling() {
|
||||
id: index + 1, adviceName: item.adviceName || item.advice_name || '',
|
||||
dosage: 1, unit: 'ml', usage: 'iv', usageLabel: '静脉注射',
|
||||
frequency: '立即', executeTime: '',
|
||||
signDate: '', signDoctorName: '',
|
||||
originalMedicine: {
|
||||
...item,
|
||||
medicineName: item.adviceName || item.advice_name || '',
|
||||
|
||||
@@ -198,7 +198,11 @@
|
||||
field="unit"
|
||||
min-width="80"
|
||||
align="center"
|
||||
/>
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ cleanUnitLabel(row.unit) || '-' }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
title="用法"
|
||||
field="usage"
|
||||
@@ -214,13 +218,21 @@
|
||||
field="frequency"
|
||||
min-width="80"
|
||||
align="center"
|
||||
/>
|
||||
>
|
||||
<template #default>
|
||||
立即
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
title="执行时间"
|
||||
field="executeTime"
|
||||
min-width="160"
|
||||
align="center"
|
||||
/>
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ row.executeTime || '-' }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
title="操作"
|
||||
min-width="140"
|
||||
@@ -511,9 +523,15 @@ const displayAdvicesList = computed(() => {
|
||||
|
||||
const isSigned = ref(false)
|
||||
|
||||
const signatureDoctor = ref(userStore.nickName || userStore.name || '未知用户')
|
||||
const signatureDoctor = ref('')
|
||||
const signatureTime = ref('')
|
||||
|
||||
// 🔧 工具函数:清洗单位字符串,去除所有特殊符号,只保留字母、数字、中文
|
||||
const cleanUnitLabel = (raw) => {
|
||||
if (!raw) return ''
|
||||
return String(raw).replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '')
|
||||
}
|
||||
|
||||
const showSignDialog = ref(false)
|
||||
const signPassword = ref('')
|
||||
const showEditDialog = ref(false)
|
||||
@@ -523,7 +541,7 @@ const editForm = ref({
|
||||
dosage: '',
|
||||
unit: '',
|
||||
usage: '',
|
||||
frequency: '临时'
|
||||
frequency: '立即'
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
@@ -552,9 +570,17 @@ const totalAmount = computed(() => {
|
||||
const convertedAdvices = computed(() => {
|
||||
return props.billingMedicines.map((medicine, index) => {
|
||||
// 解析规格中的数值和单位(支持小数,去除 ×、:、/、* 等多余字符)
|
||||
const specMatch = medicine.specification ? medicine.specification.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/) : null
|
||||
const specMatch = medicine.specification ? medicine.specification.match(/([\d.]+)\s*([a-zA-Z\u4e00-\u9fa5]+)/) : null
|
||||
const specValue = specMatch ? parseFloat(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : ''
|
||||
// 🔧 BugFix: 清洗单位 — 优先从正则提取,失败时回退到 doseUnitCode/unitCode,再清洗多余符号
|
||||
let specUnit = specMatch ? specMatch[2] : ''
|
||||
if (!specUnit && medicine.contentJson) {
|
||||
try {
|
||||
const cd = typeof medicine.contentJson === 'string' ? JSON.parse(medicine.contentJson) : medicine.contentJson
|
||||
specUnit = cd.doseUnitCode || cd.unitCode || cd.unit || ''
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
specUnit = specUnit.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '')
|
||||
|
||||
// 计算剂量 = 规格数值 × 数量
|
||||
const dosage = specValue * (medicine.quantity || 1)
|
||||
@@ -595,7 +621,16 @@ const displayAdvices = ref([])
|
||||
const initDisplayAdvices = () => {
|
||||
// 区域二只显示已生成(已签发)的数据,没有时保持为空,不自动转换区域一的草稿
|
||||
if (props.temporaryAdvices && props.temporaryAdvices.length > 0) {
|
||||
displayAdvices.value = props.temporaryAdvices.map(mapUsageCode)
|
||||
// 🔧 BugFix: 映射时同步清洗单位和频次(与 watch 保持一致)
|
||||
displayAdvices.value = props.temporaryAdvices.map(advice => {
|
||||
const mapped = { ...advice }
|
||||
if (usageCodeMapping[advice.usage]) {
|
||||
mapped.usage = usageCodeMapping[advice.usage]
|
||||
}
|
||||
mapped.unit = cleanUnitLabel(mapped.unit)
|
||||
mapped.frequency = '立即'
|
||||
return mapped
|
||||
})
|
||||
} else {
|
||||
displayAdvices.value = []
|
||||
}
|
||||
@@ -616,8 +651,20 @@ watch(() => props.temporaryAdvices, (newVal, oldVal) => {
|
||||
|
||||
// 如果 props 有新数据,更新 displayAdvices
|
||||
if (newVal && newVal.length > 0) {
|
||||
// 🔧 修复:将旧编码映射到新编码
|
||||
displayAdvices.value = newVal.map(mapUsageCode)
|
||||
// 🔧 修复:将旧编码映射到新编码,同时强制清洗单位和频次
|
||||
displayAdvices.value = newVal.map(advice => {
|
||||
const mapped = { ...advice }
|
||||
// 用法编码映射
|
||||
if (usageCodeMapping[advice.usage]) {
|
||||
mapped.usage = usageCodeMapping[advice.usage]
|
||||
}
|
||||
// 🔧 BugFix: 清洗单位(去除 ×、:、/ 等多余字符)
|
||||
mapped.unit = cleanUnitLabel(mapped.unit)
|
||||
// 🔧 BugFix: 频次强制修正为"立即"(临床应用要求)
|
||||
mapped.frequency = '立即'
|
||||
// 🔧 BugFix: 执行时间不应为空时回退为空串(由父组件从 contentJson 中取持久化值)
|
||||
return mapped
|
||||
})
|
||||
}
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
@@ -639,6 +686,14 @@ const handleSign = () => {
|
||||
|
||||
// 点击已生成列表行 → 回显该行的签名信息
|
||||
const handleAdviceRowClick = (row) => {
|
||||
// 🔧 优先从映射后的顶层字段读取(index.vue 已将 contentJson 中的签名字段提取到顶层)
|
||||
if (row.signDoctorName || row.signDate) {
|
||||
if (row.signDoctorName) signatureDoctor.value = row.signDoctorName
|
||||
if (row.signDate) signatureTime.value = row.signDate
|
||||
isSigned.value = true
|
||||
return
|
||||
}
|
||||
// 回退到 originalMedicine.contentJson
|
||||
const om = row?.originalMedicine
|
||||
if (!om) return
|
||||
const contentJson = om.contentJson || om.content_json
|
||||
@@ -669,9 +724,9 @@ const handleEditAdvice = (index) => {
|
||||
editForm.value = {
|
||||
adviceName: advice.adviceName,
|
||||
dosage: advice.dosage,
|
||||
unit: advice.unit,
|
||||
unit: cleanUnitLabel(advice.unit),
|
||||
usage: usageCode, // 使用映射后的正确编码
|
||||
frequency: advice.frequency
|
||||
frequency: '立即'
|
||||
}
|
||||
showEditDialog.value = true
|
||||
}
|
||||
@@ -735,7 +790,7 @@ const handleSaveEdit = async () => {
|
||||
|
||||
// 如果用户修改了剂量,重新计算数量
|
||||
if (originalMedicine.specification) {
|
||||
const specMatch = originalMedicine.specification.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/)
|
||||
const specMatch = originalMedicine.specification.match(/([\d.]+)\s*([a-zA-Z\u4e00-\u9fa5]+)/)
|
||||
const specValue = specMatch ? parseFloat(specMatch[1]) : 1
|
||||
if (specValue > 0) {
|
||||
const newQuantity = editForm.value.dosage / specValue
|
||||
@@ -770,8 +825,11 @@ const handleSaveEdit = async () => {
|
||||
try { contentJsonData = JSON.parse(editMedicine.contentJson || '{}') } catch (e) {}
|
||||
const quantity = editMedicine.quantity || contentJsonData.quantity || 1
|
||||
const unitPrice = editMedicine.unitPrice || contentJsonData.unitPrice || 0
|
||||
// 🔧 BugFix: 清理单位中的多余符号
|
||||
const cleanUnit = cleanUnitLabel(editForm.value.unit)
|
||||
const cleanDoseUnitCode = cleanUnitLabel(editForm.value.unit)
|
||||
contentJsonData.dose = editForm.value.dosage
|
||||
contentJsonData.doseUnitCode = editForm.value.unit
|
||||
contentJsonData.doseUnitCode = cleanDoseUnitCode
|
||||
contentJsonData.methodCode = updatedAdvice.usage
|
||||
contentJsonData.quantity = quantity
|
||||
contentJsonData.totalPrice = unitPrice * quantity
|
||||
@@ -785,7 +843,7 @@ const handleSaveEdit = async () => {
|
||||
chargeItemId: editMedicine.chargeItemId,
|
||||
contentJson: JSON.stringify(contentJsonData),
|
||||
quantity,
|
||||
unitCode: editMedicine.unitCode || editForm.value.unit,
|
||||
unitCode: editMedicine.unitCode || cleanUnit,
|
||||
unitPrice,
|
||||
totalPrice: unitPrice * quantity,
|
||||
adviceName: updatedAdvice.adviceName,
|
||||
@@ -794,7 +852,7 @@ const handleSaveEdit = async () => {
|
||||
orgId: props.patientInfo.orgId,
|
||||
methodCode: updatedAdvice.usage,
|
||||
dose: editForm.value.dosage,
|
||||
doseUnitCode: editForm.value.unit,
|
||||
doseUnitCode: cleanDoseUnitCode,
|
||||
generateSourceEnum: 6,
|
||||
sourceBillNo: props.patientInfo?.operCode || ''
|
||||
}
|
||||
@@ -938,7 +996,9 @@ const handleSubmit = async () => {
|
||||
// ✅ 关键修复:把修改后的数据更新到contentJson中,后端会优先读取这里的值
|
||||
contentJsonData.adviceName = advice.adviceName;
|
||||
contentJsonData.quantity = quantity;
|
||||
contentJsonData.volume = advice.dosage + (advice.unit || '');
|
||||
// 🔧 BugFix: 清理单位中的多余符号,确保 volume 字段只包含纯单位名称
|
||||
const cleanUnit = cleanUnitLabel(advice.unit);
|
||||
contentJsonData.volume = advice.dosage + cleanUnit;
|
||||
contentJsonData.totalPrice = totalPrice;
|
||||
contentJsonData.unitPrice = unitPrice;
|
||||
// 用法、剂量、单位也更新到contentJson
|
||||
@@ -957,10 +1017,12 @@ const handleSubmit = async () => {
|
||||
}
|
||||
contentJsonData.methodCode = methodCode;
|
||||
contentJsonData.dose = advice.dosage;
|
||||
contentJsonData.doseUnitCode = advice.unit;
|
||||
// 🔧 BugFix: 清理单位中的多余符号,确保保存的单位是纯单位名称
|
||||
contentJsonData.doseUnitCode = cleanUnitLabel(advice.unit);
|
||||
contentJsonData.rateCode = advice.frequency;
|
||||
contentJsonData.signDoctorName = signatureDoctor.value
|
||||
contentJsonData.signDate = signatureTime.value
|
||||
contentJsonData.executeTime = signatureTime.value
|
||||
|
||||
// 重新序列化contentJson
|
||||
const updatedContentJson = JSON.stringify(contentJsonData);
|
||||
@@ -981,7 +1043,7 @@ const handleSubmit = async () => {
|
||||
|
||||
// 数量和单位:使用重新计算后的数量
|
||||
quantity: quantity,
|
||||
unitCode: contentJsonData.unitCode || originalMedicine?.unitCode || advice.unit,
|
||||
unitCode: contentJsonData.unitCode || originalMedicine?.unitCode || cleanUnitLabel(advice.unit),
|
||||
unitPrice: unitPrice,
|
||||
totalPrice: totalPrice,
|
||||
definitionId: originalMedicine?.definitionId ? String(originalMedicine.definitionId) : contentJsonData.definitionId ? String(contentJsonData.definitionId) : advice.definitionId ? String(advice.definitionId) : null,
|
||||
@@ -1014,7 +1076,7 @@ const handleSubmit = async () => {
|
||||
methodCode: methodCode,
|
||||
rateCode: advice.frequency,
|
||||
dose: advice.dosage,
|
||||
doseUnitCode: contentJsonData.doseUnitCode || originalMedicine?.doseUnitCode || advice.unit,
|
||||
doseUnitCode: contentJsonData.doseUnitCode || originalMedicine?.doseUnitCode || cleanUnitLabel(advice.unit),
|
||||
skinTestFlag: originalMedicine?.skinTestFlag || contentJsonData.skinTestFlag,
|
||||
injectFlag: originalMedicine?.injectFlag || contentJsonData.injectFlag,
|
||||
|
||||
|
||||
@@ -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