Compare commits
5 Commits
2eec988c56
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3d011951b | ||
| 7dc76d7b59 | |||
| b2dec2667a | |||
|
|
879d31b51d | ||
|
|
473a5f7f06 |
@@ -353,8 +353,6 @@ public class DoctorStationDiagnosisAppServiceImpl implements IDoctorStationDiagn
|
|||||||
encounterDiagnosis.setLongTermFlag(saveDiagnosisChildParam.getLongTermFlag());
|
encounterDiagnosis.setLongTermFlag(saveDiagnosisChildParam.getLongTermFlag());
|
||||||
encounterDiagnosis.setOnsetDate(saveDiagnosisChildParam.getOnsetDate());
|
encounterDiagnosis.setOnsetDate(saveDiagnosisChildParam.getOnsetDate());
|
||||||
encounterDiagnosis.setDiagnosisTime(saveDiagnosisChildParam.getDiagnosisTime());
|
encounterDiagnosis.setDiagnosisTime(saveDiagnosisChildParam.getDiagnosisTime());
|
||||||
encounterDiagnosis.setOnsetDate(saveDiagnosisChildParam.getOnsetDate());
|
|
||||||
encounterDiagnosis.setDiagnosisTime(saveDiagnosisChildParam.getDiagnosisTime());
|
|
||||||
if(encounterDiagnosis.getCreateBy() == null){
|
if(encounterDiagnosis.getCreateBy() == null){
|
||||||
encounterDiagnosis.setCreateBy(username);
|
encounterDiagnosis.setCreateBy(username);
|
||||||
}
|
}
|
||||||
@@ -383,8 +381,6 @@ public class DoctorStationDiagnosisAppServiceImpl implements IDoctorStationDiagn
|
|||||||
encounterDiagnosis.setLongTermFlag(saveDiagnosisChildParam.getLongTermFlag());
|
encounterDiagnosis.setLongTermFlag(saveDiagnosisChildParam.getLongTermFlag());
|
||||||
encounterDiagnosis.setOnsetDate(saveDiagnosisChildParam.getOnsetDate());
|
encounterDiagnosis.setOnsetDate(saveDiagnosisChildParam.getOnsetDate());
|
||||||
encounterDiagnosis.setDiagnosisTime(saveDiagnosisChildParam.getDiagnosisTime());
|
encounterDiagnosis.setDiagnosisTime(saveDiagnosisChildParam.getDiagnosisTime());
|
||||||
encounterDiagnosis.setOnsetDate(saveDiagnosisChildParam.getOnsetDate());
|
|
||||||
encounterDiagnosis.setDiagnosisTime(saveDiagnosisChildParam.getDiagnosisTime());
|
|
||||||
if(encounterDiagnosis.getCreateBy() == null){
|
if(encounterDiagnosis.getCreateBy() == null){
|
||||||
encounterDiagnosis.setCreateBy(username);
|
encounterDiagnosis.setCreateBy(username);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,15 +245,37 @@ public class DocDefinitionAppServiceImpl implements IDocDefinitionAppService {
|
|||||||
public R<?> getTreeList(DocDefinitonParam param) {
|
public R<?> getTreeList(DocDefinitonParam param) {
|
||||||
// 1. 获取当前登录用户的医院ID(避免跨医院查询)
|
// 1. 获取当前登录用户的医院ID(避免跨医院查询)
|
||||||
Long hospitalId = SecurityUtils.getLoginUser().getHospitalId();
|
Long hospitalId = SecurityUtils.getLoginUser().getHospitalId();
|
||||||
|
Long organizationId = param.getOrganizationId();
|
||||||
|
List<Integer> useRanges = param.getUseRanges();
|
||||||
|
|
||||||
|
log.info("获取文书定义树形列表 - 请求参数: hospitalId={}, organizationId={}, useRanges={}, name={}, primaryMenuEnum={}",
|
||||||
|
hospitalId, organizationId, useRanges, param.getName(), param.getPrimaryMenuEnum());
|
||||||
|
|
||||||
if (hospitalId == null) {
|
if (hospitalId == null) {
|
||||||
log.warn("当前登录用户未关联医院ID,将使用默认值");
|
log.warn("当前登录用户未关联医院ID,将使用默认值");
|
||||||
// 设置默认医院ID为1(或其他合适的默认值)
|
// 设置默认医院ID为1(或其他合适的默认值)
|
||||||
hospitalId = 1L;
|
hospitalId = 1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (organizationId == null || organizationId == 0) {
|
||||||
|
log.warn("organizationId为空或0,将跳过医院过滤和使用范围过滤");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useRanges == null || useRanges.isEmpty()) {
|
||||||
|
log.warn("useRanges为空,可能返回所有使用范围的文书");
|
||||||
|
}
|
||||||
|
|
||||||
// 2. 数据库查询文书定义列表
|
// 2. 数据库查询文书定义列表
|
||||||
List<DocDefinitionDto> docList = docDefinitionAppMapper.getDefinationList(param.getUseRanges(),
|
List<DocDefinitionDto> docList = docDefinitionAppMapper.getDefinationList(useRanges,
|
||||||
param.getOrganizationId(), hospitalId, param.getName(), param.getPrimaryMenuEnum());
|
organizationId, hospitalId, param.getName(), param.getPrimaryMenuEnum());
|
||||||
|
|
||||||
|
log.info("获取文书定义树形列表 - 查询结果: 记录数={}", docList != null ? docList.size() : 0);
|
||||||
|
if (docList != null && !docList.isEmpty()) {
|
||||||
|
for (DocDefinitionDto doc : docList) {
|
||||||
|
log.debug("文书: id={}, name={}, useRangeEnum={}, hospitalId={}",
|
||||||
|
doc.getId(), doc.getName(), doc.getUseRangeEnum(), doc.getHospitalId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 3. 构建树形结构(空列表时返回空树,避免空指针)
|
// 3. 构建树形结构(空列表时返回空树,避免空指针)
|
||||||
List<DirectoryNode> treeNodes = new ArrayList<>();
|
List<DirectoryNode> treeNodes = new ArrayList<>();
|
||||||
|
|||||||
@@ -62,10 +62,10 @@ public class OutpatientInfusionAppServiceImpl implements IOutpatientInfusionAppS
|
|||||||
OutpatientStationInitDto initDto = new OutpatientStationInitDto();
|
OutpatientStationInitDto initDto = new OutpatientStationInitDto();
|
||||||
// 执行状态
|
// 执行状态
|
||||||
List<OutpatientStationInitDto.ServiceStatus> serviceStatusOptions = new ArrayList<>();
|
List<OutpatientStationInitDto.ServiceStatus> serviceStatusOptions = new ArrayList<>();
|
||||||
|
serviceStatusOptions.add(new OutpatientStationInitDto.ServiceStatus(RequestStatus.ACTIVE.getValue(),
|
||||||
|
"待执行"));
|
||||||
serviceStatusOptions.add(new OutpatientStationInitDto.ServiceStatus(RequestStatus.COMPLETED.getValue(),
|
serviceStatusOptions.add(new OutpatientStationInitDto.ServiceStatus(RequestStatus.COMPLETED.getValue(),
|
||||||
RequestStatus.COMPLETED.getInfo()));
|
RequestStatus.COMPLETED.getInfo()));
|
||||||
// serviceStatusOptions.add(new OutpatientStationInitDto.ServiceStatus(RequestStatus.IN_PROGRESS.getValue(),
|
|
||||||
// RequestStatus.IN_PROGRESS.getInfo()));
|
|
||||||
serviceStatusOptions.add(new OutpatientStationInitDto.ServiceStatus(RequestStatus.CANCELLED.getValue(),
|
serviceStatusOptions.add(new OutpatientStationInitDto.ServiceStatus(RequestStatus.CANCELLED.getValue(),
|
||||||
RequestStatus.CANCELLED.getInfo()));
|
RequestStatus.CANCELLED.getInfo()));
|
||||||
initDto.setServiceStatusOptions(serviceStatusOptions);
|
initDto.setServiceStatusOptions(serviceStatusOptions);
|
||||||
|
|||||||
@@ -622,6 +622,37 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!medicationRequestIdList.isEmpty()) {
|
if (!medicationRequestIdList.isEmpty()) {
|
||||||
|
// 获取药品请求信息,为输液类药品生成服务请求
|
||||||
|
List<MedicationRequest> medicationRequests = medicationRequestService.listByIds(medicationRequestIdList);
|
||||||
|
|
||||||
|
// 为输液类药品生成 wor_service_request 记录
|
||||||
|
for (MedicationRequest medReq : medicationRequests) {
|
||||||
|
if (medReq.getInfusionFlag() != null && medReq.getInfusionFlag() == 1) {
|
||||||
|
ServiceRequest serviceRequest = new ServiceRequest();
|
||||||
|
serviceRequest.setBasedOnId(medReq.getId())
|
||||||
|
.setBasedOnTable(CommonConstants.TableName.MED_MEDICATION_REQUEST)
|
||||||
|
.setEncounterId(medReq.getEncounterId())
|
||||||
|
.setPatientId(medReq.getPatientId())
|
||||||
|
.setActivityId(medReq.getMedicationId())
|
||||||
|
.setStatusEnum(RequestStatus.ACTIVE.getValue()) // 状态设为已发送 (2),这样门诊输液页面才能查到
|
||||||
|
.setGroupId(medReq.getGroupId())
|
||||||
|
.setOrgId(medReq.getOrgId())
|
||||||
|
.setRequesterId(medReq.getPractitionerId())
|
||||||
|
.setAuthoredTime(new Date())
|
||||||
|
.setEncounterDiagnosisId(medReq.getEncounterDiagnosisId())
|
||||||
|
.setConditionId(medReq.getConditionId())
|
||||||
|
.setQuantity(medReq.getQuantity())
|
||||||
|
.setUnitCode(medReq.getUnitCode())
|
||||||
|
.setPriorityEnum(medReq.getPriorityEnum())
|
||||||
|
.setPerformFlag(Whether.NO.getValue())
|
||||||
|
.setIntentEnum(medReq.getIntentEnum())
|
||||||
|
.setCategoryEnum(medReq.getCategoryEnum())
|
||||||
|
.setYbClassEnum(medReq.getYbClassEnum())
|
||||||
|
.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4));
|
||||||
|
serviceRequestService.save(serviceRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 更新请求状态为已完成
|
// 更新请求状态为已完成
|
||||||
medicationRequestService.updateCompletedStatusBatch(medicationRequestIdList, null, null);
|
medicationRequestService.updateCompletedStatusBatch(medicationRequestIdList, null, null);
|
||||||
// 更新药品发放状态为待配药
|
// 更新药品发放状态为待配药
|
||||||
|
|||||||
@@ -236,6 +236,11 @@ public class WesternMedicineDispenseAppServiceImpl implements IWesternMedicineDi
|
|||||||
EnumUtils.getInfoByValue(DispenseStatus.class, medicineDispenseOrder.getStatusEnum()));
|
EnumUtils.getInfoByValue(DispenseStatus.class, medicineDispenseOrder.getStatusEnum()));
|
||||||
// 设置所在表名
|
// 设置所在表名
|
||||||
medicineDispenseOrder.setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION);
|
medicineDispenseOrder.setItemTable(CommonConstants.TableName.MED_MEDICATION_DEFINITION);
|
||||||
|
// 处方类型(发药类型:门诊/住院等)
|
||||||
|
if (medicineDispenseOrder.getDispenseEnum() != null) {
|
||||||
|
medicineDispenseOrder.setDispenseEnum_enumText(
|
||||||
|
EnumUtils.getInfoByValue(EncounterClass.class, medicineDispenseOrder.getDispenseEnum()));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return R.ok(medicineDispenseOrderPage);
|
return R.ok(medicineDispenseOrderPage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,6 +271,12 @@ public class ItemDispenseOrderDto {
|
|||||||
private String medTypeCode;
|
private String medTypeCode;
|
||||||
private String medTypeCode_dictText;
|
private String medTypeCode_dictText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发药类型(处方类型:门诊/住院等)
|
||||||
|
*/
|
||||||
|
private Integer dispenseEnum;
|
||||||
|
private String dispenseEnum_enumText;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输液标志
|
* 输液标志
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,9 +29,12 @@ import com.openhis.web.regdoctorstation.appservice.IAdviceManageAppService;
|
|||||||
import com.openhis.web.regdoctorstation.dto.*;
|
import com.openhis.web.regdoctorstation.dto.*;
|
||||||
import com.openhis.web.regdoctorstation.mapper.AdviceManageAppMapper;
|
import com.openhis.web.regdoctorstation.mapper.AdviceManageAppMapper;
|
||||||
import com.openhis.web.regdoctorstation.utils.RegPrescriptionUtils;
|
import com.openhis.web.regdoctorstation.utils.RegPrescriptionUtils;
|
||||||
import com.openhis.workflow.domain.ActivityDefinition;
|
import com.openhis.workflow.domain.DeviceRequest;
|
||||||
import com.openhis.workflow.domain.ServiceRequest;
|
import com.openhis.workflow.domain.ServiceRequest;
|
||||||
import com.openhis.workflow.service.IActivityDefinitionService;
|
import com.openhis.workflow.service.IActivityDefinitionService;
|
||||||
|
import com.openhis.workflow.domain.ActivityDefinition;
|
||||||
|
import com.openhis.workflow.service.IDeviceDispenseService;
|
||||||
|
import com.openhis.workflow.service.IDeviceRequestService;
|
||||||
import com.openhis.workflow.service.IServiceRequestService;
|
import com.openhis.workflow.service.IServiceRequestService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -76,6 +79,12 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
|||||||
@Resource
|
@Resource
|
||||||
IActivityDefinitionService iActivityDefinitionService;
|
IActivityDefinitionService iActivityDefinitionService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
IDeviceRequestService iDeviceRequestService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
IDeviceDispenseService iDeviceDispenseService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询住院患者信息
|
* 查询住院患者信息
|
||||||
*
|
*
|
||||||
@@ -174,6 +183,9 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
|||||||
// 诊疗活动
|
// 诊疗活动
|
||||||
List<RegAdviceSaveDto> activityList = regAdviceSaveList.stream()
|
List<RegAdviceSaveDto> activityList = regAdviceSaveList.stream()
|
||||||
.filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
|
.filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
|
||||||
|
// 耗材 🔧 Bug #147 修复
|
||||||
|
List<RegAdviceSaveDto> deviceList = regAdviceSaveList.stream()
|
||||||
|
.filter(e -> ItemType.DEVICE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
|
||||||
|
|
||||||
// 保存时,校验临时医嘱库存
|
// 保存时,校验临时医嘱库存
|
||||||
if (AdviceOpType.SAVE_ADVICE.getCode().equals(adviceOpType)) {
|
if (AdviceOpType.SAVE_ADVICE.getCode().equals(adviceOpType)) {
|
||||||
@@ -210,6 +222,11 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
|||||||
*/
|
*/
|
||||||
this.handService(activityList, startTime, authoredTime, curDate, adviceOpType, organizationId, signCode);
|
this.handService(activityList, startTime, authoredTime, curDate, adviceOpType, organizationId, signCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 🔧 Bug #147 修复:处理耗材请求
|
||||||
|
*/
|
||||||
|
this.handDevice(deviceList, startTime, authoredTime, curDate, adviceOpType, organizationId, signCode);
|
||||||
|
|
||||||
// 签发时,把草稿状态的账单更新为待收费
|
// 签发时,把草稿状态的账单更新为待收费
|
||||||
if (AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType) && !regAdviceSaveList.isEmpty()) {
|
if (AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType) && !regAdviceSaveList.isEmpty()) {
|
||||||
// 签发的医嘱id集合
|
// 签发的医嘱id集合
|
||||||
@@ -594,6 +611,150 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 🔧 Bug #147 修复:处理耗材
|
||||||
|
*/
|
||||||
|
private void handDevice(List<RegAdviceSaveDto> deviceList, Date startTime, Date authoredTime, Date curDate,
|
||||||
|
String adviceOpType, Long organizationId, String signCode) {
|
||||||
|
// 当前登录账号的科室id
|
||||||
|
Long orgId = SecurityUtils.getLoginUser().getOrgId();
|
||||||
|
// 获取当前登录用户的tenantId
|
||||||
|
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||||
|
// 保存操作
|
||||||
|
boolean is_save = AdviceOpType.SAVE_ADVICE.getCode().equals(adviceOpType);
|
||||||
|
// 签发操作
|
||||||
|
boolean is_sign = AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType);
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
List<RegAdviceSaveDto> deleteList = deviceList.stream()
|
||||||
|
.filter(e -> DbOpType.DELETE.getCode().equals(e.getDbOpType())).collect(Collectors.toList());
|
||||||
|
for (RegAdviceSaveDto regAdviceSaveDto : deleteList) {
|
||||||
|
iDeviceRequestService.removeById(regAdviceSaveDto.getRequestId());
|
||||||
|
// 删除已经产生的耗材发放信息
|
||||||
|
iDeviceDispenseService.deleteDeviceDispense(regAdviceSaveDto.getRequestId());
|
||||||
|
// 删除费用项
|
||||||
|
iChargeItemService.deleteByServiceTableAndId(CommonConstants.TableName.WOR_DEVICE_REQUEST,
|
||||||
|
regAdviceSaveDto.getRequestId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 声明耗材请求
|
||||||
|
DeviceRequest deviceRequest;
|
||||||
|
// 声明费用项
|
||||||
|
ChargeItem chargeItem;
|
||||||
|
|
||||||
|
// 新增 + 修改 (长期医嘱)
|
||||||
|
List<RegAdviceSaveDto> longInsertOrUpdateList = deviceList.stream().filter(e -> TherapyTimeType.LONG_TERM
|
||||||
|
.getValue().equals(e.getTherapyEnum())
|
||||||
|
&& (DbOpType.INSERT.getCode().equals(e.getDbOpType()) || DbOpType.UPDATE.getCode().equals(e.getDbOpType())))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
for (RegAdviceSaveDto regAdviceSaveDto : longInsertOrUpdateList) {
|
||||||
|
deviceRequest = new DeviceRequest();
|
||||||
|
deviceRequest.setId(regAdviceSaveDto.getRequestId()); // 主键id
|
||||||
|
deviceRequest.setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue()); // 请求状态
|
||||||
|
deviceRequest.setTenantId(SecurityUtils.getLoginUser().getTenantId()); // 显式设置租户ID
|
||||||
|
if (is_sign) {
|
||||||
|
deviceRequest.setReqAuthoredTime(authoredTime); // 医嘱签发时间
|
||||||
|
}
|
||||||
|
// 保存时处理的字段属性
|
||||||
|
if (is_save) {
|
||||||
|
deviceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.DEVICE_RES_NO.getPrefix(), 4));
|
||||||
|
deviceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
|
||||||
|
deviceRequest.setQuantity(regAdviceSaveDto.getQuantity()); // 请求数量
|
||||||
|
deviceRequest.setUnitCode(regAdviceSaveDto.getUnitCode()); // 请求单位编码
|
||||||
|
deviceRequest.setLotNumber(regAdviceSaveDto.getLotNumber()); // 产品批号
|
||||||
|
deviceRequest.setCategoryEnum(regAdviceSaveDto.getCategoryEnum()); // 请求类型
|
||||||
|
deviceRequest.setDeviceDefId(regAdviceSaveDto.getAdviceDefinitionId());// 耗材定义id
|
||||||
|
deviceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
|
||||||
|
deviceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
|
||||||
|
deviceRequest.setOrgId(regAdviceSaveDto.getFounderOrgId()); // 开方人科室
|
||||||
|
deviceRequest.setReqAuthoredTime(startTime); // 医嘱开始时间
|
||||||
|
deviceRequest.setPerformLocation(regAdviceSaveDto.getLocationId()); // 发放科室
|
||||||
|
deviceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
|
||||||
|
deviceRequest.setPackageId(regAdviceSaveDto.getPackageId()); // 组套id
|
||||||
|
deviceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
|
||||||
|
deviceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
|
||||||
|
deviceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
|
||||||
|
deviceRequest.setEncounterDiagnosisId(regAdviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
|
||||||
|
}
|
||||||
|
iDeviceRequestService.saveOrUpdate(deviceRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增 + 修改 (临时医嘱)
|
||||||
|
List<RegAdviceSaveDto> tempInsertOrUpdateList = deviceList.stream().filter(e -> TherapyTimeType.TEMPORARY
|
||||||
|
.getValue().equals(e.getTherapyEnum())
|
||||||
|
&& (DbOpType.INSERT.getCode().equals(e.getDbOpType()) || DbOpType.UPDATE.getCode().equals(e.getDbOpType())))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
for (RegAdviceSaveDto regAdviceSaveDto : tempInsertOrUpdateList) {
|
||||||
|
deviceRequest = new DeviceRequest();
|
||||||
|
deviceRequest.setId(regAdviceSaveDto.getRequestId()); // 主键id
|
||||||
|
deviceRequest.setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue()); // 请求状态
|
||||||
|
deviceRequest.setTenantId(SecurityUtils.getLoginUser().getTenantId()); // 显式设置租户ID
|
||||||
|
if (is_sign) {
|
||||||
|
deviceRequest.setReqAuthoredTime(authoredTime); // 医嘱签发时间
|
||||||
|
}
|
||||||
|
// 保存时处理的字段属性
|
||||||
|
if (is_save) {
|
||||||
|
deviceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.DEVICE_RES_NO.getPrefix(), 4));
|
||||||
|
deviceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
|
||||||
|
deviceRequest.setQuantity(regAdviceSaveDto.getQuantity()); // 请求数量
|
||||||
|
deviceRequest.setUnitCode(regAdviceSaveDto.getUnitCode()); // 请求单位编码
|
||||||
|
deviceRequest.setLotNumber(regAdviceSaveDto.getLotNumber()); // 产品批号
|
||||||
|
deviceRequest.setCategoryEnum(regAdviceSaveDto.getCategoryEnum()); // 请求类型
|
||||||
|
deviceRequest.setDeviceDefId(regAdviceSaveDto.getAdviceDefinitionId());// 耗材定义id
|
||||||
|
deviceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
|
||||||
|
deviceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
|
||||||
|
deviceRequest.setOrgId(regAdviceSaveDto.getFounderOrgId()); // 开方人科室
|
||||||
|
deviceRequest.setReqAuthoredTime(startTime); // 医嘱开始时间
|
||||||
|
deviceRequest.setPerformLocation(regAdviceSaveDto.getLocationId()); // 发放科室
|
||||||
|
deviceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
|
||||||
|
deviceRequest.setPackageId(regAdviceSaveDto.getPackageId()); // 组套id
|
||||||
|
deviceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
|
||||||
|
deviceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
|
||||||
|
deviceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
|
||||||
|
deviceRequest.setEncounterDiagnosisId(regAdviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
|
||||||
|
}
|
||||||
|
iDeviceRequestService.saveOrUpdate(deviceRequest);
|
||||||
|
|
||||||
|
// 保存时,保存耗材费用项
|
||||||
|
if (is_save) {
|
||||||
|
// 处理耗材发放
|
||||||
|
Long dispenseId = iDeviceDispenseService.handleDeviceDispense(deviceRequest,
|
||||||
|
regAdviceSaveDto.getDbOpType());
|
||||||
|
|
||||||
|
// 保存耗材费用项
|
||||||
|
chargeItem = new ChargeItem();
|
||||||
|
chargeItem.setId(regAdviceSaveDto.getChargeItemId()); // 费用项id
|
||||||
|
chargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue()); // 收费状态
|
||||||
|
chargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(deviceRequest.getBusNo()));
|
||||||
|
chargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
|
||||||
|
chargeItem.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
|
||||||
|
chargeItem.setContextEnum(regAdviceSaveDto.getAdviceType()); // 类型
|
||||||
|
chargeItem.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
|
||||||
|
chargeItem.setDefinitionId(regAdviceSaveDto.getDefinitionId()); // 费用定价ID
|
||||||
|
chargeItem.setDefDetailId(regAdviceSaveDto.getDefinitionDetailId()); // 定价子表主键
|
||||||
|
chargeItem.setEntererId(regAdviceSaveDto.getPractitionerId());// 开立人ID
|
||||||
|
chargeItem.setEnteredDate(curDate); // 开立时间
|
||||||
|
chargeItem.setServiceTable(CommonConstants.TableName.WOR_DEVICE_REQUEST);// 医疗服务类型
|
||||||
|
chargeItem.setServiceId(deviceRequest.getId()); // 医疗服务ID
|
||||||
|
chargeItem.setProductTable(regAdviceSaveDto.getAdviceTableName());// 产品所在表
|
||||||
|
chargeItem.setProductId(regAdviceSaveDto.getAdviceDefinitionId());// 收费项id
|
||||||
|
chargeItem.setAccountId(regAdviceSaveDto.getAccountId());// 关联账户ID
|
||||||
|
chargeItem.setRequestingOrgId(orgId); // 开立科室
|
||||||
|
chargeItem.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
|
||||||
|
chargeItem.setEncounterDiagnosisId(regAdviceSaveDto.getEncounterDiagnosisId()); // 就诊诊断id
|
||||||
|
chargeItem.setDispenseId(dispenseId); // 发放ID
|
||||||
|
|
||||||
|
chargeItem.setQuantityValue(regAdviceSaveDto.getQuantity()); // 数量
|
||||||
|
chargeItem.setQuantityUnit(regAdviceSaveDto.getUnitCode()); // 单位
|
||||||
|
chargeItem.setUnitPrice(regAdviceSaveDto.getUnitPrice()); // 单价
|
||||||
|
chargeItem.setTotalPrice(regAdviceSaveDto.getTotalPrice()); // 总价
|
||||||
|
|
||||||
|
iChargeItemService.saveOrUpdate(chargeItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询住院医嘱请求数据
|
* 查询住院医嘱请求数据
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -55,10 +55,10 @@
|
|||||||
<if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
|
<if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
|
||||||
<choose>
|
<choose>
|
||||||
<when test="ew.customSqlSegment.contains('tenant_id')">
|
<when test="ew.customSqlSegment.contains('tenant_id')">
|
||||||
${ew.customSqlSegment.replaceFirst('tenant_id', 'T1.tenant_id').replaceFirst('status_enum', 'T1.status_enum').replaceFirst('WHERE', 'AND')}
|
${ew.customSqlSegment.replaceFirst('tenant_id', 'T1.tenant_id').replaceFirst('status_enum', 'T1.status_enum').replaceFirst('name', 'T1.name').replaceFirst('WHERE', 'AND')}
|
||||||
</when>
|
</when>
|
||||||
<otherwise>
|
<otherwise>
|
||||||
${ew.customSqlSegment.replaceFirst('status_enum', 'T1.status_enum').replaceFirst('WHERE', 'AND')}
|
${ew.customSqlSegment.replaceFirst('status_enum', 'T1.status_enum').replaceFirst('name', 'T1.name').replaceFirst('WHERE', 'AND')}
|
||||||
</otherwise>
|
</otherwise>
|
||||||
</choose>
|
</choose>
|
||||||
</if>
|
</if>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
AND ddo.delete_flag = '0'
|
AND ddo.delete_flag = '0'
|
||||||
|
|
||||||
WHERE dd.delete_flag = '0'
|
WHERE dd.delete_flag = '0'
|
||||||
|
AND dd.is_valid = 0
|
||||||
|
|
||||||
<!-- 关键:医院 + 科室联合可见 -->
|
<!-- 关键:医院 + 科室联合可见 -->
|
||||||
<if test="organizationId != null and organizationId != 0">
|
<if test="organizationId != null and organizationId != 0">
|
||||||
@@ -80,6 +81,10 @@
|
|||||||
AND dd.name LIKE CONCAT('%', #{name}, '%')
|
AND dd.name LIKE CONCAT('%', #{name}, '%')
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
|
<if test="primaryMenuEnum != null">
|
||||||
|
AND dd.primary_menu_enum = #{primaryMenuEnum}
|
||||||
|
</if>
|
||||||
|
|
||||||
GROUP BY dd.id, dd.primary_menu_enum, dd.sub_menu
|
GROUP BY dd.id, dd.primary_menu_enum, dd.sub_menu
|
||||||
ORDER BY dd.display_order
|
ORDER BY dd.display_order
|
||||||
|
|
||||||
|
|||||||
@@ -34,14 +34,16 @@
|
|||||||
ON e.id = sr.encounter_id
|
ON e.id = sr.encounter_id
|
||||||
AND sr.refund_service_id IS NULL
|
AND sr.refund_service_id IS NULL
|
||||||
AND sr.delete_flag = '0'
|
AND sr.delete_flag = '0'
|
||||||
|
INNER JOIN med_medication_request mmr
|
||||||
|
ON mmr.id = sr.based_on_id
|
||||||
|
AND mmr.delete_flag = '0'
|
||||||
|
AND mmr.infusion_flag = 1
|
||||||
LEFT JOIN adm_patient pt
|
LEFT JOIN adm_patient pt
|
||||||
ON pt.id = sr.patient_id
|
ON pt.id = sr.patient_id
|
||||||
AND pt.delete_flag = '0'
|
AND pt.delete_flag = '0'
|
||||||
LEFT JOIN wor_activity_definition ad
|
|
||||||
ON ad.id = sr.activity_id
|
|
||||||
AND ad.delete_flag = '0'
|
|
||||||
WHERE e.delete_flag = '0'
|
WHERE e.delete_flag = '0'
|
||||||
AND sr.status_enum IN (#{inProgress}, #{completed}, #{cancelled})
|
AND sr.status_enum IN (#{inProgress}, #{completed}, #{cancelled})
|
||||||
|
AND sr.based_on_table = #{medMedicationRequest}
|
||||||
GROUP BY sr.status_enum,
|
GROUP BY sr.status_enum,
|
||||||
sr.encounter_id,
|
sr.encounter_id,
|
||||||
e.bus_no,
|
e.bus_no,
|
||||||
@@ -106,7 +108,7 @@
|
|||||||
mmr.performer_id,
|
mmr.performer_id,
|
||||||
dis.status_enum AS dispense_status,
|
dis.status_enum AS dispense_status,
|
||||||
mmd."name" AS medication_name,
|
mmd."name" AS medication_name,
|
||||||
ad."name" AS service_name,
|
mmd."name" AS service_name,
|
||||||
ap."name" AS practitioner_name,
|
ap."name" AS practitioner_name,
|
||||||
o."name" AS dept_name,
|
o."name" AS dept_name,
|
||||||
-- 新增子查询:查询配药人
|
-- 新增子查询:查询配药人
|
||||||
@@ -128,15 +130,12 @@
|
|||||||
AND wsr.delete_flag = '0'
|
AND wsr.delete_flag = '0'
|
||||||
AND wsr.refund_service_id IS NULL
|
AND wsr.refund_service_id IS NULL
|
||||||
LEFT JOIN med_medication_request mmr
|
LEFT JOIN med_medication_request mmr
|
||||||
ON mmr.group_id = wsr.group_id
|
ON mmr.id = wsr.based_on_id
|
||||||
AND mmr.delete_flag = '0'
|
AND mmr.delete_flag = '0'
|
||||||
AND mmr.infusion_flag = 1
|
AND mmr.infusion_flag = 1
|
||||||
LEFT JOIN med_medication_dispense dis
|
LEFT JOIN med_medication_dispense dis
|
||||||
ON dis.med_req_id = mmr.id
|
ON dis.med_req_id = mmr.id
|
||||||
AND dis.delete_flag = '0'
|
AND dis.delete_flag = '0'
|
||||||
LEFT JOIN wor_activity_definition ad
|
|
||||||
ON ad.id = wsr.activity_id
|
|
||||||
AND ad.delete_flag = '0'
|
|
||||||
LEFT JOIN med_medication_definition mmd
|
LEFT JOIN med_medication_definition mmd
|
||||||
ON mmr.medication_id = mmd.id
|
ON mmr.medication_id = mmd.id
|
||||||
AND mmd.delete_flag = '0'
|
AND mmd.delete_flag = '0'
|
||||||
@@ -147,7 +146,6 @@
|
|||||||
ON o.id = wsr.org_id
|
ON o.id = wsr.org_id
|
||||||
AND o.delete_flag = '0'
|
AND o.delete_flag = '0'
|
||||||
WHERE ae.id = #{encounterId}
|
WHERE ae.id = #{encounterId}
|
||||||
AND ad.category_code = '21'
|
|
||||||
AND wsr.based_on_table = #{medMedicationRequest}
|
AND wsr.based_on_table = #{medMedicationRequest}
|
||||||
AND ae.delete_flag = '0') AS pr
|
AND ae.delete_flag = '0') AS pr
|
||||||
${ew.customSqlSegment}
|
${ew.customSqlSegment}
|
||||||
@@ -173,13 +171,16 @@
|
|||||||
wsr.occurrence_end_time,
|
wsr.occurrence_end_time,
|
||||||
wsr.id AS service_id,
|
wsr.id AS service_id,
|
||||||
wsr.tenant_id,
|
wsr.tenant_id,
|
||||||
ad."name" AS service_name,
|
mmd."name" AS service_name,
|
||||||
ap."name" AS performer_name,
|
ap."name" AS performer_name,
|
||||||
al."name" AS org_name
|
al."name" AS org_name
|
||||||
FROM wor_service_request wsr
|
FROM wor_service_request wsr
|
||||||
LEFT JOIN wor_activity_definition ad
|
LEFT JOIN med_medication_request mmr
|
||||||
ON ad.id = wsr.activity_id
|
ON wsr.based_on_id = mmr.id
|
||||||
AND ad.delete_flag = '0'
|
AND mmr.delete_flag = '0'
|
||||||
|
LEFT JOIN med_medication_definition mmd
|
||||||
|
ON mmr.medication_id = mmd.id
|
||||||
|
AND mmd.delete_flag = '0'
|
||||||
LEFT JOIN adm_practitioner ap
|
LEFT JOIN adm_practitioner ap
|
||||||
ON wsr.performer_id = ap.id
|
ON wsr.performer_id = ap.id
|
||||||
AND ap.delete_flag = '0'
|
AND ap.delete_flag = '0'
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
<result property="merchandiseName" column="merchandise_name"/>
|
<result property="merchandiseName" column="merchandise_name"/>
|
||||||
<result property="traceNo" column="trace_no"/>
|
<result property="traceNo" column="trace_no"/>
|
||||||
<result property="partAttributeEnum" column="part_attribute_enum"/>
|
<result property="partAttributeEnum" column="part_attribute_enum"/>
|
||||||
|
<result property="dispenseEnum" column="dispense_enum"/>
|
||||||
<collection property="inventoryDetailList" ofType="com.openhis.web.pharmacymanage.dto.InventoryDetailDto">
|
<collection property="inventoryDetailList" ofType="com.openhis.web.pharmacymanage.dto.InventoryDetailDto">
|
||||||
<result property="inventoryId" column="inventory_id"/>
|
<result property="inventoryId" column="inventory_id"/>
|
||||||
<result property="maxUnitCode" column="max_unit_code"/>
|
<result property="maxUnitCode" column="max_unit_code"/>
|
||||||
@@ -169,7 +170,8 @@
|
|||||||
ii.inventory_quantity,
|
ii.inventory_quantity,
|
||||||
ii.inventory_lot_number,
|
ii.inventory_lot_number,
|
||||||
ii.expiration_date,
|
ii.expiration_date,
|
||||||
ii.med_type_code
|
ii.med_type_code,
|
||||||
|
ii.dispense_enum
|
||||||
FROM ( SELECT T8."name" AS department_name,
|
FROM ( SELECT T8."name" AS department_name,
|
||||||
T9.id AS doctor_id,
|
T9.id AS doctor_id,
|
||||||
T9."name" AS doctor_name,
|
T9."name" AS doctor_name,
|
||||||
@@ -188,7 +190,7 @@
|
|||||||
T1.status_enum,
|
T1.status_enum,
|
||||||
T2.rate_code,
|
T2.rate_code,
|
||||||
T1.location_id,
|
T1.location_id,
|
||||||
T1.method_code,
|
T2.method_code,
|
||||||
T1.lot_number,
|
T1.lot_number,
|
||||||
T2.dose_unit_code,
|
T2.dose_unit_code,
|
||||||
T2.dispense_per_quantity,
|
T2.dispense_per_quantity,
|
||||||
@@ -216,7 +218,8 @@
|
|||||||
T14.quantity AS inventory_quantity,
|
T14.quantity AS inventory_quantity,
|
||||||
T14.lot_number AS inventory_lot_number,
|
T14.lot_number AS inventory_lot_number,
|
||||||
T14.expiration_date,
|
T14.expiration_date,
|
||||||
T15.med_type_code
|
T15.med_type_code,
|
||||||
|
T1.dispense_enum
|
||||||
FROM med_medication_dispense AS T1
|
FROM med_medication_dispense AS T1
|
||||||
LEFT JOIN med_medication_request AS T2
|
LEFT JOIN med_medication_request AS T2
|
||||||
ON T1.med_req_id = T2.id
|
ON T1.med_req_id = T2.id
|
||||||
@@ -252,7 +255,7 @@
|
|||||||
ON T1.location_id = T13.id
|
ON T1.location_id = T13.id
|
||||||
AND T13.delete_flag = '0'
|
AND T13.delete_flag = '0'
|
||||||
LEFT JOIN wor_inventory_item AS T14
|
LEFT JOIN wor_inventory_item AS T14
|
||||||
ON T2.medication_id = T14.item_id
|
ON T1.medication_id = T14.item_id
|
||||||
AND T1.location_id = T14.location_id
|
AND T1.location_id = T14.location_id
|
||||||
AND T14.delete_flag = '0'
|
AND T14.delete_flag = '0'
|
||||||
LEFT JOIN adm_encounter_diagnosis AS T15
|
LEFT JOIN adm_encounter_diagnosis AS T15
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
* 从字典动态获取常量值,避免硬编码
|
* 从字典动态获取常量值,避免硬编码
|
||||||
*
|
*
|
||||||
* 使用方式:
|
* 使用方式:
|
||||||
* import { DIAG_TYPE } from '@/utils/medicalConstants';
|
* import { DIAG_TYPE, RequestStatus } from '@/utils/medicalConstants';
|
||||||
* medTypeCode: DIAG_TYPE.WESTERN_MEDICINE
|
* medTypeCode: DIAG_TYPE.WESTERN_MEDICINE
|
||||||
|
* serviceStatus: RequestStatus.ACTIVE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getDicts } from '@/api/system/dict/data';
|
import { getDicts } from '@/api/system/dict/data';
|
||||||
@@ -12,6 +13,52 @@ import { getDicts } from '@/api/system/dict/data';
|
|||||||
// 诊断类型字典缓存
|
// 诊断类型字典缓存
|
||||||
let diagTypeCache = null;
|
let diagTypeCache = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求状态枚举(与后端 RequestStatus.java 保持一致)
|
||||||
|
* 用于服务申请、医嘱执行等状态管理
|
||||||
|
*/
|
||||||
|
export const RequestStatus = {
|
||||||
|
/** 待发送 */
|
||||||
|
DRAFT: 1,
|
||||||
|
/** 已发送/待执行 */
|
||||||
|
ACTIVE: 2,
|
||||||
|
/** 已完成 */
|
||||||
|
COMPLETED: 3,
|
||||||
|
/** 暂停 */
|
||||||
|
ON_HOLD: 4,
|
||||||
|
/** 取消/待退 */
|
||||||
|
CANCELLED: 5,
|
||||||
|
/** 停嘱 */
|
||||||
|
STOPPED: 6,
|
||||||
|
/** 不执行 */
|
||||||
|
ENDED: 7,
|
||||||
|
/** 未知 */
|
||||||
|
UNKNOWN: 9,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求状态枚举的说明信息
|
||||||
|
*/
|
||||||
|
export const RequestStatusDescriptions = {
|
||||||
|
1: '待发送',
|
||||||
|
2: '已发送/待执行',
|
||||||
|
3: '已完成',
|
||||||
|
4: '暂停',
|
||||||
|
5: '取消/待退',
|
||||||
|
6: '停嘱',
|
||||||
|
7: '不执行',
|
||||||
|
9: '未知',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求状态的说明
|
||||||
|
* @param {number} value - 请求状态值
|
||||||
|
* @returns {string} - 说明信息
|
||||||
|
*/
|
||||||
|
export function getRequestStatusDescription(value) {
|
||||||
|
return RequestStatusDescriptions[value] || '未知状态';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取诊断类型字典(异步初始化)
|
* 获取诊断类型字典(异步初始化)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ import {
|
|||||||
} from './component/api';
|
} from './component/api';
|
||||||
import AdviceListDialog from './component/adviceListDialog.vue';
|
import AdviceListDialog from './component/adviceListDialog.vue';
|
||||||
import {formatDate, formatDateStr} from '@/utils/index';
|
import {formatDate, formatDateStr} from '@/utils/index';
|
||||||
|
import { RequestStatus } from '@/utils/medicalConstants';
|
||||||
|
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
const total = ref(1);
|
const total = ref(1);
|
||||||
@@ -210,7 +211,7 @@ const data = reactive({
|
|||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
searchKey: undefined,
|
searchKey: undefined,
|
||||||
serviceStatus: 3, // 默认值为已完成 (对应 RequestStatus.COMPLETED)
|
serviceStatus: RequestStatus.ACTIVE, // 默认值为待执行
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { queryParams } = toRefs(data);
|
const { queryParams } = toRefs(data);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<!-- 顶部操作按钮区 -->
|
<!-- 顶部操作按钮区 -->
|
||||||
<el-header class="top-action-bar" height="50px">
|
<el-header class="top-action-bar" height="50px">
|
||||||
<el-row class="action-buttons" type="flex" justify="end" :gutter="10">
|
<el-row class="action-buttons" type="flex" justify="end" :gutter="10">
|
||||||
<el-button type="success" size="large" @click="handleSave" class="save-btn">
|
<el-button type="success" size="large" @click="handleSave" class="save-btn" :loading="saving">
|
||||||
<el-icon><Document /></el-icon>
|
<el-icon><Document /></el-icon>
|
||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -400,19 +400,35 @@
|
|||||||
<span class="card-title">检验项目选择</span>
|
<span class="card-title">检验项目选择</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 搜索框 -->
|
<!-- 搜索框(自动完成) -->
|
||||||
<el-input
|
<el-autocomplete
|
||||||
v-model="searchKeyword"
|
v-model="searchKeyword"
|
||||||
|
:fetch-suggestions="querySearchInspectionItems"
|
||||||
placeholder="搜索检验项目..."
|
placeholder="搜索检验项目..."
|
||||||
size="small"
|
size="small"
|
||||||
clearable
|
clearable
|
||||||
prefix-icon="Search"
|
prefix-icon="Search"
|
||||||
@input="handleSearch"
|
@select="handleSearchSelect"
|
||||||
|
@clear="handleSearchClear"
|
||||||
|
value-key="itemName"
|
||||||
class="search-input"
|
class="search-input"
|
||||||
/>
|
:debounce="300"
|
||||||
|
>
|
||||||
|
<template #default="{ item }">
|
||||||
|
<div class="suggestion-item">
|
||||||
|
<span class="suggestion-name">{{ item.itemName }}</span>
|
||||||
|
<el-tag size="small" type="info" class="suggestion-category">{{ item.typeName || '检验' }}</el-tag>
|
||||||
|
<span class="suggestion-price">¥{{ item.itemPrice }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
|
|
||||||
<!-- 分类树 -->
|
<!-- 分类树 -->
|
||||||
<el-scrollbar class="category-tree" style="max-height: 280px">
|
<el-scrollbar
|
||||||
|
class="category-tree"
|
||||||
|
style="max-height: 280px"
|
||||||
|
@scroll="handleScroll"
|
||||||
|
>
|
||||||
<!-- 无数据提示 -->
|
<!-- 无数据提示 -->
|
||||||
<el-empty v-if="!inspectionLoading && inspectionCategories.length === 0" description="暂无检验项目数据" :image-size="80" />
|
<el-empty v-if="!inspectionLoading && inspectionCategories.length === 0" description="暂无检验项目数据" :image-size="80" />
|
||||||
<!-- 数据列表 -->
|
<!-- 数据列表 -->
|
||||||
@@ -427,9 +443,19 @@
|
|||||||
>
|
>
|
||||||
<span class="category-tree-icon">{{ category.expanded ? '▼' : '▶' }}</span>
|
<span class="category-tree-icon">{{ category.expanded ? '▼' : '▶' }}</span>
|
||||||
<span>{{ category.label }}</span>
|
<span>{{ category.label }}</span>
|
||||||
<span class="category-count">({{ category.items.length }})</span>
|
<span class="category-count">({{ category.total || category.items.length }})</span>
|
||||||
|
<!-- 加载状态图标 -->
|
||||||
|
<el-icon v-if="category.loading" class="is-loading" style="margin-left: 8px; color: #409eff;">
|
||||||
|
<Loading />
|
||||||
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="category.expanded" class="category-tree-children">
|
<div v-if="category.expanded" class="category-tree-children">
|
||||||
|
<!-- 加载中占位 -->
|
||||||
|
<div v-if="category.loading && category.items.length === 0" class="loading-placeholder">
|
||||||
|
<el-icon class="is-loading" style="margin-right: 8px;"><Loading /></el-icon>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
|
<!-- 项目列表 -->
|
||||||
<div
|
<div
|
||||||
v-for="item in getFilteredItems(category.key)"
|
v-for="item in getFilteredItems(category.key)"
|
||||||
:key="item.itemId"
|
:key="item.itemId"
|
||||||
@@ -444,6 +470,22 @@
|
|||||||
<span class="item-itemName">{{ item.itemName }}</span>
|
<span class="item-itemName">{{ item.itemName }}</span>
|
||||||
<span class="item-price">¥{{ item.itemPrice }}</span>
|
<span class="item-price">¥{{ item.itemPrice }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 加载更多 -->
|
||||||
|
<div v-if="category.hasMore && category.items.length > 0" class="load-more">
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
:loading="category.loading"
|
||||||
|
@click.stop="loadMoreItems(category.key)"
|
||||||
|
>
|
||||||
|
{{ category.loading ? '加载中...' : '加载更多' }}
|
||||||
|
</el-button>
|
||||||
|
<span class="load-info">(已加载 {{ category.items.length }}/{{ category.total }} 条)</span>
|
||||||
|
</div>
|
||||||
|
<!-- 加载完成提示 -->
|
||||||
|
<div v-if="!category.hasMore && category.items.length > 0" class="no-more">
|
||||||
|
已全部加载 (共 {{ category.total }} 条)
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@@ -492,7 +534,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted, reactive, ref, watch, computed, getCurrentInstance} from 'vue'
|
import {onMounted, reactive, ref, watch, computed, getCurrentInstance} from 'vue'
|
||||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||||
import { DocumentChecked, Plus, Document, Printer, Delete, Check } from '@element-plus/icons-vue'
|
import { DocumentChecked, Plus, Document, Printer, Delete, Check, Loading } from '@element-plus/icons-vue'
|
||||||
import {
|
import {
|
||||||
checkInspectionApplicationNo,
|
checkInspectionApplicationNo,
|
||||||
deleteInspectionApplication, getApplyList,
|
deleteInspectionApplication, getApplyList,
|
||||||
@@ -504,6 +546,7 @@ import useUserStore from '@/store/modules/user.js'
|
|||||||
// 迁移到 hiprint
|
// 迁移到 hiprint
|
||||||
import { previewPrint } from '@/utils/printUtils.js'
|
import { previewPrint } from '@/utils/printUtils.js'
|
||||||
import {storeToRefs} from 'pinia'
|
import {storeToRefs} from 'pinia'
|
||||||
|
import { debounce } from 'lodash-es'
|
||||||
|
|
||||||
// 获取当前组件实例和字典
|
// 获取当前组件实例和字典
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
@@ -532,6 +575,7 @@ const emit = defineEmits(['save'])
|
|||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
const saving = ref(false) // 保存状态
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const leftActiveTab = ref('application')
|
const leftActiveTab = ref('application')
|
||||||
const isGeneratingNewApplyNo = ref(false) // 标志:是否正在生成新申请单号
|
const isGeneratingNewApplyNo = ref(false) // 标志:是否正在生成新申请单号
|
||||||
@@ -624,7 +668,8 @@ const validationErrors = reactive({
|
|||||||
clinicDiag: false,
|
clinicDiag: false,
|
||||||
medicalHistorySummary: false,
|
medicalHistorySummary: false,
|
||||||
purposeofInspection: false,
|
purposeofInspection: false,
|
||||||
labApplyItemList: false
|
labApplyItemList: false,
|
||||||
|
applyTime: false
|
||||||
})
|
})
|
||||||
|
|
||||||
// 已选择的表格行
|
// 已选择的表格行
|
||||||
@@ -639,15 +684,21 @@ const searchKeyword = ref('')
|
|||||||
// 活动分类
|
// 活动分类
|
||||||
const activeCategory = ref('')
|
const activeCategory = ref('')
|
||||||
|
|
||||||
// 检验项目分类(动态从API获取)
|
// 检验项目分类(动态从API获取,支持懒加载和分页)
|
||||||
const inspectionCategories = ref([])
|
const inspectionCategories = ref([])
|
||||||
|
|
||||||
// 检验项目加载状态
|
// 检验项目加载状态(整体)
|
||||||
const inspectionLoading = ref(false)
|
const inspectionLoading = ref(false)
|
||||||
|
|
||||||
// 加载检验项目分类和项目
|
// 每页加载条数
|
||||||
|
const PAGE_SIZE = 50
|
||||||
|
|
||||||
|
// 搜索防抖时间(毫秒)
|
||||||
|
const SEARCH_DEBOUNCE_TIME = 300
|
||||||
|
|
||||||
|
// 加载检验类型分类列表(只加载分类,项目懒加载)
|
||||||
async function loadInspectionData() {
|
async function loadInspectionData() {
|
||||||
// 如果已经加载过数据,直接返回(避免重复请求)
|
// 如果已经加载过分类,直接返回
|
||||||
if (inspectionCategories.value.length > 0) {
|
if (inspectionCategories.value.length > 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -655,194 +706,244 @@ async function loadInspectionData() {
|
|||||||
inspectionLoading.value = true
|
inspectionLoading.value = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 并行请求:同时获取检验类型列表和检验项目列表
|
// 只获取检验类型列表
|
||||||
const [typeRes, itemRes] = await Promise.all([
|
const typeRes = await getInspectionTypeList().catch(error => {
|
||||||
getInspectionTypeList().catch(error => {
|
|
||||||
console.error('获取检验类型失败:', error)
|
console.error('获取检验类型失败:', error)
|
||||||
return { data: [] }
|
return { data: [] }
|
||||||
}),
|
|
||||||
getInspectionItemList({
|
|
||||||
pageNo: 1,
|
|
||||||
pageSize: 500,
|
|
||||||
searchKey: '',
|
|
||||||
categoryCode: inspectionCategoryCode.value
|
|
||||||
}).catch(error => {
|
|
||||||
console.error('获取检验项目失败:', error)
|
|
||||||
return { data: { records: [] } }
|
|
||||||
})
|
})
|
||||||
])
|
|
||||||
|
|
||||||
const typeList = typeRes.data || []
|
const typeList = typeRes.data || []
|
||||||
|
|
||||||
// 解析检验项目数据
|
// 创建分类结构,但不加载项目(懒加载)
|
||||||
let allItems = []
|
|
||||||
if (itemRes.data && itemRes.data.records) {
|
|
||||||
allItems = itemRes.data.records
|
|
||||||
} else if (itemRes.data && Array.isArray(itemRes.data)) {
|
|
||||||
allItems = itemRes.data
|
|
||||||
} else if (Array.isArray(itemRes)) {
|
|
||||||
allItems = itemRes
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按分类组织数据(与检验项目设置维护保持一致的字段映射)
|
|
||||||
const categories = typeList
|
const categories = typeList
|
||||||
.filter(type => type.validFlag === 1 || type.validFlag === undefined)
|
.filter(type => type.validFlag === 1 || type.validFlag === undefined)
|
||||||
.map((type, index) => {
|
.map((type, index) => ({
|
||||||
const categoryItems = allItems
|
|
||||||
.filter(item => {
|
|
||||||
// 转换为字符串进行比较,避免类型不匹配问题
|
|
||||||
const itemTypeId = String(item.inspectionTypeId || '')
|
|
||||||
const typeId = String(type.id || '')
|
|
||||||
const itemTypeName = String(item.inspectionTypeId_dictText || item.typeName || '').trim()
|
|
||||||
const typeName = String(type.name || '').trim()
|
|
||||||
|
|
||||||
// 按检验类型ID匹配(优先使用 inspectionTypeId)
|
|
||||||
const matchById = itemTypeId && typeId && itemTypeId === typeId
|
|
||||||
const matchByName = itemTypeName && typeName && itemTypeName === typeName
|
|
||||||
const matchByCode = String(item.typeCode || '') === String(type.code || '')
|
|
||||||
|
|
||||||
return matchById || matchByName || matchByCode
|
|
||||||
})
|
|
||||||
.map(item => ({
|
|
||||||
itemId: item.id || item.activityId || Math.random().toString(36).substring(2, 11),
|
|
||||||
itemName: item.name || item.itemName || '',
|
|
||||||
itemPrice: item.retailPrice || item.price || 0,
|
|
||||||
itemAmount: item.retailPrice || item.price || 0,
|
|
||||||
sampleType: item.specimenCode_dictText || item.sampleType || '血液',
|
|
||||||
unit: item.unit || '',
|
|
||||||
itemQty: 1,
|
|
||||||
serviceFee: 0,
|
|
||||||
type: type.name || item.inspectionTypeId_dictText || '检验',
|
|
||||||
isSelfPay: false,
|
|
||||||
activityId: item.activityId,
|
|
||||||
code: item.busNo || item.code || item.activityCode,
|
|
||||||
inspectionTypeId: item.inspectionTypeId || null
|
|
||||||
}))
|
|
||||||
|
|
||||||
return {
|
|
||||||
key: type.code || `type_${index}`,
|
key: type.code || `type_${index}`,
|
||||||
label: type.name || `分类${index + 1}`,
|
label: type.name || `分类${index + 1}`,
|
||||||
expanded: index === 0,
|
typeId: type.id, // 保存类型ID用于分页查询
|
||||||
items: categoryItems
|
expanded: index === 0, // 默认展开第一个
|
||||||
}
|
loaded: false, // 是否已加载项目
|
||||||
})
|
loading: false, // 是否正在加载
|
||||||
|
items: [], // 项目列表
|
||||||
// 过滤掉没有项目的分类
|
pageNo: 1, // 当前页码
|
||||||
const validCategories = categories.filter(cat => cat.items.length > 0)
|
pageSize: PAGE_SIZE, // 每页条数
|
||||||
|
total: 0, // 总条数
|
||||||
// 如果没有有效分类,但有项目数据,按项目自带的检验类型文本分组
|
hasMore: true // 是否还有更多数据
|
||||||
if (validCategories.length === 0 && allItems.length > 0) {
|
|
||||||
// 按检验类型文本分组
|
|
||||||
const typeMap = new Map()
|
|
||||||
allItems.forEach(item => {
|
|
||||||
const typeName = item.inspectionTypeId_dictText || '其他检验'
|
|
||||||
if (!typeMap.has(typeName)) {
|
|
||||||
typeMap.set(typeName, [])
|
|
||||||
}
|
|
||||||
typeMap.get(typeName).push(item)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 创建分类
|
|
||||||
typeMap.forEach((items, typeName) => {
|
|
||||||
const mappedItems = items.map(item => ({
|
|
||||||
itemId: item.id || item.activityId || Math.random().toString(36).substring(2, 11),
|
|
||||||
itemName: item.name || item.itemName || '',
|
|
||||||
itemPrice: item.retailPrice || item.price || 0,
|
|
||||||
itemAmount: item.retailPrice || item.price || 0,
|
|
||||||
sampleType: item.specimenCode_dictText || item.sampleType || '血液',
|
|
||||||
unit: item.unit || '',
|
|
||||||
itemQty: 1,
|
|
||||||
serviceFee: 0,
|
|
||||||
type: typeName,
|
|
||||||
isSelfPay: false,
|
|
||||||
activityId: item.activityId,
|
|
||||||
code: item.busNo || item.code || item.activityCode,
|
|
||||||
inspectionTypeId: item.inspectionTypeId || null
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
validCategories.push({
|
if (categories.length > 0) {
|
||||||
key: `type_${typeName}`,
|
inspectionCategories.value = categories
|
||||||
label: typeName,
|
activeCategory.value = categories[0].key
|
||||||
expanded: validCategories.length === 0,
|
|
||||||
items: mappedItems
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validCategories.length > 0) {
|
// 预加载第一个分类的项目
|
||||||
inspectionCategories.value = validCategories
|
await loadCategoryItems(categories[0].key)
|
||||||
activeCategory.value = validCategories[0].key
|
|
||||||
} else {
|
} else {
|
||||||
console.warn('未获取到有效的检验项目数据,使用备用数据')
|
console.warn('未获取到检验类型分类')
|
||||||
// 直接使用备用数据,不抛出错误
|
|
||||||
inspectionCategories.value = [
|
|
||||||
{
|
|
||||||
key: 'biochemical',
|
|
||||||
label: '生化',
|
|
||||||
expanded: true,
|
|
||||||
items: [
|
|
||||||
{ itemId: 1, itemName: '肝功能', itemPrice: 31, itemAmount: 31, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
|
|
||||||
{ itemId: 2, itemName: '肾功能', itemPrice: 28, itemAmount: 28, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
|
|
||||||
{ itemId: 3, itemName: '血糖', itemPrice: 15, itemAmount: 15, sampleType: '血清', unit: 'mmol/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'blood',
|
|
||||||
label: '临检',
|
|
||||||
expanded: false,
|
|
||||||
items: [
|
|
||||||
{ itemId: 4, itemName: '血常规+crp', itemPrice: 50, itemAmount: 50, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false },
|
|
||||||
{ itemId: 5, itemName: '血常规(五分类)', itemPrice: 15, itemAmount: 15, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
activeCategory.value = 'biochemical'
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载检验项目数据失败:', error)
|
console.error('加载检验类型分类失败:', error)
|
||||||
// 加载失败时使用静态数据作为备用
|
|
||||||
inspectionCategories.value = [
|
|
||||||
{
|
|
||||||
key: 'biochemical',
|
|
||||||
label: '生化',
|
|
||||||
expanded: true,
|
|
||||||
items: [
|
|
||||||
{ itemId: 1, itemName: '肝功能', itemPrice: 31, itemAmount: 31, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
|
|
||||||
{ itemId: 2, itemName: '肾功能', itemPrice: 28, itemAmount: 28, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
|
|
||||||
{ itemId: 3, itemName: '血糖', itemPrice: 15, itemAmount: 15, sampleType: '血清', unit: 'mmol/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'blood',
|
|
||||||
label: '临检',
|
|
||||||
expanded: false,
|
|
||||||
items: [
|
|
||||||
{ itemId: 4, itemName: '血常规+crp', itemPrice: 50, itemAmount: 50, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false },
|
|
||||||
{ itemId: 5, itemName: '血常规(五分类)', itemPrice: 15, itemAmount: 15, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
activeCategory.value = 'biochemical'
|
|
||||||
} finally {
|
} finally {
|
||||||
inspectionLoading.value = false
|
inspectionLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取过滤后的项目
|
// 懒加载分类项目(分页)
|
||||||
|
async function loadCategoryItems(categoryKey, loadMore = false) {
|
||||||
|
const category = inspectionCategories.value.find(c => c.key === categoryKey)
|
||||||
|
if (!category) return
|
||||||
|
|
||||||
|
// 已加载完成且不是加载更多,或正在加载中,跳过
|
||||||
|
if ((category.loaded && !loadMore) || category.loading) return
|
||||||
|
// 没有更多数据了,跳过
|
||||||
|
if (loadMore && !category.hasMore) return
|
||||||
|
|
||||||
|
category.loading = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
pageNo: category.pageNo,
|
||||||
|
pageSize: category.pageSize,
|
||||||
|
categoryCode: inspectionCategoryCode.value,
|
||||||
|
searchKey: searchKeyword.value || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有类型ID,添加筛选条件
|
||||||
|
if (category.typeId) {
|
||||||
|
params.inspectionTypeId = category.typeId
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getInspectionItemList(params)
|
||||||
|
|
||||||
|
// 解析数据
|
||||||
|
let records = []
|
||||||
|
let total = 0
|
||||||
|
if (res.data && res.data.records) {
|
||||||
|
records = res.data.records
|
||||||
|
total = res.data.total || 0
|
||||||
|
} else if (res.data && Array.isArray(res.data)) {
|
||||||
|
records = res.data
|
||||||
|
total = records.length
|
||||||
|
} else if (Array.isArray(res)) {
|
||||||
|
records = res
|
||||||
|
total = records.length
|
||||||
|
}
|
||||||
|
|
||||||
|
// 映射数据格式
|
||||||
|
const mappedItems = records.map(item => ({
|
||||||
|
itemId: item.id || item.activityId || Math.random().toString(36).substring(2, 11),
|
||||||
|
itemName: item.name || item.itemName || '',
|
||||||
|
itemPrice: item.retailPrice || item.price || 0,
|
||||||
|
itemAmount: item.retailPrice || item.price || 0,
|
||||||
|
sampleType: item.specimenCode_dictText || item.sampleType || '血液',
|
||||||
|
unit: item.unit || '',
|
||||||
|
itemQty: 1,
|
||||||
|
serviceFee: 0,
|
||||||
|
type: category.label,
|
||||||
|
isSelfPay: false,
|
||||||
|
activityId: item.activityId,
|
||||||
|
code: item.busNo || item.code || item.activityCode,
|
||||||
|
inspectionTypeId: item.inspectionTypeId || null
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 更新分类数据
|
||||||
|
if (loadMore) {
|
||||||
|
// 追加数据
|
||||||
|
category.items.push(...mappedItems)
|
||||||
|
} else {
|
||||||
|
// 首次加载
|
||||||
|
category.items = mappedItems
|
||||||
|
}
|
||||||
|
|
||||||
|
category.total = total
|
||||||
|
category.hasMore = category.items.length < total
|
||||||
|
category.loaded = true
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`加载分类 [${category.label}] 项目失败:`, error)
|
||||||
|
// 加载失败时设置空数据
|
||||||
|
if (!loadMore) {
|
||||||
|
category.items = []
|
||||||
|
category.total = 0
|
||||||
|
category.hasMore = false
|
||||||
|
category.loaded = true
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
category.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载更多项目
|
||||||
|
function loadMoreItems(categoryKey) {
|
||||||
|
const category = inspectionCategories.value.find(c => c.key === categoryKey)
|
||||||
|
if (!category || !category.hasMore || category.loading) return
|
||||||
|
|
||||||
|
category.pageNo++
|
||||||
|
loadCategoryItems(categoryKey, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理滚动事件(无限滚动)
|
||||||
|
function handleScroll({ scrollTop, scrollHeight, clientHeight }) {
|
||||||
|
// 距离底部 50px 时触发加载更多
|
||||||
|
if (scrollHeight - scrollTop - clientHeight < 50) {
|
||||||
|
const expandedCategory = inspectionCategories.value.find(c => c.expanded)
|
||||||
|
if (expandedCategory && expandedCategory.hasMore && !expandedCategory.loading) {
|
||||||
|
loadMoreItems(expandedCategory.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防抖搜索处理
|
||||||
|
const handleSearchDebounced = debounce(() => {
|
||||||
|
// 重新加载当前展开分类的数据
|
||||||
|
const expandedCategory = inspectionCategories.value.find(c => c.expanded)
|
||||||
|
if (expandedCategory) {
|
||||||
|
// 重置分页状态
|
||||||
|
expandedCategory.pageNo = 1
|
||||||
|
expandedCategory.loaded = false
|
||||||
|
expandedCategory.hasMore = true
|
||||||
|
expandedCategory.items = []
|
||||||
|
// 重新加载
|
||||||
|
loadCategoryItems(expandedCategory.key)
|
||||||
|
}
|
||||||
|
}, SEARCH_DEBOUNCE_TIME)
|
||||||
|
|
||||||
|
// 获取过滤后的项目(本地搜索)
|
||||||
const getFilteredItems = (categoryKey) => {
|
const getFilteredItems = (categoryKey) => {
|
||||||
const category = inspectionCategories.value.find(cat => cat.key === categoryKey)
|
const category = inspectionCategories.value.find(cat => cat.key === categoryKey)
|
||||||
if (!category) return []
|
if (!category) return []
|
||||||
|
|
||||||
if (!searchKeyword.value) {
|
// 如果正在加载,返回现有数据
|
||||||
|
if (category.loading) {
|
||||||
return category.items
|
return category.items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 本地过滤(安全检查 itemName)
|
||||||
|
if (searchKeyword.value) {
|
||||||
|
const keyword = searchKeyword.value.toLowerCase()
|
||||||
return category.items.filter(item =>
|
return category.items.filter(item =>
|
||||||
item.itemName.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
item.itemName && item.itemName.toLowerCase().includes(keyword)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return category.items
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索建议查询(自动完成)
|
||||||
|
async function querySearchInspectionItems(queryString, cb) {
|
||||||
|
if (!queryString) {
|
||||||
|
cb([])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 20, // 限制返回数量
|
||||||
|
categoryCode: inspectionCategoryCode.value,
|
||||||
|
searchKey: queryString
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getInspectionItemList(params)
|
||||||
|
|
||||||
|
let suggestions = []
|
||||||
|
if (res.data && res.data.records) {
|
||||||
|
// 映射数据格式,与 loadInspectionItemsByType 保持一致
|
||||||
|
suggestions = res.data.records.map(item => ({
|
||||||
|
itemId: item.id || item.activityId,
|
||||||
|
itemName: item.name || item.itemName || '',
|
||||||
|
itemPrice: item.retailPrice || item.price || 0,
|
||||||
|
sampleType: item.specimenCode_dictText || item.sampleType || '血液',
|
||||||
|
unit: item.unit || '',
|
||||||
|
code: item.busNo || item.code || item.activityCode,
|
||||||
|
activityId: item.activityId,
|
||||||
|
inspectionTypeId: item.inspectionTypeId || null
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(suggestions)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('搜索检验项目失败:', error)
|
||||||
|
cb([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索选择处理
|
||||||
|
function handleSearchSelect(item) {
|
||||||
|
// 直接添加到已选列表
|
||||||
|
if (!isItemSelected(item)) {
|
||||||
|
selectedInspectionItems.value.push({
|
||||||
|
...item,
|
||||||
|
itemName: item.itemName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 清空搜索关键词
|
||||||
|
searchKeyword.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索框清空处理
|
||||||
|
function handleSearchClear() {
|
||||||
|
searchKeyword.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
// 获取检验申请单列表
|
// 获取检验申请单列表
|
||||||
function getInspectionList() {
|
function getInspectionList() {
|
||||||
@@ -1054,6 +1155,9 @@ async function resetForm() {
|
|||||||
|
|
||||||
// 保存
|
// 保存
|
||||||
function handleSave() {
|
function handleSave() {
|
||||||
|
// 如果正在保存,直接返回
|
||||||
|
if (saving.value) return
|
||||||
|
|
||||||
// 重置验证错误状态
|
// 重置验证错误状态
|
||||||
Object.keys(validationErrors).forEach(key => {
|
Object.keys(validationErrors).forEach(key => {
|
||||||
validationErrors[key] = false
|
validationErrors[key] = false
|
||||||
@@ -1061,29 +1165,28 @@ function handleSave() {
|
|||||||
|
|
||||||
let hasErrors = false
|
let hasErrors = false
|
||||||
|
|
||||||
// 检查必填字段
|
|
||||||
// 检查必填字段,执行科室
|
// 检查必填字段,执行科室
|
||||||
if (!formData.executeDepartment) {
|
if (!formData.executeDepartment) {
|
||||||
validationErrors.executeDepartment = true
|
validationErrors.executeDepartment = true
|
||||||
hasErrors = true
|
hasErrors = true
|
||||||
}
|
}
|
||||||
// 检查必填字段,诊断描述
|
// 检查必填字段,诊断描述
|
||||||
if (!formData.clinicDesc.trim()) {
|
if (!formData.clinicDesc?.trim()) {
|
||||||
validationErrors.clinicDesc = true
|
validationErrors.clinicDesc = true
|
||||||
hasErrors = true
|
hasErrors = true
|
||||||
}
|
}
|
||||||
// 检查必填字段,临床诊断
|
// 检查必填字段,临床诊断
|
||||||
if (!formData.clinicDiag.trim()) {
|
if (!formData.clinicDiag?.trim()) {
|
||||||
validationErrors.clinicDiag = true
|
validationErrors.clinicDiag = true
|
||||||
hasErrors = true
|
hasErrors = true
|
||||||
}
|
}
|
||||||
// 检查必填字段,病史摘要
|
// 检查必填字段,病史摘要
|
||||||
if (!formData.medicalHistorySummary.trim()) {
|
if (!formData.medicalHistorySummary?.trim()) {
|
||||||
validationErrors.medicalHistorySummary = true
|
validationErrors.medicalHistorySummary = true
|
||||||
hasErrors = true
|
hasErrors = true
|
||||||
}
|
}
|
||||||
// 检查必填字段,检验目的
|
// 检查必填字段,检验目的
|
||||||
if (!formData.purposeofInspection.trim()) {
|
if (!formData.purposeofInspection?.trim()) {
|
||||||
validationErrors.purposeofInspection = true
|
validationErrors.purposeofInspection = true
|
||||||
hasErrors = true
|
hasErrors = true
|
||||||
}
|
}
|
||||||
@@ -1095,7 +1198,7 @@ function handleSave() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 检查必填字段,申请日期
|
// 检查必填字段,申请日期
|
||||||
if(!formData.applyTime || (typeof formData.applyTime === 'string' && !formData.applyTime.trim())) {
|
if(!formData.applyTime || (typeof formData.applyTime === 'string' && !formData.applyTime?.trim())) {
|
||||||
validationErrors.applyTime = true
|
validationErrors.applyTime = true
|
||||||
hasErrors = true
|
hasErrors = true
|
||||||
}
|
}
|
||||||
@@ -1182,9 +1285,11 @@ function handleSave() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
const executeSave = (saveData) => {
|
const executeSave = (saveData) => {
|
||||||
|
saving.value = true
|
||||||
saveInspectionApplication(saveData).then((res) => {
|
saveInspectionApplication(saveData).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
ElMessage.success('保存成功')
|
ElMessage.success('保存成功')
|
||||||
|
emit('save', res.data) // 通知父组件保存成功
|
||||||
resetForm()
|
resetForm()
|
||||||
// 生成新的申请单号
|
// 生成新的申请单号
|
||||||
generateApplicationNo().then((newApplyNo) => {
|
generateApplicationNo().then((newApplyNo) => {
|
||||||
@@ -1211,6 +1316,8 @@ const executeSave = (saveData) => {
|
|||||||
// 处理请求失败的其他错误
|
// 处理请求失败的其他错误
|
||||||
console.error('保存检验申请单时发生错误:', error);
|
console.error('保存检验申请单时发生错误:', error);
|
||||||
ElMessage.error('保存失败,请稍后重试');
|
ElMessage.error('保存失败,请稍后重试');
|
||||||
|
}).finally(() => {
|
||||||
|
saving.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1222,10 +1329,10 @@ function handleView(row) {
|
|||||||
|
|
||||||
// 根据检验项目名称找到对应的项目数据
|
// 根据检验项目名称找到对应的项目数据
|
||||||
selectedInspectionItems.value = []
|
selectedInspectionItems.value = []
|
||||||
const itemNames = row.inspectionItem.split('、')
|
const itemNames = row.itemName?.split('、') || row.inspectionItem?.split('、') || []
|
||||||
inspectionCategories.value.forEach(category => {
|
inspectionCategories.value.forEach(category => {
|
||||||
category.items.forEach(item => {
|
category.items.forEach(item => {
|
||||||
if (itemNames.includes(item.name)) {
|
if (itemNames.includes(item.itemName)) {
|
||||||
selectedInspectionItems.value.push(item)
|
selectedInspectionItems.value.push(item)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1234,7 +1341,7 @@ function handleView(row) {
|
|||||||
leftActiveTab.value = 'application'
|
leftActiveTab.value = 'application'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换分类
|
// 切换分类(修改为懒加载)
|
||||||
function switchCategory(category) {
|
function switchCategory(category) {
|
||||||
if (activeCategory.value === category) {
|
if (activeCategory.value === category) {
|
||||||
// 如果点击的是当前激活的分类,则收起
|
// 如果点击的是当前激活的分类,则收起
|
||||||
@@ -1250,12 +1357,13 @@ function switchCategory(category) {
|
|||||||
inspectionCategories.value.forEach(cat => {
|
inspectionCategories.value.forEach(cat => {
|
||||||
cat.expanded = cat.key === category
|
cat.expanded = cat.key === category
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理搜索
|
// 懒加载该分类的项目
|
||||||
function handleSearch() {
|
const targetCategory = inspectionCategories.value.find(c => c.key === category)
|
||||||
// 搜索逻辑已在getFilteredItems中实现
|
if (targetCategory && !targetCategory.loaded) {
|
||||||
|
loadCategoryItems(category)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理项目项点击(排除勾选框点击)
|
// 处理项目项点击(排除勾选框点击)
|
||||||
@@ -1409,8 +1517,8 @@ function handleCellClick(row, column) {
|
|||||||
|
|
||||||
// 根据检验项目名称解析已选项目
|
// 根据检验项目名称解析已选项目
|
||||||
selectedInspectionItems.value = []
|
selectedInspectionItems.value = []
|
||||||
if (row.inspectionItem) {
|
if (row.itemName || row.inspectionItem) {
|
||||||
const itemNames = row.inspectionItem.split('、')
|
const itemNames = (row.itemName || row.inspectionItem).split('、')
|
||||||
inspectionCategories.value.forEach(category => {
|
inspectionCategories.value.forEach(category => {
|
||||||
category.items.forEach(item => {
|
category.items.forEach(item => {
|
||||||
if (itemNames.includes(item.itemName)) {
|
if (itemNames.includes(item.itemName)) {
|
||||||
@@ -1956,6 +2064,39 @@ defineExpose({
|
|||||||
border-top: 1px solid #ebeef5;
|
border-top: 1px solid #ebeef5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 加载中占位样式 */
|
||||||
|
.loading-placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载更多样式 */
|
||||||
|
.load-more {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 1px dashed #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-info {
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 没有更多数据提示 */
|
||||||
|
.no-more {
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #c0c4cc;
|
||||||
|
}
|
||||||
|
|
||||||
.inspection-tree-item {
|
.inspection-tree-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ import PatientList from '../components/patientList.vue';
|
|||||||
import PrescriptionList from './components/prescriptionList.vue';
|
import PrescriptionList from './components/prescriptionList.vue';
|
||||||
import SummaryMedicineList from './components/summaryMedicineList.vue';
|
import SummaryMedicineList from './components/summaryMedicineList.vue';
|
||||||
import {inpatientNurseNavs} from '../constants/navigation';
|
import {inpatientNurseNavs} from '../constants/navigation';
|
||||||
|
import { RequestStatus } from '@/utils/medicalConstants';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -115,7 +116,7 @@ const activeName = ref('preparation');
|
|||||||
const active = ref('first');
|
const active = ref('first');
|
||||||
const exeStatus = ref(1);
|
const exeStatus = ref(1);
|
||||||
const deadline = ref(proxy.formatDateStr(new Date(), 'YYYY-MM-DD') + ' 23:59:59');
|
const deadline = ref(proxy.formatDateStr(new Date(), 'YYYY-MM-DD') + ' 23:59:59');
|
||||||
const requestStatus = ref(3);
|
const requestStatus = ref(RequestStatus.COMPLETED);
|
||||||
const chooseAll = ref(false);
|
const chooseAll = ref(false);
|
||||||
const drugType = ref('1');
|
const drugType = ref('1');
|
||||||
const isDetails = ref('1');
|
const isDetails = ref('1');
|
||||||
|
|||||||
@@ -54,11 +54,12 @@
|
|||||||
import {getCurrentInstance} from 'vue';
|
import {getCurrentInstance} from 'vue';
|
||||||
import PatientList from '../components/patientList.vue';
|
import PatientList from '../components/patientList.vue';
|
||||||
import PrescriptionList from './components/prescriptionList.vue';
|
import PrescriptionList from './components/prescriptionList.vue';
|
||||||
|
import { RequestStatus } from '@/utils/medicalConstants';
|
||||||
|
|
||||||
const activeName = ref('preparation');
|
const activeName = ref('preparation');
|
||||||
const active = ref('first');
|
const active = ref('first');
|
||||||
const exeStatus = ref(1);
|
const exeStatus = ref(1);
|
||||||
const requestStatus = ref(3);
|
const requestStatus = ref(RequestStatus.COMPLETED);
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
|
|
||||||
// 存储子组件引用的对象
|
// 存储子组件引用的对象
|
||||||
|
|||||||
@@ -52,10 +52,11 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import PatientList from '../components/patientList.vue';
|
import PatientList from '../components/patientList.vue';
|
||||||
import PrescriptionList from './components/prescriptionList.vue';
|
import PrescriptionList from './components/prescriptionList.vue';
|
||||||
|
import { RequestStatus } from '@/utils/medicalConstants';
|
||||||
|
|
||||||
const activeName = ref('unverified');
|
const activeName = ref('unverified');
|
||||||
const active = ref('first');
|
const active = ref('first');
|
||||||
const requestStatus = ref(2);
|
const requestStatus = ref(RequestStatus.ACTIVE);
|
||||||
|
|
||||||
// 存储子组件引用的对象
|
// 存储子组件引用的对象
|
||||||
const prescriptionRefs = ref({});
|
const prescriptionRefs = ref({});
|
||||||
|
|||||||
@@ -239,7 +239,7 @@
|
|||||||
<el-table-column type="selection" width="55" align="center" fixed="left"/>
|
<el-table-column type="selection" width="55" align="center" fixed="left"/>
|
||||||
<el-table-column prop="prescriptionNo" label="处方号" width="120" align="center"/>
|
<el-table-column prop="prescriptionNo" label="处方号" width="120" align="center"/>
|
||||||
<el-table-column prop="conditionName" label="诊断" width="120" align="center"/>
|
<el-table-column prop="conditionName" label="诊断" width="120" align="center"/>
|
||||||
<el-table-column prop="medTypeCode_dictText" label="处方类型" width="120" align="center"/>
|
<el-table-column prop="dispenseEnum_enumText" label="处方类型" width="120" align="center"/>
|
||||||
<el-table-column prop="itemName" label="项目名称" width="160" align="center"/>
|
<el-table-column prop="itemName" label="项目名称" width="160" align="center"/>
|
||||||
<el-table-column prop="merchandiseName" label="商品名称" width="160" align="center"/>
|
<el-table-column prop="merchandiseName" label="商品名称" width="160" align="center"/>
|
||||||
<el-table-column prop="quantity" label="发药数量" width="130" align="center">
|
<el-table-column prop="quantity" label="发药数量" width="130" align="center">
|
||||||
@@ -836,7 +836,7 @@ function getRowMarkers(groupCounts, data) {
|
|||||||
|
|
||||||
function spanMethod({row, column, rowIndex, columnIndex}) {
|
function spanMethod({row, column, rowIndex, columnIndex}) {
|
||||||
// 定义需要合并的列范围(前6列,包括selection列)
|
// 定义需要合并的列范围(前6列,包括selection列)
|
||||||
const columnsToMerge = [1, 2, 3, 17]; // 假设selection列是第0列,其他列依次是1, 2, 3, 4, 5
|
const columnsToMerge = [1, 2, 3]; // 假设selection列是第0列,其他列依次是1, 2, 3, 4, 5
|
||||||
// 检查当前列是否在需要合并的列范围内
|
// 检查当前列是否在需要合并的列范围内
|
||||||
if (row.prescriptionNo) {
|
if (row.prescriptionNo) {
|
||||||
if (columnsToMerge.includes(columnIndex)) {
|
if (columnsToMerge.includes(columnIndex)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user