fix(core): 修复审计字段缺失和组件状态管理问题
- 在Account、ChargeItem、EncounterParticipant和Encounter服务中添加审计字段验证 - 确保tenantId、createBy和createTime字段在插入数据库前正确设置 - 修复EMR模块中删除模板API的导出问题 - 更新患者信息状态管理,统一使用localPatientInfo替换patientInfo - 在EMR组件中实现防抖机制优化历史记录刷新性能 - 修复病历模板切换时的表单数据重置逻辑 - 在首页统计组件中使用markRaw包装图标组件 - 为住院记录模板添加默认表单数据结构 - 修复SVG患者图标路径错误
This commit is contained in:
@@ -1419,6 +1419,19 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 确保所有PaymentRecDetail对象的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
for (PaymentRecDetail detail : paymentRecDetails) {
|
||||||
|
if (detail.getTenantId() == null) {
|
||||||
|
detail.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (detail.getCreateBy() == null || detail.getCreateBy().isEmpty()) {
|
||||||
|
detail.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (detail.getCreateTime() == null) {
|
||||||
|
detail.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
paymentRecDetailService.saveBatch(paymentRecDetails);
|
paymentRecDetailService.saveBatch(paymentRecDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1754,6 +1767,17 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
BeanUtils.copyProperties(outpatientRegistrationAddParam.getChargeItemFormData(), chargeItem);
|
BeanUtils.copyProperties(outpatientRegistrationAddParam.getChargeItemFormData(), chargeItem);
|
||||||
chargeItem.setContextEnum(ChargeItemContext.REGISTER.getValue());// 挂号
|
chargeItem.setContextEnum(ChargeItemContext.REGISTER.getValue());// 挂号
|
||||||
|
|
||||||
|
// 确保必需的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
if (chargeItem.getTenantId() == null) {
|
||||||
|
chargeItem.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (chargeItem.getCreateBy() == null || chargeItem.getCreateBy().isEmpty()) {
|
||||||
|
chargeItem.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (chargeItem.getCreateTime() == null) {
|
||||||
|
chargeItem.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
YbPsnSetlWay finCategory = YbPsnSetlWay.getByValue(outpatientRegistrationAddParam.getYbPsnSetlWay());
|
YbPsnSetlWay finCategory = YbPsnSetlWay.getByValue(outpatientRegistrationAddParam.getYbPsnSetlWay());
|
||||||
if (finCategory == null) {
|
if (finCategory == null) {
|
||||||
throw new ServiceException("请选择收费方式");
|
throw new ServiceException("请选择收费方式");
|
||||||
@@ -1818,11 +1842,23 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
// 保存就诊信息
|
// 保存就诊信息
|
||||||
Encounter encounter = new Encounter();
|
Encounter encounter = new Encounter();
|
||||||
BeanUtils.copyProperties(encounterFormData, encounter);
|
BeanUtils.copyProperties(encounterFormData, encounter);
|
||||||
// 将挂号医生ID提前塞入 encounter 的 registrarId,便于生成“科室+医生+当日”序号
|
// 将挂号医生ID提前塞入 encounter 的 registrarId,便于生成"科室+医生+当日"序号
|
||||||
if (encounterParticipantFormData.getPractitionerId() != null) {
|
if (encounterParticipantFormData.getPractitionerId() != null) {
|
||||||
encounter.setRegistrarId(encounterParticipantFormData.getPractitionerId());
|
encounter.setRegistrarId(encounterParticipantFormData.getPractitionerId());
|
||||||
}
|
}
|
||||||
encounter.setBusNo(outpatientRegistrationSettleParam.getBusNo());
|
encounter.setBusNo(outpatientRegistrationSettleParam.getBusNo());
|
||||||
|
|
||||||
|
// 确保必需的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
if (encounter.getTenantId() == null) {
|
||||||
|
encounter.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (encounter.getCreateBy() == null || encounter.getCreateBy().isEmpty()) {
|
||||||
|
encounter.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (encounter.getCreateTime() == null) {
|
||||||
|
encounter.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
// 就诊ID
|
// 就诊ID
|
||||||
Long encounterId = iEncounterService.saveEncounterByRegister(encounter);
|
Long encounterId = iEncounterService.saveEncounterByRegister(encounter);
|
||||||
// 保存就诊位置信息
|
// 保存就诊位置信息
|
||||||
@@ -1920,6 +1956,18 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
.setChargeItemIds(chargeItemIdList.stream().map(String::valueOf).collect(Collectors.joining(",")))
|
.setChargeItemIds(chargeItemIdList.stream().map(String::valueOf).collect(Collectors.joining(",")))
|
||||||
.setTenderedAmount(chargeItem.getTotalPrice()).setDisplayAmount(paymentResult.getPsnPartAmt())
|
.setTenderedAmount(chargeItem.getTotalPrice()).setDisplayAmount(paymentResult.getPsnPartAmt())
|
||||||
.setReturnedAmount(new BigDecimal("0.0")).setEncounterId(encounter.getId());
|
.setReturnedAmount(new BigDecimal("0.0")).setEncounterId(encounter.getId());
|
||||||
|
|
||||||
|
// 确保必需的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
if (payment.getTenantId() == null) {
|
||||||
|
payment.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (payment.getCreateBy() == null || payment.getCreateBy().isEmpty()) {
|
||||||
|
payment.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (payment.getCreateTime() == null) {
|
||||||
|
payment.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
// 保存付款信息
|
// 保存付款信息
|
||||||
paymentReconciliationService.save(payment);
|
paymentReconciliationService.save(payment);
|
||||||
// 保存付款详情
|
// 保存付款详情
|
||||||
@@ -1938,6 +1986,18 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
invoice.setPatientId(encounter.getPatientId()).setStatusEnum(InvoiceStatus.DRAFT)
|
invoice.setPatientId(encounter.getPatientId()).setStatusEnum(InvoiceStatus.DRAFT)
|
||||||
.setReconciliationId(payment.getId()).setTypeCode(InvoiceType.ISSUING_INVOICES.getValue())
|
.setReconciliationId(payment.getId()).setTypeCode(InvoiceType.ISSUING_INVOICES.getValue())
|
||||||
.setChargeItemIds(payment.getChargeItemIds().toString());
|
.setChargeItemIds(payment.getChargeItemIds().toString());
|
||||||
|
|
||||||
|
// 确保必需的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
if (invoice.getTenantId() == null) {
|
||||||
|
invoice.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (invoice.getCreateBy() == null || invoice.getCreateBy().isEmpty()) {
|
||||||
|
invoice.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (invoice.getCreateTime() == null) {
|
||||||
|
invoice.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
iInvoiceService.save(invoice);
|
iInvoiceService.save(invoice);
|
||||||
return R.ok(payment, "收费成功");
|
return R.ok(payment, "收费成功");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.openhis.administration.service.impl;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.core.common.utils.SecurityUtils;
|
||||||
import com.openhis.administration.domain.Account;
|
import com.openhis.administration.domain.Account;
|
||||||
import com.openhis.administration.mapper.AccountMapper;
|
import com.openhis.administration.mapper.AccountMapper;
|
||||||
import com.openhis.administration.service.IAccountService;
|
import com.openhis.administration.service.IAccountService;
|
||||||
@@ -32,6 +33,18 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
@Override
|
@Override
|
||||||
public Long saveAccountByRegister(Account account) {
|
public Long saveAccountByRegister(Account account) {
|
||||||
account.setEncounterFlag(Whether.YES.getValue());
|
account.setEncounterFlag(Whether.YES.getValue());
|
||||||
|
|
||||||
|
// 确保必需的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
if (account.getTenantId() == null) {
|
||||||
|
account.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (account.getCreateBy() == null || account.getCreateBy().isEmpty()) {
|
||||||
|
account.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (account.getCreateTime() == null) {
|
||||||
|
account.setCreateTime(new java.util.Date());
|
||||||
|
}
|
||||||
|
|
||||||
baseMapper.insert(account);
|
baseMapper.insert(account);
|
||||||
return account.getId();
|
return account.getId();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,18 @@ public class ChargeItemServiceImpl extends ServiceImpl<ChargeItemMapper, ChargeI
|
|||||||
@Override
|
@Override
|
||||||
public void saveChargeItemByRegister(ChargeItem chargeItem) {
|
public void saveChargeItemByRegister(ChargeItem chargeItem) {
|
||||||
chargeItem.setContextEnum(ChargeItemContext.REGISTER.getValue());// 挂号
|
chargeItem.setContextEnum(ChargeItemContext.REGISTER.getValue());// 挂号
|
||||||
|
|
||||||
|
// 确保必需的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
if (chargeItem.getTenantId() == null) {
|
||||||
|
chargeItem.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (chargeItem.getCreateBy() == null || chargeItem.getCreateBy().isEmpty()) {
|
||||||
|
chargeItem.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (chargeItem.getCreateTime() == null) {
|
||||||
|
chargeItem.setCreateTime(new java.util.Date());
|
||||||
|
}
|
||||||
|
|
||||||
baseMapper.insert(chargeItem);
|
baseMapper.insert(chargeItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.openhis.administration.service.impl;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.core.common.utils.SecurityUtils;
|
||||||
import com.core.common.enums.DelFlag;
|
import com.core.common.enums.DelFlag;
|
||||||
import com.openhis.administration.domain.EncounterParticipant;
|
import com.openhis.administration.domain.EncounterParticipant;
|
||||||
import com.openhis.administration.mapper.EncounterParticipantMapper;
|
import com.openhis.administration.mapper.EncounterParticipantMapper;
|
||||||
@@ -32,6 +33,17 @@ public class EncounterParticipantServiceImpl extends ServiceImpl<EncounterPartic
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void saveEncounterParticipant(EncounterParticipant encounterParticipant) {
|
public void saveEncounterParticipant(EncounterParticipant encounterParticipant) {
|
||||||
|
// 确保必需的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
if (encounterParticipant.getTenantId() == null) {
|
||||||
|
encounterParticipant.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (encounterParticipant.getCreateBy() == null || encounterParticipant.getCreateBy().isEmpty()) {
|
||||||
|
encounterParticipant.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (encounterParticipant.getCreateTime() == null) {
|
||||||
|
encounterParticipant.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
baseMapper.insert(encounterParticipant);
|
baseMapper.insert(encounterParticipant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.core.common.utils.AssignSeqUtil;
|
import com.core.common.utils.AssignSeqUtil;
|
||||||
|
import com.core.common.utils.SecurityUtils;
|
||||||
import com.core.common.utils.StringUtils;
|
import com.core.common.utils.StringUtils;
|
||||||
import com.openhis.administration.domain.Encounter;
|
import com.openhis.administration.domain.Encounter;
|
||||||
import com.openhis.administration.dto.EncounterAccountDto;
|
import com.openhis.administration.dto.EncounterAccountDto;
|
||||||
@@ -45,9 +46,9 @@ public class EncounterServiceImpl extends ServiceImpl<EncounterMapper, Encounter
|
|||||||
encounter.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.ENCOUNTER_NUM.getPrefix(), 4));
|
encounter.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.ENCOUNTER_NUM.getPrefix(), 4));
|
||||||
}
|
}
|
||||||
// 生成就诊序号:
|
// 生成就诊序号:
|
||||||
// 1) 若挂号医生已传入(registrarId 充当挂号医生 ID),按“科室+医生+当日”递增
|
// 1) 若挂号医生已传入(registrarId 充当挂号医生 ID),按"科室+医生+当日"递增
|
||||||
// Key 示例:ORG-123-DOC-456 -> 1、2、3...
|
// Key 示例:ORG-123-DOC-456 -> 1、2、3...
|
||||||
// 2) 否则按“科室+当日”递增
|
// 2) 否则按"科室+当日"递增
|
||||||
String preFix;
|
String preFix;
|
||||||
if (encounter.getRegistrarId() != null) {
|
if (encounter.getRegistrarId() != null) {
|
||||||
preFix = "ORG-" + encounter.getOrganizationId() + "-DOC-" + encounter.getRegistrarId();
|
preFix = "ORG-" + encounter.getOrganizationId() + "-DOC-" + encounter.getRegistrarId();
|
||||||
@@ -62,6 +63,18 @@ public class EncounterServiceImpl extends ServiceImpl<EncounterMapper, Encounter
|
|||||||
if (count > 0L) {
|
if (count > 0L) {
|
||||||
encounter.setFirstEnum(EncounterType.FOLLOW_UP.getValue());
|
encounter.setFirstEnum(EncounterType.FOLLOW_UP.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 确保必需的审计字段被设置,防止违反NOT NULL约束
|
||||||
|
if (encounter.getTenantId() == null) {
|
||||||
|
encounter.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||||
|
}
|
||||||
|
if (encounter.getCreateBy() == null || encounter.getCreateBy().isEmpty()) {
|
||||||
|
encounter.setCreateBy(SecurityUtils.getLoginUser().getUsername());
|
||||||
|
}
|
||||||
|
if (encounter.getCreateTime() == null) {
|
||||||
|
encounter.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
baseMapper.insert(encounter);
|
baseMapper.insert(encounter);
|
||||||
return encounter.getId();
|
return encounter.getId();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M512 128c-70.69 0-128 57.31-128 128 0 70.69 57.31 128 128 70.69 0 128-57.31 128-128 0-70.69-57.31-128-128-128zm0 192c-35.34 0-64-28.66-64-64 0-35.34 28.66-64 64-64 35.34 0 64 28.66 64 64 0 35.34-28.66 64-64 64z" fill="currentColor"/>
|
<path d="M512 128c-70.69 0-128 57.31-128 128 0 70.69 57.31 128 128 128s128-57.31 128-128-57.31-128-128-128zm0 192c-35.34 0-64-28.66-64-64 0-35.34 28.66-64 64-64 35.34 0 64 28.66 64 64 0 35.34-28.66 64-64 64z" fill="currentColor"/>
|
||||||
<path d="M832 832c0-88.36-28.7-172.6-80.4-242.4C702 521 608 480 512 480s-190 41-239.6 109.6C221 659.4 192 743.64 192 832v64h640v-64z" fill="currentColor"/>
|
<path d="M832 832c0-88.36-28.7-172.6-80.4-242.4C702 521 608 480 512 480s-190 41-239.6 109.6C221 659.4 192 743.64 192 832v64h640v-64z" fill="currentColor"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 476 B |
@@ -97,21 +97,6 @@ export const constantRoutes = [
|
|||||||
|
|
||||||
// 动态路由,基于用户权限动态去加载
|
// 动态路由,基于用户权限动态去加载
|
||||||
export const dynamicRoutes = [
|
export const dynamicRoutes = [
|
||||||
{
|
|
||||||
path: '/basicmanage',
|
|
||||||
component: Layout,
|
|
||||||
redirect: '/basicmanage/invoice-management',
|
|
||||||
name: 'BasicManage',
|
|
||||||
meta: { title: '基础管理', icon: 'component' },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'invoice-management',
|
|
||||||
component: () => import('@/views/basicmanage/InvoiceManagement/index.vue'),
|
|
||||||
name: 'invoice-management',
|
|
||||||
meta: { title: '发票管理' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/system/tenant-user',
|
path: '/system/tenant-user',
|
||||||
|
|||||||
@@ -490,6 +490,61 @@ const formData = reactive({
|
|||||||
signDate: '',
|
signDate: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 默认表单数据
|
||||||
|
const defaultFormData = {
|
||||||
|
// 基础信息
|
||||||
|
patientName: patient?.name || '',
|
||||||
|
hospitalNo: patient?.busNo || '',
|
||||||
|
gender: patient?.genderEnum_enumText || '',
|
||||||
|
age: patient?.age || '',
|
||||||
|
nation: '',
|
||||||
|
occupation: '', // 职业
|
||||||
|
marriage: '', // 婚姻状况
|
||||||
|
birthplace: '', // 出生地
|
||||||
|
admissionTime: '', // 入院时间
|
||||||
|
recordTime: '', // 记录时间
|
||||||
|
historyReporter: '', // 病史陈述者
|
||||||
|
reliability: '可靠', // 可靠程度
|
||||||
|
// 病史信息
|
||||||
|
complaint: '', // 主诉
|
||||||
|
presentIllness: '', // 现病史
|
||||||
|
pastIllness: '', // 既往史
|
||||||
|
personalHistory: '', // 个人史
|
||||||
|
allergyHistory: '', // 过敏史
|
||||||
|
pastHistory: '', // 既往史
|
||||||
|
familyHistory: '', // 家族史
|
||||||
|
maritalHistory: '', // 婚姻史
|
||||||
|
menstrualHistory: '', // 月经史
|
||||||
|
// 中医信息
|
||||||
|
tcmInfo: '',
|
||||||
|
|
||||||
|
// 体格检查
|
||||||
|
temp: '',
|
||||||
|
pulse: '',
|
||||||
|
respiration: '',
|
||||||
|
bp: '',
|
||||||
|
height: '',
|
||||||
|
weight: '',
|
||||||
|
bmi: '',
|
||||||
|
general: '',
|
||||||
|
skin: '',
|
||||||
|
chest: '',
|
||||||
|
abdomen: '',
|
||||||
|
limbsNervous: '',
|
||||||
|
|
||||||
|
// 辅助检查
|
||||||
|
auxExam: '',
|
||||||
|
|
||||||
|
// 诊断信息
|
||||||
|
tcmDiagnosis: '',
|
||||||
|
westernDiagnosis: '',
|
||||||
|
|
||||||
|
// 签名信息
|
||||||
|
doctorSign: '',
|
||||||
|
superiorSign: '',
|
||||||
|
signDate: '',
|
||||||
|
};
|
||||||
|
|
||||||
// 表单校验规则
|
// 表单校验规则
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
name: [{ required: true, message: '请填写姓名', trigger: ['blur', 'submit'] }],
|
name: [{ required: true, message: '请填写姓名', trigger: ['blur', 'submit'] }],
|
||||||
@@ -623,8 +678,19 @@ const handleReset = () => {
|
|||||||
|
|
||||||
// 表单数据赋值
|
// 表单数据赋值
|
||||||
const setFormData = (data) => {
|
const setFormData = (data) => {
|
||||||
if (data) {
|
if (data && Object.keys(data).length > 0) {
|
||||||
|
// 如果有数据,则合并到表单中
|
||||||
Object.assign(formData, data);
|
Object.assign(formData, data);
|
||||||
|
} else {
|
||||||
|
// 如果没有数据或数据为空,则重置为默认值
|
||||||
|
// 保留患者基础信息(来自props)
|
||||||
|
Object.assign(formData, {
|
||||||
|
...defaultFormData,
|
||||||
|
patientName: patient?.name || formData.patientName,
|
||||||
|
hospitalNo: patient?.busNo || formData.hospitalNo,
|
||||||
|
gender: patient?.genderEnum_enumText || formData.gender,
|
||||||
|
age: patient?.age || formData.age,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -438,7 +438,7 @@
|
|||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="挂号类型 "
|
label="*挂号类型 "
|
||||||
align="center"
|
align="center"
|
||||||
key="healthcareName"
|
key="healthcareName"
|
||||||
prop="healthcareName"
|
prop="healthcareName"
|
||||||
@@ -734,6 +734,7 @@ const data = reactive({
|
|||||||
priorityEnum: [{ required: true, message: '优先级不能为空', trigger: 'blur' }],
|
priorityEnum: [{ required: true, message: '优先级不能为空', trigger: 'blur' }],
|
||||||
organizationId: [{ required: true, message: '优先级不能为空', trigger: 'blur' }],
|
organizationId: [{ required: true, message: '优先级不能为空', trigger: 'blur' }],
|
||||||
orgId: [{ required: true, message: '就诊科室不能为空', trigger: 'blur' }],
|
orgId: [{ required: true, message: '就诊科室不能为空', trigger: 'blur' }],
|
||||||
|
serviceTypeId: [{ required: true, message: '挂号类型不能为空', trigger: 'blur' }],
|
||||||
practitionerId: [{ required: true, message: '医生不能为空', trigger: 'blur' }],
|
practitionerId: [{ required: true, message: '医生不能为空', trigger: 'blur' }],
|
||||||
typeCode: [{ required: true, message: '账户类型不能为空', trigger: 'blur' }],
|
typeCode: [{ required: true, message: '账户类型不能为空', trigger: 'blur' }],
|
||||||
definitionId: [{ required: true, message: '费用定价不能为空', trigger: 'blur' }],
|
definitionId: [{ required: true, message: '费用定价不能为空', trigger: 'blur' }],
|
||||||
|
|||||||
@@ -26,9 +26,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {defineEmits, ref, unref} from 'vue';
|
import {defineEmits, ref, unref, watch} from 'vue';
|
||||||
import {deleteTemplate, getListByDefinitionId} from '../api';
|
import {deleteTemplate, getListByDefinitionId} from '../api';
|
||||||
import {ElMessage} from 'element-plus';
|
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||||
|
|
||||||
const emits = defineEmits(['templateClick', 'edit']);
|
const emits = defineEmits(['templateClick', 'edit']);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -45,26 +45,54 @@ const defaultProps = {
|
|||||||
children: 'children',
|
children: 'children',
|
||||||
label: 'name',
|
label: 'name',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 缓存已加载的模板数据
|
||||||
|
const templateCache = new Map();
|
||||||
const queryParams = ref({
|
const queryParams = ref({
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
isPage: 0,
|
isPage: 0,
|
||||||
});
|
});
|
||||||
const templateData = ref([]);
|
const templateData = ref([]);
|
||||||
|
|
||||||
|
// 防抖定时器
|
||||||
|
let debounceTimer = null;
|
||||||
|
|
||||||
// 删除模板
|
// 删除模板
|
||||||
const handleDelete = async (item) => {
|
const handleDelete = async (item) => {
|
||||||
try {
|
try {
|
||||||
|
ElMessageBox.confirm('确定要删除该模板吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(async () => {
|
||||||
await deleteTemplate(item.id);
|
await deleteTemplate(item.id);
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
|
// 清除缓存中的数据,强制重新加载
|
||||||
|
templateCache.delete(unref(definitionId));
|
||||||
queryList();
|
queryList();
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
ElMessage.error('删除失败');
|
ElMessage.error('删除失败');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryList = async () => {
|
const queryList = async () => {
|
||||||
try {
|
try {
|
||||||
if (unref(definitionId) && unref(definitionId) !== '') {
|
const id = unref(definitionId);
|
||||||
const res = await getListByDefinitionId(unref(definitionId));
|
if (id && id !== '') {
|
||||||
templateData.value = res.data || [];
|
// 检查缓存中是否存在数据
|
||||||
|
if (templateCache.has(id)) {
|
||||||
|
templateData.value = templateCache.get(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getListByDefinitionId(id);
|
||||||
|
const data = res.data || [];
|
||||||
|
// 将数据存入缓存
|
||||||
|
templateCache.set(id, data);
|
||||||
|
templateData.value = data;
|
||||||
} else {
|
} else {
|
||||||
templateData.value = [];
|
templateData.value = [];
|
||||||
}
|
}
|
||||||
@@ -73,6 +101,23 @@ const queryList = async () => {
|
|||||||
templateData.value = [];
|
templateData.value = [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 防抖版本的查询函数
|
||||||
|
const debouncedQueryList = async () => {
|
||||||
|
if (debounceTimer) {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
debounceTimer = setTimeout(async () => {
|
||||||
|
await queryList();
|
||||||
|
}, 300); // 300ms 防抖延迟
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听 definitionId 变化,使用防抖
|
||||||
|
watch(definitionId, () => {
|
||||||
|
debouncedQueryList();
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
const handleNodeClick = (data) => {
|
const handleNodeClick = (data) => {
|
||||||
emits('templateClick', data);
|
emits('templateClick', data);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -125,6 +125,7 @@
|
|||||||
<script setup name="Home">
|
<script setup name="Home">
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import { markRaw } from 'vue'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import { getHomeStatistics } from '@/api/home'
|
import { getHomeStatistics } from '@/api/home'
|
||||||
import {
|
import {
|
||||||
@@ -171,90 +172,90 @@ const statisticsData = ref({
|
|||||||
// 不同角色的统计数据配置
|
// 不同角色的统计数据配置
|
||||||
const roleStatsConfig = {
|
const roleStatsConfig = {
|
||||||
admin: [
|
admin: [
|
||||||
{ key: 'totalPatients', label: '在院患者', icon: User, type: 'primary', iconColor: '#409eff' },
|
{ key: 'totalPatients', label: '在院患者', icon: markRaw(User), type: 'primary', iconColor: '#409eff' },
|
||||||
{ key: 'todayRevenue', label: '今日收入', icon: Money, type: 'success', iconColor: '#67c23a' },
|
{ key: 'todayRevenue', label: '今日收入', icon: markRaw(Money), type: 'success', iconColor: '#67c23a' },
|
||||||
{ key: 'appointments', label: '今日预约', icon: Calendar, type: 'warning', iconColor: '#e6a23c' },
|
{ key: 'appointments', label: '今日预约', icon: markRaw(Calendar), type: 'warning', iconColor: '#e6a23c' },
|
||||||
{ key: 'pendingApprovals', label: '待审核', icon: Document, type: 'danger', iconColor: '#f56c6c' }
|
{ key: 'pendingApprovals', label: '待审核', icon: markRaw(Document), type: 'danger', iconColor: '#f56c6c' }
|
||||||
],
|
],
|
||||||
doctor: [
|
doctor: [
|
||||||
{ key: 'myPatients', label: '我的患者', icon: User, type: 'primary', iconColor: '#409eff' },
|
{ key: 'myPatients', label: '我的患者', icon: markRaw(User), type: 'primary', iconColor: '#409eff' },
|
||||||
{ key: 'todayAppointments', label: '今日门诊', icon: Calendar, type: 'success', iconColor: '#67c23a' },
|
{ key: 'todayAppointments', label: '今日门诊', icon: markRaw(Calendar), type: 'success', iconColor: '#67c23a' },
|
||||||
{ key: 'pendingRecords', label: '待写病历', icon: Document, type: 'warning', iconColor: '#e6a23c' },
|
{ key: 'pendingRecords', label: '待写病历', icon: markRaw(Document), type: 'warning', iconColor: '#e6a23c' },
|
||||||
{ key: 'prescriptions', label: '今日处方', icon: Box, type: 'info', iconColor: '#909399' }
|
{ key: 'prescriptions', label: '今日处方', icon: markRaw(Box), type: 'info', iconColor: '#909399' }
|
||||||
],
|
],
|
||||||
nurse: [
|
nurse: [
|
||||||
{ key: 'wardPatients', label: '病房患者', icon: User, type: 'primary', iconColor: '#409eff' },
|
{ key: 'wardPatients', label: '病房患者', icon: markRaw(User), type: 'primary', iconColor: '#409eff' },
|
||||||
{ key: 'todayTreatments', label: '今日治疗', icon: Operation, type: 'success', iconColor: '#67c23a' },
|
{ key: 'todayTreatments', label: '今日治疗', icon: markRaw(Operation), type: 'success', iconColor: '#67c23a' },
|
||||||
{ key: 'vitalSigns', label: '待测体征', icon: Monitor, type: 'warning', iconColor: '#e6a23c' },
|
{ key: 'vitalSigns', label: '待测体征', icon: markRaw(Monitor), type: 'warning', iconColor: '#e6a23c' },
|
||||||
{ key: 'drugDistribution', label: '发药次数', icon: Box, type: 'info', iconColor: '#909399' }
|
{ key: 'drugDistribution', label: '发药次数', icon: markRaw(Box), type: 'info', iconColor: '#909399' }
|
||||||
],
|
],
|
||||||
pharmacist: [
|
pharmacist: [
|
||||||
{ key: 'todayPrescriptions', label: '今日处方', icon: Box, type: 'primary', iconColor: '#409eff' },
|
{ key: 'todayPrescriptions', label: '今日处方', icon: markRaw(Box), type: 'primary', iconColor: '#409eff' },
|
||||||
{ key: 'pendingReview', label: '待审核', icon: Document, type: 'warning', iconColor: '#e6a23c' },
|
{ key: 'pendingReview', label: '待审核', icon: markRaw(Document), type: 'warning', iconColor: '#e6a23c' },
|
||||||
{ key: 'outOfStock', label: '缺货药品', icon: Warning, type: 'danger', iconColor: '#f56c6c' },
|
{ key: 'outOfStock', label: '缺货药品', icon: markRaw(Warning), type: 'danger', iconColor: '#f56c6c' },
|
||||||
{ key: 'nearExpiry', label: '近效期', icon: Clock, type: 'info', iconColor: '#909399' }
|
{ key: 'nearExpiry', label: '近效期', icon: markRaw(Clock), type: 'info', iconColor: '#909399' }
|
||||||
],
|
],
|
||||||
cashier: [
|
cashier: [
|
||||||
{ key: 'todayPayments', label: '今日缴费', icon: Money, type: 'primary', iconColor: '#409eff' },
|
{ key: 'todayPayments', label: '今日缴费', icon: markRaw(Money), type: 'primary', iconColor: '#409eff' },
|
||||||
{ key: 'refundRequests', label: '退费申请', icon: Document, type: 'warning', iconColor: '#e6a23c' },
|
{ key: 'refundRequests', label: '退费申请', icon: markRaw(Document), type: 'warning', iconColor: '#e6a23c' },
|
||||||
{ key: 'pendingInvoices', label: '待开发票', icon: Files, type: 'info', iconColor: '#909399' },
|
{ key: 'pendingInvoices', label: '待开发票', icon: markRaw(Files), type: 'info', iconColor: '#909399' },
|
||||||
{ key: 'insuranceClaims', label: '医保结算', icon: Wallet, type: 'success', iconColor: '#67c23a' }
|
{ key: 'insuranceClaims', label: '医保结算', icon: markRaw(Wallet), type: 'success', iconColor: '#67c23a' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 不同角色的快捷功能配置
|
// 不同角色的快捷功能配置
|
||||||
const roleQuickAccessConfig = {
|
const roleQuickAccessConfig = {
|
||||||
admin: [
|
admin: [
|
||||||
{ key: 'patient', label: '患者管理', icon: User, iconColor: '#409eff', route: '/patientmanagement' },
|
{ key: 'patient', label: '患者管理', icon: markRaw(User), iconColor: '#409eff', route: '/patientmanagement' },
|
||||||
{ key: 'appointment', label: '预约管理', icon: Calendar, iconColor: '#67c23a', route: '/appoinmentmanage' },
|
{ key: 'appointment', label: '预约管理', icon: markRaw(Calendar), iconColor: '#67c23a', route: '/appoinmentmanage' },
|
||||||
{ key: 'doctor', label: '医生管理', icon: User, iconColor: '#e6a23c', route: '/doctorstation' },
|
{ key: 'doctor', label: '医生管理', icon: markRaw(User), iconColor: '#e6a23c', route: '/doctorstation' },
|
||||||
{ key: 'surgery', label: '手术管理', icon: Operation, iconColor: '#f56c6c', route: '/surgerymanage' },
|
{ key: 'surgery', label: '手术管理', icon: markRaw(Operation), iconColor: '#f56c6c', route: '/surgerymanage' },
|
||||||
{ key: 'drug', label: '药品管理', icon: Box, iconColor: '#909399', route: '/pharmacymanagement' },
|
{ key: 'drug', label: '药品管理', icon: markRaw(Box), iconColor: '#909399', route: '/pharmacymanagement' },
|
||||||
{ key: 'statistic', label: '数据统计', icon: TrendCharts, iconColor: '#409eff', route: '/monitor' },
|
{ key: 'statistic', label: '数据统计', icon: markRaw(TrendCharts), iconColor: '#409eff', route: '/monitor' },
|
||||||
{ key: 'invoice', label: '发票管理', icon: Files, iconColor: '#67c23a', route: '/basicmanage/InvoiceManagement' },
|
{ key: 'invoice', label: '发票管理', icon: markRaw(Files), iconColor: '#67c23a', route: '/basicmanage/InvoiceManagement' },
|
||||||
{ key: 'system', label: '系统设置', icon: Setting, iconColor: '#909399', route: '/system' }
|
{ key: 'system', label: '系统设置', icon: markRaw(Setting), iconColor: '#909399', route: '/system' }
|
||||||
],
|
],
|
||||||
doctor: [
|
doctor: [
|
||||||
{ key: 'outpatient', label: '门诊接诊', icon: ChatDotRound, iconColor: '#409eff', route: '/doctorstation' },
|
{ key: 'outpatient', label: '门诊接诊', icon: markRaw(ChatDotRound), iconColor: '#409eff', route: '/doctorstation' },
|
||||||
{ key: 'emr', label: '病历管理', icon: Document, iconColor: '#67c23a', route: '/doctorstation/doctorphrase' },
|
{ key: 'emr', label: '病历管理', icon: markRaw(Document), iconColor: '#67c23a', route: '/doctorstation/doctorphrase' },
|
||||||
{ key: 'prescription', label: '开立处方', icon: Box, iconColor: '#e6a23c', route: '/clinicmanagement/ePrescribing' },
|
{ key: 'prescription', label: '开立处方', icon: markRaw(Box), iconColor: '#e6a23c', route: '/clinicmanagement/ePrescribing' },
|
||||||
{ key: 'history', label: '历史处方', icon: Clock, iconColor: '#f56c6c', route: '/clinicmanagement/historicalPrescription' },
|
{ key: 'history', label: '历史处方', icon: markRaw(Clock), iconColor: '#f56c6c', route: '/clinicmanagement/historicalPrescription' },
|
||||||
{ key: 'schedule', label: '排班管理', icon: Calendar, iconColor: '#909399', route: '/appoinmentmanage/deptManage' },
|
{ key: 'schedule', label: '排班管理', icon: markRaw(Calendar), iconColor: '#909399', route: '/appoinmentmanage/deptManage' },
|
||||||
{ key: 'inquiry', label: '患者查询', icon: Search, iconColor: '#409eff', route: '/patientmanagement' }
|
{ key: 'inquiry', label: '患者查询', icon: markRaw(Search), iconColor: '#409eff', route: '/patientmanagement' }
|
||||||
],
|
],
|
||||||
nurse: [
|
nurse: [
|
||||||
{ key: 'ward', label: '病房管理', icon: User, iconColor: '#409eff', route: '/inpatientNurse/inpatientNurseStation' },
|
{ key: 'ward', label: '病房管理', icon: markRaw(User), iconColor: '#409eff', route: '/inpatientNurse/inpatientNurseStation' },
|
||||||
{ key: 'execution', label: '医嘱执行', icon: Operation, iconColor: '#67c23a', route: '/inpatientNurse/medicalOrderExecution' },
|
{ key: 'execution', label: '医嘱执行', icon: markRaw(Operation), iconColor: '#67c23a', route: '/inpatientNurse/medicalOrderExecution' },
|
||||||
{ key: 'proofread', label: '医嘱核对', icon: Document, iconColor: '#e6a23c', route: '/inpatientNurse/medicalOrderProofread' },
|
{ key: 'proofread', label: '医嘱核对', icon: markRaw(Document), iconColor: '#e6a23c', route: '/inpatientNurse/medicalOrderProofread' },
|
||||||
{ key: 'drugCollect', label: '领药管理', icon: Box, iconColor: '#f56c6c', route: '/inpatientNurse/medicineCollect' },
|
{ key: 'drugCollect', label: '领药管理', icon: markRaw(Box), iconColor: '#f56c6c', route: '/inpatientNurse/medicineCollect' },
|
||||||
{ key: 'tpr', label: '体温单', icon: Monitor, iconColor: '#909399', route: '/inpatientNurse/tprsheet' },
|
{ key: 'tpr', label: '体温单', icon: markRaw(Monitor), iconColor: '#909399', route: '/inpatientNurse/tprsheet' },
|
||||||
{ key: 'nursing', label: '护理记录', icon: ChatDotRound, iconColor: '#409eff', route: '/inpatientNurse/nursingRecord' }
|
{ key: 'nursing', label: '护理记录', icon: markRaw(ChatDotRound), iconColor: '#409eff', route: '/inpatientNurse/nursingRecord' }
|
||||||
],
|
],
|
||||||
pharmacist: [
|
pharmacist: [
|
||||||
{ key: 'dispensing', label: '发药管理', icon: Box, iconColor: '#409eff', route: '/pharmacymanagement' },
|
{ key: 'dispensing', label: '发药管理', icon: markRaw(Box), iconColor: '#409eff', route: '/pharmacymanagement' },
|
||||||
{ key: 'prescription', label: '处方审核', icon: Document, iconColor: '#67c23a', route: '/pharmacymanagement' },
|
{ key: 'prescription', label: '处方审核', icon: markRaw(Document), iconColor: '#67c23a', route: '/pharmacymanagement' },
|
||||||
{ key: 'inventory', label: '库存管理', icon: Van, iconColor: '#e6a23c', route: '/medicineStorage' },
|
{ key: 'inventory', label: '库存管理', icon: markRaw(Van), iconColor: '#e6a23c', route: '/medicineStorage' },
|
||||||
{ key: 'purchase', label: '采购管理', icon: ShoppingCart, iconColor: '#f56c6c', route: '/medicineStorage' },
|
{ key: 'purchase', label: '采购管理', icon: markRaw(ShoppingCart), iconColor: '#f56c6c', route: '/medicineStorage' },
|
||||||
{ key: 'warning', label: '效期预警', icon: Warning, iconColor: '#f56c6c', route: '/medicationmanagement/statisticalManagement/statisticalManagement' },
|
{ key: 'warning', label: '效期预警', icon: markRaw(Warning), iconColor: '#f56c6c', route: '/medicationmanagement/statisticalManagement/statisticalManagement' },
|
||||||
{ key: 'statistics', label: '用药统计', icon: DataLine, iconColor: '#909399', route: '/monitor' }
|
{ key: 'statistics', label: '用药统计', icon: markRaw(DataLine), iconColor: '#909399', route: '/monitor' }
|
||||||
],
|
],
|
||||||
cashier: [
|
cashier: [
|
||||||
{ key: 'registration', label: '挂号收费', icon: Money, iconColor: '#409eff', route: '/charge/outpatientregistration' },
|
{ key: 'registration', label: '挂号收费', icon: markRaw(Money), iconColor: '#409eff', route: '/charge/outpatientregistration' },
|
||||||
{ key: 'clinicCharge', label: '门诊收费', icon: Wallet, iconColor: '#67c23a', route: '/charge/cliniccharge' },
|
{ key: 'clinicCharge', label: '门诊收费', icon: markRaw(Wallet), iconColor: '#67c23a', route: '/charge/cliniccharge' },
|
||||||
{ key: 'refund', label: '退费管理', icon: Document, iconColor: '#e6a23c', route: '/charge/clinicrefund' },
|
{ key: 'refund', label: '退费管理', icon: markRaw(Document), iconColor: '#e6a23c', route: '/charge/clinicrefund' },
|
||||||
{ key: 'invoice', label: '发票打印', icon: Files, iconColor: '#f56c6c', route: '/basicmanage/InvoiceManagement' },
|
{ key: 'invoice', label: '发票打印', icon: markRaw(Files), iconColor: '#f56c6c', route: '/basicmanage/InvoiceManagement' },
|
||||||
{ key: 'record', label: '收费记录', icon: Clock, iconColor: '#909399', route: '/charge/clinicRecord' },
|
{ key: 'record', label: '收费记录', icon: markRaw(Clock), iconColor: '#909399', route: '/charge/clinicRecord' },
|
||||||
{ key: 'insurance', label: '医保结算', icon: Bell, iconColor: '#409eff', route: '/ybmanagement' }
|
{ key: 'insurance', label: '医保结算', icon: markRaw(Bell), iconColor: '#409eff', route: '/ybmanagement' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 待办事项
|
// 待办事项
|
||||||
const todoList = ref([
|
const todoList = ref([
|
||||||
{ id: 1, title: '审核处方申请', desc: '张医生提交的5条处方待审核', priority: 'high', icon: Document, time: '10分钟前' },
|
{ id: 1, title: '审核处方申请', desc: '张医生提交的5条处方待审核', priority: 'high', icon: markRaw(Document), time: '10分钟前' },
|
||||||
{ id: 2, title: '确认患者入院', desc: '李某某(男,45岁)已办理入院', priority: 'medium', icon: User, time: '30分钟前' },
|
{ id: 2, title: '确认患者入院', desc: '李某某(男,45岁)已办理入院', priority: 'medium', icon: markRaw(User), time: '30分钟前' },
|
||||||
{ id: 3, title: '处理投诉反馈', desc: '患者家属对服务态度的投诉', priority: 'high', icon: ChatDotRound, time: '1小时前' },
|
{ id: 3, title: '处理投诉反馈', desc: '患者家属对服务态度的投诉', priority: 'high', icon: markRaw(ChatDotRound), time: '1小时前' },
|
||||||
{ id: 4, title: '药品效期预警', desc: '阿莫西林等3种药品即将过期', priority: 'low', icon: Warning, time: '2小时前' },
|
{ id: 4, title: '药品效期预警', desc: '阿莫西林等3种药品即将过期', priority: 'low', icon: markRaw(Warning), time: '2小时前' },
|
||||||
{ id: 5, title: '月度报表审核', desc: '11月份门诊收入报表待审核', priority: 'medium', icon: Files, time: '3小时前' }
|
{ id: 5, title: '月度报表审核', desc: '11月份门诊收入报表待审核', priority: 'medium', icon: markRaw(Files), time: '3小时前' }
|
||||||
])
|
])
|
||||||
|
|
||||||
// 今日日程
|
// 今日日程
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ import {
|
|||||||
} from '../api';
|
} from '../api';
|
||||||
import adviceBaseList from '../adviceBaseList';
|
import adviceBaseList from '../adviceBaseList';
|
||||||
import {calculateQuantityByDays} from '@/utils/his';
|
import {calculateQuantityByDays} from '@/utils/his';
|
||||||
import {patientInfo} from '../../store/patient.js';
|
import {localPatientInfo as patientInfo} from '../../store/localPatient.js';
|
||||||
import OrderGroupDrawer from '@/views/doctorstation/components/prescription/orderGroupDrawer.vue';
|
import OrderGroupDrawer from '@/views/doctorstation/components/prescription/orderGroupDrawer.vue';
|
||||||
import PrescriptionHistory from '@/views/doctorstation/components/prescription/prescriptionHistory.vue';
|
import PrescriptionHistory from '@/views/doctorstation/components/prescription/prescriptionHistory.vue';
|
||||||
import Decimal from 'decimal.js';
|
import Decimal from 'decimal.js';
|
||||||
|
|||||||
@@ -72,3 +72,12 @@ export function updateTemplate(data) {
|
|||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除模板
|
||||||
|
export function deleteTemplate(ids) {
|
||||||
|
return request({
|
||||||
|
url: '/document/template/delete',
|
||||||
|
method: 'delete',
|
||||||
|
data: ids,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import {defineEmits, nextTick, ref, unref} from 'vue';
|
|||||||
import {deleteRecord, getRecordByEncounterIdList} from '../api';
|
import {deleteRecord, getRecordByEncounterIdList} from '../api';
|
||||||
import {ElMessage} from 'element-plus';
|
import {ElMessage} from 'element-plus';
|
||||||
import {Delete} from '@element-plus/icons-vue';
|
import {Delete} from '@element-plus/icons-vue';
|
||||||
import {patientInfo} from '../../store/patient.js';
|
import {localPatientInfo as patientInfo} from '../../store/localPatient.js';
|
||||||
|
|
||||||
const emits = defineEmits(['historyClick']);
|
const emits = defineEmits(['historyClick']);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|||||||
@@ -26,8 +26,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {defineEmits, ref, unref} from 'vue';
|
import {defineEmits, ref, unref, watch} from 'vue';
|
||||||
import {getListByDefinitionId} from '../api';
|
import {getListByDefinitionId, deleteTemplate} from '../api';
|
||||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||||
import {Edit} from '@element-plus/icons-vue';
|
import {Edit} from '@element-plus/icons-vue';
|
||||||
|
|
||||||
@@ -46,16 +46,33 @@ const defaultProps = {
|
|||||||
children: 'children',
|
children: 'children',
|
||||||
label: 'name',
|
label: 'name',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 缓存已加载的模板数据
|
||||||
|
const templateCache = new Map();
|
||||||
const queryParams = ref({
|
const queryParams = ref({
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
isPage: 0,
|
isPage: 0,
|
||||||
});
|
});
|
||||||
const templateData = ref([]);
|
const templateData = ref([]);
|
||||||
|
|
||||||
|
// 防抖定时器
|
||||||
|
let debounceTimer = null;
|
||||||
|
|
||||||
const queryList = async () => {
|
const queryList = async () => {
|
||||||
try {
|
try {
|
||||||
if (unref(definitionId) && unref(definitionId) !== '') {
|
const id = unref(definitionId);
|
||||||
const res = await getListByDefinitionId(unref(definitionId));
|
if (id && id !== '') {
|
||||||
templateData.value = res.data || [];
|
// 检查缓存中是否存在数据
|
||||||
|
if (templateCache.has(id)) {
|
||||||
|
templateData.value = templateCache.get(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getListByDefinitionId(id);
|
||||||
|
const data = res.data || [];
|
||||||
|
// 将数据存入缓存
|
||||||
|
templateCache.set(id, data);
|
||||||
|
templateData.value = data;
|
||||||
} else {
|
} else {
|
||||||
templateData.value = [];
|
templateData.value = [];
|
||||||
}
|
}
|
||||||
@@ -64,6 +81,23 @@ const queryList = async () => {
|
|||||||
templateData.value = [];
|
templateData.value = [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 防抖版本的查询函数
|
||||||
|
const debouncedQueryList = async () => {
|
||||||
|
if (debounceTimer) {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
debounceTimer = setTimeout(async () => {
|
||||||
|
await queryList();
|
||||||
|
}, 300); // 300ms 防抖延迟
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听 definitionId 变化,使用防抖
|
||||||
|
watch(definitionId, () => {
|
||||||
|
debouncedQueryList();
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
const handleNodeClick = (data) => {
|
const handleNodeClick = (data) => {
|
||||||
emits('templateClick', data);
|
emits('templateClick', data);
|
||||||
};
|
};
|
||||||
@@ -81,6 +115,8 @@ const handleDelete = async (item) => {
|
|||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
await deleteTemplate(item.id);
|
await deleteTemplate(item.id);
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
|
// 清除缓存中的数据,强制重新加载
|
||||||
|
templateCache.delete(unref(definitionId));
|
||||||
queryList();
|
queryList();
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ import {nextTick, onMounted, reactive, ref, watch} from 'vue';
|
|||||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||||
import {getTreeList} from '@/views/basicmanage/caseTemplates/api';
|
import {getTreeList} from '@/views/basicmanage/caseTemplates/api';
|
||||||
import {addTemplate, getRecordByEncounterIdList, saveOrUpdateRecord} from './api';
|
import {addTemplate, getRecordByEncounterIdList, saveOrUpdateRecord} from './api';
|
||||||
import {patientInfo} from '../store/patient.js';
|
import {localPatientInfo as patientInfo} from '../store/localPatient.js';
|
||||||
import NursingStatus from '@/views/inpatientDoctor/home/components/applicationShow/nursingStatus.vue';
|
import NursingStatus from '@/views/inpatientDoctor/home/components/applicationShow/nursingStatus.vue';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
// 打印工具
|
// 打印工具
|
||||||
@@ -148,9 +148,18 @@ const emrComponentRef = ref(null);
|
|||||||
const quicklyactiveName = ref('history');
|
const quicklyactiveName = ref('history');
|
||||||
const leftShow = ref(true);
|
const leftShow = ref(true);
|
||||||
const rightShow = ref(true);
|
const rightShow = ref(true);
|
||||||
|
// 使用防抖处理历史记录和模板列表的刷新
|
||||||
|
let listRefreshDebounceTimer = null;
|
||||||
watch(patientInfo, () => {
|
watch(patientInfo, () => {
|
||||||
|
if (listRefreshDebounceTimer) {
|
||||||
|
clearTimeout(listRefreshDebounceTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
listRefreshDebounceTimer = setTimeout(() => {
|
||||||
historyRef.value?.queryList();
|
historyRef.value?.queryList();
|
||||||
templateRef.value?.queryList();
|
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||||
|
// templateRef.value?.queryList();
|
||||||
|
}, 150); // 稍微延后刷新,避免频繁更新
|
||||||
});
|
});
|
||||||
const templateTree = ref(null);
|
const templateTree = ref(null);
|
||||||
|
|
||||||
@@ -185,8 +194,29 @@ const handleNodeClick = (data, node) => {
|
|||||||
if (node.isLeaf) {
|
if (node.isLeaf) {
|
||||||
// 存储当前节点数据
|
// 存储当前节点数据
|
||||||
currentSelectTemplate.value = data.document;
|
currentSelectTemplate.value = data.document;
|
||||||
|
|
||||||
|
// 在切换组件前先重置表单数据,避免显示之前的数据
|
||||||
|
editForm.value = {
|
||||||
|
id: '',
|
||||||
|
definitionId: '',
|
||||||
|
definitionBusNo: '',
|
||||||
|
contentJson: '',
|
||||||
|
statusEnum: 1,
|
||||||
|
organizationId: 0,
|
||||||
|
encounterId: '',
|
||||||
|
patientId: '',
|
||||||
|
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
createBy: '',
|
||||||
|
source: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 先清空当前组件,再设置新组件,确保组件完全重新渲染
|
||||||
|
currentComponent.value = '';
|
||||||
|
|
||||||
|
// 使用 nextTick 确保 DOM 更新后再设置新组件
|
||||||
|
nextTick(() => {
|
||||||
currentComponent.value = currentSelectTemplate.value.vueRouter || '';
|
currentComponent.value = currentSelectTemplate.value.vueRouter || '';
|
||||||
// currentComponent.value = data.document.vueRouter || '';
|
});
|
||||||
} else {
|
} else {
|
||||||
currentSelectTemplate.value = {
|
currentSelectTemplate.value = {
|
||||||
id: '',
|
id: '',
|
||||||
@@ -198,7 +228,8 @@ const handleNodeClick = (data, node) => {
|
|||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
historyRef.value?.queryList();
|
historyRef.value?.queryList();
|
||||||
templateRef.value?.queryList();
|
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||||
|
// templateRef.value?.queryList();
|
||||||
|
|
||||||
// 选择任何病历模板后,都加载该病历类型的最新历史记录
|
// 选择任何病历模板后,都加载该病历类型的最新历史记录
|
||||||
if (node.isLeaf && patientInfo.value && patientInfo.value.patientId) {
|
if (node.isLeaf && patientInfo.value && patientInfo.value.patientId) {
|
||||||
@@ -270,7 +301,8 @@ const handleSubmitOk = async (data) => {
|
|||||||
|
|
||||||
// 刷新历史记录列表
|
// 刷新历史记录列表
|
||||||
historyRef.value?.queryList();
|
historyRef.value?.queryList();
|
||||||
templateRef.value?.queryList();
|
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||||
|
// templateRef.value?.queryList();
|
||||||
|
|
||||||
// 等待历史记录列表更新后,重新加载最新病历并更新选中状态
|
// 等待历史记录列表更新后,重新加载最新病历并更新选中状态
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -429,7 +461,8 @@ const print = async () => {
|
|||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
queryTemplateTree();
|
queryTemplateTree();
|
||||||
historyRef.value?.queryList();
|
historyRef.value?.queryList();
|
||||||
templateRef.value?.queryList();
|
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||||
|
// templateRef.value?.queryList();
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteEmr = async () => {
|
const deleteEmr = async () => {
|
||||||
@@ -522,7 +555,7 @@ const selectOutpatientMedicalRecordTemplate = async () => {
|
|||||||
|
|
||||||
// 加载最新的病历数据并回显
|
// 加载最新的病历数据并回显
|
||||||
const loadLatestMedicalRecord = async () => {
|
const loadLatestMedicalRecord = async () => {
|
||||||
if (!patientInfo.value.encounterId || !currentSelectTemplate.value.id) return;
|
if (!patientInfo.value?.encounterId || !currentSelectTemplate.value.id) return;
|
||||||
editForm.value.id = '';
|
editForm.value.id = '';
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
@@ -546,7 +579,17 @@ const loadLatestMedicalRecord = async () => {
|
|||||||
editForm.value = latestRecord;
|
editForm.value = latestRecord;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (emrComponentRef.value && latestRecord.contentJson) {
|
if (emrComponentRef.value && latestRecord.contentJson) {
|
||||||
emrComponentRef.value.setFormData(JSON.parse(latestRecord.contentJson));
|
try {
|
||||||
|
const parsedData = JSON.parse(latestRecord.contentJson);
|
||||||
|
emrComponentRef.value.setFormData(parsedData);
|
||||||
|
} catch (parseError) {
|
||||||
|
console.error('解析病历数据失败:', parseError);
|
||||||
|
// 解析失败时仍然尝试设置空数据以清空之前的残留数据
|
||||||
|
emrComponentRef.value.setFormData({});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果没有内容数据,也要清空组件中的数据
|
||||||
|
emrComponentRef.value.setFormData({});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通知History组件更新选中状态
|
// 通知History组件更新选中状态
|
||||||
@@ -557,16 +600,52 @@ const loadLatestMedicalRecord = async () => {
|
|||||||
} else {
|
} else {
|
||||||
// 清空选中状态
|
// 清空选中状态
|
||||||
selectedHistoryRecordId.value = '';
|
selectedHistoryRecordId.value = '';
|
||||||
// 病案首页切换晴空逻辑
|
// 当没有历史记录时,也要清空当前表单数据,避免显示之前患者的数据
|
||||||
emrComponentRef.value.setFormData?.({});
|
editForm.value = {
|
||||||
|
id: '',
|
||||||
|
definitionId: '',
|
||||||
|
definitionBusNo: '',
|
||||||
|
contentJson: '',
|
||||||
|
statusEnum: 1,
|
||||||
|
organizationId: 0,
|
||||||
|
encounterId: '',
|
||||||
|
patientId: '',
|
||||||
|
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
createBy: '',
|
||||||
|
source: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
if (emrComponentRef.value) {
|
||||||
|
emrComponentRef.value.setFormData({});
|
||||||
|
}
|
||||||
|
});
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('加载最新病历数据失败=====>', error);
|
ElMessage.error('加载最新病历数据失败=====>', error);
|
||||||
// 出错时也清空选中状态
|
// 出错时也清空选中状态
|
||||||
selectedHistoryRecordId.value = '';
|
selectedHistoryRecordId.value = '';
|
||||||
// 病案首页切换晴空逻辑
|
// 出错时也要清空表单数据,避免显示之前患者的数据
|
||||||
emrComponentRef.value.setFormData?.({});
|
editForm.value = {
|
||||||
|
id: '',
|
||||||
|
definitionId: '',
|
||||||
|
definitionBusNo: '',
|
||||||
|
contentJson: '',
|
||||||
|
statusEnum: 1,
|
||||||
|
organizationId: 0,
|
||||||
|
encounterId: '',
|
||||||
|
patientId: '',
|
||||||
|
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
createBy: '',
|
||||||
|
source: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
if (emrComponentRef.value) {
|
||||||
|
emrComponentRef.value.setFormData({});
|
||||||
|
}
|
||||||
|
});
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@@ -672,6 +751,7 @@ const templateEditSubmitOk = async () => {
|
|||||||
ElMessage.success('模板新增成功');
|
ElMessage.success('模板新增成功');
|
||||||
// 刷新模板列表
|
// 刷新模板列表
|
||||||
if (templateRef.value && typeof templateRef.value.queryList === 'function') {
|
if (templateRef.value && typeof templateRef.value.queryList === 'function') {
|
||||||
|
// 在模板操作后,需要清除缓存并重新加载
|
||||||
templateRef.value.queryList();
|
templateRef.value.queryList();
|
||||||
}
|
}
|
||||||
// 关闭模板编辑弹窗
|
// 关闭模板编辑弹窗
|
||||||
@@ -703,7 +783,8 @@ const templateEditSubmitOk = async () => {
|
|||||||
} finally {
|
} finally {
|
||||||
// 无论成功失败都刷新列表
|
// 无论成功失败都刷新列表
|
||||||
historyRef.value?.queryList();
|
historyRef.value?.queryList();
|
||||||
templateRef.value?.queryList();
|
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||||
|
// templateRef.value?.queryList();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// onBeforeMount(() => {});
|
// onBeforeMount(() => {});
|
||||||
@@ -726,6 +807,29 @@ watch(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 如果没有患者信息,也要重置组件和表单数据
|
||||||
|
currentComponent.value = '';
|
||||||
|
editForm.value = {
|
||||||
|
id: '',
|
||||||
|
definitionId: '',
|
||||||
|
definitionBusNo: '',
|
||||||
|
contentJson: '',
|
||||||
|
statusEnum: 1,
|
||||||
|
organizationId: 0,
|
||||||
|
encounterId: '',
|
||||||
|
patientId: '',
|
||||||
|
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
createBy: '',
|
||||||
|
source: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 如果有动态组件实例,也需要重置其表单数据
|
||||||
|
nextTick(() => {
|
||||||
|
if (emrComponentRef.value && emrComponentRef.value.setFormData) {
|
||||||
|
emrComponentRef.value.setFormData({});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: true }
|
{ deep: true, immediate: true }
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import {computed, onBeforeMount, onMounted, provide, reactive, ref, watch,} from
|
|||||||
import Emr from './emr/index.vue';
|
import Emr from './emr/index.vue';
|
||||||
import inPatientBarDoctorFold from '@/components/patientBar/inPatientBarDoctorFold.vue';
|
import inPatientBarDoctorFold from '@/components/patientBar/inPatientBarDoctorFold.vue';
|
||||||
import PatientList from '@/components/PatientList/patient-list.vue';
|
import PatientList from '@/components/PatientList/patient-list.vue';
|
||||||
|
import {localPatientInfo, updateLocalPatientInfo} from './store/localPatient';
|
||||||
import {patientInfo, updatePatientInfo} from './store/patient';
|
import {patientInfo, updatePatientInfo} from './store/patient';
|
||||||
import {getPatientList} from './components/api';
|
import {getPatientList} from './components/api';
|
||||||
import {
|
import {
|
||||||
@@ -121,21 +122,40 @@ watch(
|
|||||||
) {
|
) {
|
||||||
const firstPatient = newData[0];
|
const firstPatient = newData[0];
|
||||||
if (firstPatient?.encounterId) {
|
if (firstPatient?.encounterId) {
|
||||||
|
// 使用防抖处理默认选择
|
||||||
|
if (debounceTimer) {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
debounceTimer = setTimeout(() => {
|
||||||
handleItemClick(firstPatient);
|
handleItemClick(firstPatient);
|
||||||
isFirstLoad.value = false;
|
isFirstLoad.value = false;
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 防抖函数,防止快速点击导致状态冲突
|
||||||
|
let debounceTimer = null;
|
||||||
const handleItemClick = (node) => {
|
const handleItemClick = (node) => {
|
||||||
|
// 清除之前的计时器
|
||||||
|
if (debounceTimer) {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置新的计时器
|
||||||
|
debounceTimer = setTimeout(() => {
|
||||||
cardId.value = node.encounterId;
|
cardId.value = node.encounterId;
|
||||||
|
// 同时更新本地和全局状态,确保模块内组件和跨模块组件都能正确响应
|
||||||
updatePatientInfo(node);
|
updatePatientInfo(node);
|
||||||
|
updateLocalPatientInfo(node);
|
||||||
|
|
||||||
diagnosisRef.value?.getList();
|
diagnosisRef.value?.getList();
|
||||||
adviceRef.value?.getListInfo();
|
adviceRef.value?.getListInfo();
|
||||||
adviceRef.value?.getDiagnosisInfo();
|
adviceRef.value?.getDiagnosisInfo();
|
||||||
|
}, 100); // 100ms 防抖延迟
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearch = (keyword) => {
|
const handleSearch = (keyword) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user