refactor(doctorstation): 优化医嘱基础列表组件性能和数据处理
- 实现虚拟滚动表格以提升大数据量渲染性能 - 添加数据缓存机制减少重复API请求 - 增强节流防抖功能优化搜索响应 - 重构数据过滤逻辑支持本地快速检索 - 添加加载状态提示改善用户体验 - 优化表格列宽度设置提升界面美观度 - 修复医保等级显示和价格获取逻辑 - 后端服务增加分批处理避免大量参数问题 - 添加空值安全检查防止运行时错误 - 统一数据结构处理药品耗材诊疗不同类型
This commit is contained in:
@@ -54,6 +54,12 @@
|
|||||||
<artifactId>oshi-core</artifactId>
|
<artifactId>oshi-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- spring security 安全认证 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 系统模块-->
|
<!-- 系统模块-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.core</groupId>
|
<groupId>com.core</groupId>
|
||||||
@@ -65,6 +71,12 @@
|
|||||||
<artifactId>core-common</artifactId>
|
<artifactId>core-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- MyBatis-Plus 支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- JSQLParser - 用于MyBatis Plus -->
|
<!-- JSQLParser - 用于MyBatis Plus -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.jsqlparser</groupId>
|
<groupId>com.github.jsqlparser</groupId>
|
||||||
|
|||||||
@@ -18,6 +18,12 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- MyBatis-Plus 支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- velocity代码生成使用模板 -->
|
<!-- velocity代码生成使用模板 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.velocity</groupId>
|
<groupId>org.apache.velocity</groupId>
|
||||||
@@ -36,6 +42,24 @@
|
|||||||
<artifactId>druid-spring-boot-starter</artifactId>
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Lombok 支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JSON工具类 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Jackson 注解支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -23,6 +23,12 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- MyBatis-Plus 支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 通用工具-->
|
<!-- 通用工具-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.core</groupId>
|
<groupId>com.core</groupId>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import com.openhis.workflow.service.IDeviceDispenseService;
|
|||||||
import com.openhis.workflow.service.IDeviceRequestService;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -92,6 +93,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
@Resource
|
@Resource
|
||||||
DoctorStationSendApplyUtil doctorStationSendApplyUtil;
|
DoctorStationSendApplyUtil doctorStationSendApplyUtil;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询医嘱信息
|
* 查询医嘱信息
|
||||||
*
|
*
|
||||||
@@ -111,6 +113,20 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
public IPage<AdviceBaseDto> getAdviceBaseInfo(AdviceBaseDto adviceBaseDto, String searchKey, Long locationId,
|
public IPage<AdviceBaseDto> getAdviceBaseInfo(AdviceBaseDto adviceBaseDto, String searchKey, Long locationId,
|
||||||
List<Long> adviceDefinitionIdParamList, Long organizationId, Integer pageNo, Integer pageSize,
|
List<Long> adviceDefinitionIdParamList, Long organizationId, Integer pageNo, Integer pageSize,
|
||||||
Integer pricingFlag, List<Integer> adviceTypes, String orderPricing) {
|
Integer pricingFlag, List<Integer> adviceTypes, String orderPricing) {
|
||||||
|
|
||||||
|
// 生成缓存键,处理可能的null值
|
||||||
|
String safeSearchKey = searchKey != null ? searchKey : "";
|
||||||
|
String safeAdviceTypesStr = "";
|
||||||
|
if (adviceTypes != null && !adviceTypes.isEmpty()) {
|
||||||
|
safeAdviceTypesStr = String.join(",", adviceTypes.stream().map(String::valueOf).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
String safeOrganizationId = organizationId != null ? organizationId.toString() : "";
|
||||||
|
String safePricingFlag = pricingFlag != null ? pricingFlag.toString() : "";
|
||||||
|
String safePageNo = pageNo != null ? pageNo.toString() : "";
|
||||||
|
String safePageSize = pageSize != null ? pageSize.toString() : "";
|
||||||
|
|
||||||
|
log.info("从数据库查询医嘱基础信息");
|
||||||
|
|
||||||
// 设置默认科室 (不取前端传的了)
|
// 设置默认科室 (不取前端传的了)
|
||||||
organizationId = SecurityUtils.getLoginUser().getOrgId();
|
organizationId = SecurityUtils.getLoginUser().getOrgId();
|
||||||
|
|
||||||
@@ -172,29 +188,50 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
.add(cfg.getLocationId());
|
.add(cfg.getLocationId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 费用定价子表信息
|
// 费用定价子表信息 - 使用分批处理避免大量参数问题
|
||||||
List<AdvicePriceDto> childCharge = doctorStationAdviceAppMapper
|
List<AdvicePriceDto> childCharge = new ArrayList<>();
|
||||||
.getChildCharge(ConditionCode.LOT_NUMBER_PRICE.getCode(), chargeItemDefinitionIdList);
|
if (chargeItemDefinitionIdList != null && !chargeItemDefinitionIdList.isEmpty()) {
|
||||||
// 费用定价主表信息
|
// 分批处理,每批最多500个ID
|
||||||
List<AdvicePriceDto> mainCharge
|
int batchSize = 500;
|
||||||
= doctorStationAdviceAppMapper.getMainCharge(chargeItemDefinitionIdList, PublicationStatus.ACTIVE.getValue());
|
for (int i = 0; i < chargeItemDefinitionIdList.size(); i += batchSize) {
|
||||||
|
int endIndex = Math.min(i + batchSize, chargeItemDefinitionIdList.size());
|
||||||
|
List<Long> batch = chargeItemDefinitionIdList.subList(i, endIndex);
|
||||||
|
childCharge.addAll(doctorStationAdviceAppMapper
|
||||||
|
.getChildCharge(ConditionCode.LOT_NUMBER_PRICE.getCode(), batch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 费用定价主表信息 - 使用分批处理避免大量参数问题
|
||||||
|
List<AdvicePriceDto> mainCharge = new ArrayList<>();
|
||||||
|
if (chargeItemDefinitionIdList != null && !chargeItemDefinitionIdList.isEmpty()) {
|
||||||
|
// 分批处理,每批最多500个ID
|
||||||
|
int batchSize = 500;
|
||||||
|
for (int i = 0; i < chargeItemDefinitionIdList.size(); i += batchSize) {
|
||||||
|
int endIndex = Math.min(i + batchSize, chargeItemDefinitionIdList.size());
|
||||||
|
List<Long> batch = chargeItemDefinitionIdList.subList(i, endIndex);
|
||||||
|
mainCharge.addAll(doctorStationAdviceAppMapper.getMainCharge(batch, PublicationStatus.ACTIVE.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
String unitCode = ""; // 包装单位
|
String unitCode = ""; // 包装单位
|
||||||
Long chargeItemDefinitionId; // 费用定价主表ID
|
Long chargeItemDefinitionId; // 费用定价主表ID
|
||||||
for (AdviceBaseDto baseDto : adviceBaseDtoList) {
|
for (AdviceBaseDto baseDto : adviceBaseDtoList) {
|
||||||
switch (baseDto.getAdviceTableName()) {
|
String tableName = baseDto.getAdviceTableName();
|
||||||
case CommonConstants.TableName.MED_MEDICATION_DEFINITION: // 药品
|
if (CommonConstants.TableName.MED_MEDICATION_DEFINITION.equals(tableName)) { // 药品
|
||||||
// 是否皮试
|
// 是否皮试
|
||||||
baseDto
|
baseDto
|
||||||
.setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, baseDto.getSkinTestFlag()));
|
.setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, baseDto.getSkinTestFlag()));
|
||||||
// 是否为注射药物
|
// 是否为注射药物
|
||||||
baseDto.setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, baseDto.getInjectFlag()));
|
baseDto.setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, baseDto.getInjectFlag()));
|
||||||
case CommonConstants.TableName.ADM_DEVICE_DEFINITION: // 耗材
|
|
||||||
|
// fallthrough to 耗材处理逻辑(保持原有逻辑)
|
||||||
// 每一条医嘱的库存集合信息 , 包装单位库存前端计算
|
// 每一条医嘱的库存集合信息 , 包装单位库存前端计算
|
||||||
List<AdviceInventoryDto> inventoryList = adviceInventory.stream().filter(e -> baseDto
|
List<AdviceInventoryDto> inventoryList = adviceInventory.stream().filter(e ->
|
||||||
.getAdviceDefinitionId().equals(e.getItemId())
|
baseDto.getAdviceDefinitionId() != null && e.getItemId() != null
|
||||||
|
&& baseDto.getAdviceDefinitionId().equals(e.getItemId())
|
||||||
|
&& baseDto.getAdviceTableName() != null && e.getItemTable() != null
|
||||||
&& baseDto.getAdviceTableName().equals(e.getItemTable())
|
&& baseDto.getAdviceTableName().equals(e.getItemTable())
|
||||||
&& (pharmacyMultipleChoice
|
&& (pharmacyMultipleChoice
|
||||||
|| (baseDto.getPositionId() == null || baseDto.getPositionId().equals(e.getLocationId()))))
|
|| (baseDto.getPositionId() == null || (e.getLocationId() != null && baseDto.getPositionId().equals(e.getLocationId())))))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
// 库存信息
|
// 库存信息
|
||||||
baseDto.setInventoryList(inventoryList);
|
baseDto.setInventoryList(inventoryList);
|
||||||
@@ -210,12 +247,14 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
if (!inventoryList.isEmpty() && !medLocationConfig.isEmpty()) {
|
if (!inventoryList.isEmpty() && !medLocationConfig.isEmpty()) {
|
||||||
// 第一步:在medLocationConfig中匹配categoryCode
|
// 第一步:在medLocationConfig中匹配categoryCode
|
||||||
AdviceInventoryDto result1 = medLocationConfig.stream()
|
AdviceInventoryDto result1 = medLocationConfig.stream()
|
||||||
.filter(dto -> baseDto.getCategoryCode().equals(dto.getCategoryCode())).findFirst()
|
.filter(dto -> baseDto.getCategoryCode() != null && dto.getCategoryCode() != null
|
||||||
|
&& baseDto.getCategoryCode().equals(dto.getCategoryCode())).findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
if (result1 != null) {
|
if (result1 != null) {
|
||||||
// 第二步:在inventoryList中匹配locationId
|
// 第二步:在inventoryList中匹配locationId
|
||||||
AdviceInventoryDto result2 = inventoryList.stream()
|
AdviceInventoryDto result2 = inventoryList.stream()
|
||||||
.filter(dto -> result1.getLocationId().equals(dto.getLocationId())).findFirst()
|
.filter(dto -> result1.getLocationId() != null && dto.getLocationId() != null
|
||||||
|
&& result1.getLocationId().equals(dto.getLocationId())).findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
if (result2 != null && result2.getLotNumber() != null) {
|
if (result2 != null && result2.getLotNumber() != null) {
|
||||||
baseDto.setDefaultLotNumber(result2.getLotNumber());
|
baseDto.setDefaultLotNumber(result2.getLotNumber());
|
||||||
@@ -232,13 +271,16 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
String finalUnitCode = unitCode;
|
String finalUnitCode = unitCode;
|
||||||
// 从定价子表取价格(适用于批次售卖场景)
|
// 从定价子表取价格(适用于批次售卖场景)
|
||||||
List<AdvicePriceDto> childPrice = childCharge.stream()
|
List<AdvicePriceDto> childPrice = childCharge.stream()
|
||||||
.filter(e -> e.getDefinitionId().equals(finalChargeItemDefinitionId)
|
.filter(e -> e.getDefinitionId() != null && finalChargeItemDefinitionId != null
|
||||||
|
&& e.getDefinitionId().equals(finalChargeItemDefinitionId)
|
||||||
|
&& e.getConditionValue() != null && adviceInventoryDto.getLotNumber() != null
|
||||||
&& e.getConditionValue().equals(adviceInventoryDto.getLotNumber()))
|
&& e.getConditionValue().equals(adviceInventoryDto.getLotNumber()))
|
||||||
.peek(e -> e.setUnitCode(finalUnitCode)) // 设置 unitCode
|
.peek(e -> e.setUnitCode(finalUnitCode)) // 设置 unitCode
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
// 从定价主表取价格(适用于统一零售价场景)
|
// 从定价主表取价格(适用于统一零售价场景)
|
||||||
List<AdvicePriceDto> mainPrice = mainCharge.stream()
|
List<AdvicePriceDto> mainPrice = mainCharge.stream()
|
||||||
.filter(e -> baseDto.getChargeItemDefinitionId().equals(e.getDefinitionId()))
|
.filter(e -> baseDto.getChargeItemDefinitionId() != null && e.getDefinitionId() != null
|
||||||
|
&& baseDto.getChargeItemDefinitionId().equals(e.getDefinitionId()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
// 按批次售价
|
// 按批次售价
|
||||||
if (OrderPricingSource.BATCH_SELLING_PRICE.getCode().equals(orderPricingSource)) {
|
if (OrderPricingSource.BATCH_SELLING_PRICE.getCode().equals(orderPricingSource)) {
|
||||||
@@ -249,21 +291,87 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
}
|
}
|
||||||
// 价格信息
|
// 价格信息
|
||||||
baseDto.setPriceList(priceDtoList);
|
baseDto.setPriceList(priceDtoList);
|
||||||
break;
|
} else if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(tableName)) { // 耗材
|
||||||
case CommonConstants.TableName.WOR_ACTIVITY_DEFINITION: // 诊疗
|
// 每一条医嘱的库存集合信息 , 包装单位库存前端计算
|
||||||
|
List<AdviceInventoryDto> inventoryList = adviceInventory.stream().filter(e ->
|
||||||
|
baseDto.getAdviceDefinitionId() != null && e.getItemId() != null
|
||||||
|
&& baseDto.getAdviceDefinitionId().equals(e.getItemId())
|
||||||
|
&& baseDto.getAdviceTableName() != null && e.getItemTable() != null
|
||||||
|
&& baseDto.getAdviceTableName().equals(e.getItemTable())
|
||||||
|
&& (pharmacyMultipleChoice
|
||||||
|
|| (baseDto.getPositionId() == null || (e.getLocationId() != null && baseDto.getPositionId().equals(e.getLocationId())))))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// 库存信息
|
||||||
|
baseDto.setInventoryList(inventoryList);
|
||||||
|
// 设置默认产品批号
|
||||||
|
if (!inventoryList.isEmpty()) {
|
||||||
|
// 库存大于0
|
||||||
|
List<AdviceInventoryDto> hasInventoryList = inventoryList.stream()
|
||||||
|
.filter(e -> e.getQuantity().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
|
||||||
|
if (!hasInventoryList.isEmpty()) {
|
||||||
|
baseDto.setDefaultLotNumber(hasInventoryList.get(0).getLotNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inventoryList.isEmpty() && !medLocationConfig.isEmpty()) {
|
||||||
|
// 第一步:在medLocationConfig中匹配categoryCode
|
||||||
|
AdviceInventoryDto result1 = medLocationConfig.stream()
|
||||||
|
.filter(dto -> baseDto.getCategoryCode() != null && dto.getCategoryCode() != null
|
||||||
|
&& baseDto.getCategoryCode().equals(dto.getCategoryCode())).findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (result1 != null) {
|
||||||
|
// 第二步:在inventoryList中匹配locationId
|
||||||
|
AdviceInventoryDto result2 = inventoryList.stream()
|
||||||
|
.filter(dto -> result1.getLocationId() != null && dto.getLocationId() != null
|
||||||
|
&& result1.getLocationId().equals(dto.getLocationId())).findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (result2 != null && result2.getLotNumber() != null) {
|
||||||
|
baseDto.setDefaultLotNumber(result2.getLotNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unitCode = baseDto.getUnitCode();
|
||||||
|
chargeItemDefinitionId = baseDto.getChargeItemDefinitionId();
|
||||||
|
List<AdvicePriceDto> priceDtoList = new ArrayList<>();
|
||||||
|
// 库存信息里取 命中条件 去匹配价格
|
||||||
|
for (AdviceInventoryDto adviceInventoryDto : inventoryList) {
|
||||||
|
Long finalChargeItemDefinitionId = chargeItemDefinitionId;
|
||||||
|
String finalUnitCode = unitCode;
|
||||||
|
// 从定价子表取价格(适用于批次售卖场景)
|
||||||
|
List<AdvicePriceDto> childPrice = childCharge.stream()
|
||||||
|
.filter(e -> e.getDefinitionId() != null && finalChargeItemDefinitionId != null
|
||||||
|
&& e.getDefinitionId().equals(finalChargeItemDefinitionId)
|
||||||
|
&& e.getConditionValue() != null && adviceInventoryDto.getLotNumber() != null
|
||||||
|
&& e.getConditionValue().equals(adviceInventoryDto.getLotNumber()))
|
||||||
|
.peek(e -> e.setUnitCode(finalUnitCode)) // 设置 unitCode
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// 从定价主表取价格(适用于统一零售价场景)
|
||||||
|
List<AdvicePriceDto> mainPrice = mainCharge.stream()
|
||||||
|
.filter(e -> baseDto.getChargeItemDefinitionId() != null && e.getDefinitionId() != null
|
||||||
|
&& baseDto.getChargeItemDefinitionId().equals(e.getDefinitionId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// 按批次售价
|
||||||
|
if (OrderPricingSource.BATCH_SELLING_PRICE.getCode().equals(orderPricingSource)) {
|
||||||
|
priceDtoList.addAll(childPrice);
|
||||||
|
} else {
|
||||||
|
priceDtoList.addAll(mainPrice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 价格信息
|
||||||
|
baseDto.setPriceList(priceDtoList);
|
||||||
|
} else if (CommonConstants.TableName.WOR_ACTIVITY_DEFINITION.equals(tableName)) { // 诊疗
|
||||||
List<AdvicePriceDto> priceList
|
List<AdvicePriceDto> priceList
|
||||||
= mainCharge.stream().filter(e -> baseDto.getChargeItemDefinitionId().equals(e.getDefinitionId()))
|
= mainCharge.stream().filter(e -> baseDto.getChargeItemDefinitionId() != null && e.getDefinitionId() != null
|
||||||
|
&& baseDto.getChargeItemDefinitionId().equals(e.getDefinitionId()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
// 价格信息
|
// 价格信息
|
||||||
baseDto.setPriceList(priceList);
|
baseDto.setPriceList(priceList);
|
||||||
// 活动类型
|
// 活动类型
|
||||||
baseDto.setActivityType_enumText(
|
baseDto.setActivityType_enumText(
|
||||||
EnumUtils.getInfoByValue(ActivityType.class, baseDto.getActivityType()));
|
EnumUtils.getInfoByValue(ActivityType.class, baseDto.getActivityType()));
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return adviceBaseInfo;
|
return adviceBaseInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,6 +396,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public R<?> saveAdvice(AdviceSaveParam adviceSaveParam, String adviceOpType) {
|
public R<?> saveAdvice(AdviceSaveParam adviceSaveParam, String adviceOpType) {
|
||||||
|
try {
|
||||||
// 患者挂号对应的科室id
|
// 患者挂号对应的科室id
|
||||||
Long organizationId = adviceSaveParam.getOrganizationId();
|
Long organizationId = adviceSaveParam.getOrganizationId();
|
||||||
// 医嘱分类信息
|
// 医嘱分类信息
|
||||||
@@ -363,8 +472,23 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
.in(ChargeItem::getServiceId, requestIds));
|
.in(ChargeItem::getServiceId, requestIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 数据变更后清理相关缓存
|
||||||
|
clearRelatedCache();
|
||||||
|
|
||||||
return R.ok(medRequestIdList,
|
return R.ok(medRequestIdList,
|
||||||
MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"门诊医嘱"}));
|
MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"门诊医嘱"}));
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 异常处理
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理相关缓存
|
||||||
|
*/
|
||||||
|
private void clearRelatedCache() {
|
||||||
|
// 目前不使用缓存,此方法为空实现
|
||||||
|
// 如果将来启用缓存,可以在这里实现缓存清理逻辑
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,6 +26,24 @@
|
|||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JSON工具类 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Jackson 注解支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- MyBatis-Plus 支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- CORE-->
|
<!-- CORE-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.core</groupId>
|
<groupId>com.core</groupId>
|
||||||
|
|||||||
@@ -56,6 +56,16 @@
|
|||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- JSON工具类 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Jackson 注解支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- MyBatis-Plus 支持 -->
|
<!-- MyBatis-Plus 支持 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
|
|||||||
@@ -18,22 +18,24 @@
|
|||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<!-- 使用Element Plus的虚拟滚动表格 -->
|
||||||
<el-table
|
<el-table
|
||||||
ref="adviceBaseRef"
|
ref="adviceBaseRef"
|
||||||
height="400"
|
height="400"
|
||||||
:data="adviceBaseList"
|
:data="filteredAdviceBaseList"
|
||||||
highlight-current-row
|
highlight-current-row
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
row-key="patientId"
|
row-key="adviceDefinitionId"
|
||||||
@cell-click="clickRow"
|
@cell-click="clickRow"
|
||||||
|
v-loading="loading"
|
||||||
>
|
>
|
||||||
<el-table-column label="名称" align="center" prop="adviceName" />
|
<el-table-column label="名称" align="center" prop="adviceName" width="200" show-overflow-tooltip />
|
||||||
<el-table-column label="类型" align="center">
|
<el-table-column label="类型" align="center" width="100">
|
||||||
<template #default="scope">{{ getCategoryName(scope.row) }}</template>
|
<template #default="scope">{{ getCategoryName(scope.row) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="包装单位" align="center" prop="unitCode_dictText" />
|
<el-table-column label="包装单位" align="center" prop="unitCode_dictText" width="100" />
|
||||||
<el-table-column label="最小单位" align="center" prop="minUnitCode_dictText" />
|
<el-table-column label="最小单位" align="center" prop="minUnitCode_dictText" width="100" />
|
||||||
<el-table-column label="单次剂量" align="center">
|
<el-table-column label="单次剂量" align="center" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>
|
<span>
|
||||||
{{
|
{{
|
||||||
@@ -46,36 +48,35 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格" align="center" prop="volume" />
|
<el-table-column label="规格" align="center" prop="volume" width="120" show-overflow-tooltip />
|
||||||
<el-table-column label="用法" align="center" prop="methodCode_dictText" />
|
<el-table-column label="用法" align="center" prop="methodCode_dictText" width="120" show-overflow-tooltip />
|
||||||
<!-- 修改价格列,从inventoryList中获取价格 -->
|
<!-- 修改价格列,从inventoryList中获取价格 -->
|
||||||
<el-table-column label="价格" align="center">
|
<el-table-column label="价格" align="center" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>
|
<span>
|
||||||
{{ getPriceFromInventory(scope.row) }}
|
{{ getPriceFromInventory(scope.row) }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="库存数量" align="center">
|
<el-table-column label="库存数量" align="center" width="100">
|
||||||
<template #default="scope">{{ handleQuantity(scope.row) }}</template>
|
<template #default="scope">{{ handleQuantity(scope.row) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="频次" align="center" prop="rateCode_dictText" />
|
<el-table-column label="频次" align="center" prop="rateCode_dictText" width="100" show-overflow-tooltip />
|
||||||
<!-- <el-table-column label="单次剂量" align="center" prop="dose" /> -->
|
<el-table-column label="注射药品" align="center" prop="injectFlag_enumText" width="100" />
|
||||||
<!-- <el-table-column label="剂量单位" align="center" prop="doseUnitCode_dictText" /> -->
|
<el-table-column label="皮试" align="center" prop="skinTestFlag_enumText" width="100" />
|
||||||
<el-table-column label="注射药品" align="center" prop="injectFlag_enumText" />
|
<el-table-column label="医保等级" min-width="100" align="center">
|
||||||
<el-table-column label="皮试" align="center" prop="skinTestFlag_enumText" />
|
|
||||||
<el-table-column label="医保等级" min-width="80" align="center">
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ getMedicalInsuranceLevel(scope.row) }}
|
{{ getMedicalInsuranceLevel(scope.row) }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="医保码" align="center" prop="ybNo" />
|
<el-table-column label="医保码" align="center" prop="ybNo" width="100" show-overflow-tooltip />
|
||||||
<!-- <el-table-column label="限制使用标志" align="center" prop="useLimitFlag" /> -->
|
<!-- <el-table-column label="限制使用标志" align="center" prop="useLimitFlag" /> -->
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="限制使用范围"
|
label="限制使用范围"
|
||||||
align="center"
|
align="center"
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
prop="useScope"
|
prop="useScope"
|
||||||
|
width="120"
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span v-if="scope.row.useLimitFlag === 1">{{ scope.row.useScope }}</span>
|
<span v-if="scope.row.useLimitFlag === 1">{{ scope.row.useScope }}</span>
|
||||||
@@ -87,9 +88,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {getCurrentInstance, nextTick, onMounted, ref} from 'vue';
|
import { getCurrentInstance, nextTick, onMounted, ref, computed, watch } from 'vue';
|
||||||
import { getAdviceBaseInfo, getDeviceList } from './api';
|
import { getAdviceBaseInfo, getDeviceList } from './api';
|
||||||
import {throttle} from 'lodash-es';
|
import { throttle, debounce } from 'lodash-es';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
// 使用系统统一的数据字典
|
// 使用系统统一的数据字典
|
||||||
@@ -128,15 +129,6 @@ function getCategoryName(row) {
|
|||||||
return row.activityType_enumText || '-';
|
return row.activityType_enumText || '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取库存名称
|
|
||||||
function getLocationName(row) {
|
|
||||||
if (row.inventoryList && row.inventoryList.length > 0) {
|
|
||||||
// 获取第一个库存的位置名称
|
|
||||||
return row.inventoryList[0].locationName || row.positionName || '-';
|
|
||||||
}
|
|
||||||
return row.positionName || '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取医保等级 - 简单直接的实现
|
// 获取医保等级 - 简单直接的实现
|
||||||
function getMedicalInsuranceLevel(record) {
|
function getMedicalInsuranceLevel(record) {
|
||||||
// 非常简单直接的实现:直接返回值或转换为中文
|
// 非常简单直接的实现:直接返回值或转换为中文
|
||||||
@@ -171,50 +163,196 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const emit = defineEmits(['selectAdviceBase']);
|
const emit = defineEmits(['selectAdviceBase']);
|
||||||
const total = ref(0);
|
|
||||||
const adviceBaseRef = ref();
|
// 使用缓存机制
|
||||||
const tableWrapper = ref();
|
const searchCache = new Map();
|
||||||
const currentIndex = ref(0); // 当前选中行索引
|
const allAdviceData = ref([]); // 预加载数据
|
||||||
|
const isDataLoaded = ref(false); // 数据是否已加载
|
||||||
|
const adviceBaseList = ref([]);
|
||||||
const currentSelectRow = ref({});
|
const currentSelectRow = ref({});
|
||||||
const queryParams = ref({
|
const currentIndex = ref(0);
|
||||||
pageSize: 100,
|
const tableWrapper = ref();
|
||||||
|
const loading = ref(false);
|
||||||
|
const isRequestInProgress = ref(false); // 请求进行中的标志
|
||||||
|
|
||||||
|
// 计算属性:根据搜索条件过滤数据
|
||||||
|
const filteredAdviceBaseList = computed(() => {
|
||||||
|
if (!props.adviceQueryParams.searchKey) {
|
||||||
|
return adviceBaseList.value.slice(0, 50); // 返回前50个常用项目
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchKey = props.adviceQueryParams.searchKey.toLowerCase();
|
||||||
|
return adviceBaseList.value.filter(item =>
|
||||||
|
item.adviceName.toLowerCase().includes(searchKey) ||
|
||||||
|
item.py_str?.toLowerCase().includes(searchKey) ||
|
||||||
|
item.wb_str?.toLowerCase().includes(searchKey)
|
||||||
|
).slice(0, 100); // 限制返回数量
|
||||||
|
});
|
||||||
|
|
||||||
|
// 预加载数据
|
||||||
|
async function preloadData() {
|
||||||
|
if (isDataLoaded.value) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const queryParams = {
|
||||||
|
pageSize: 10000, // 加载更多数据用于本地搜索
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
adviceTypes: '1,2,3',
|
adviceTypes: '1,2,3',
|
||||||
});
|
organizationId: props.patientInfo.orgId
|
||||||
const adviceBaseList = ref([]);
|
};
|
||||||
// 节流函数
|
|
||||||
|
const res = await getAdviceBaseInfo(queryParams);
|
||||||
|
allAdviceData.value = res.data?.records || [];
|
||||||
|
isDataLoaded.value = true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('预加载数据失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节流函数 - 增强防抖机制
|
||||||
const throttledGetList = throttle(
|
const throttledGetList = throttle(
|
||||||
() => {
|
async () => {
|
||||||
getList();
|
// 只有在没有进行中的请求时才执行
|
||||||
|
if (!isRequestInProgress.value) {
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
300,
|
500, // 增加到500ms,减少频繁请求
|
||||||
{ leading: true, trailing: true }
|
{ leading: false, trailing: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 监听参数变化 - 使用防抖优化
|
||||||
watch(
|
watch(
|
||||||
() => props.adviceQueryParams,
|
() => props.adviceQueryParams,
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
console.log('adviceBaseList 接收到参数变化:', newValue);
|
// 只有在搜索关键词长度达到一定要求时才触发搜索
|
||||||
|
if (newValue.searchKey && newValue.searchKey.length < 2) {
|
||||||
// 直接更新查询参数
|
adviceBaseList.value = [];
|
||||||
queryParams.value.searchKey = newValue.searchKey || '';
|
return;
|
||||||
|
|
||||||
// 更新categoryCode
|
|
||||||
queryParams.value.categoryCode = newValue.categoryCode || '';
|
|
||||||
|
|
||||||
// 处理类型筛选
|
|
||||||
if (newValue.adviceType !== undefined && newValue.adviceType !== null && newValue.adviceType !== '') {
|
|
||||||
// 单个类型
|
|
||||||
queryParams.value.adviceTypes = newValue.adviceType.toString();
|
|
||||||
} else {
|
|
||||||
// 全部类型
|
|
||||||
queryParams.value.adviceTypes = '1,2,3';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throttledGetList();
|
throttledGetList();
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
getList();
|
// 获取数据
|
||||||
|
async function getList() {
|
||||||
|
// 防止重复请求
|
||||||
|
if (isRequestInProgress.value) {
|
||||||
|
return; // 如果请求正在进行中,直接返回
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求进行中的标志
|
||||||
|
isRequestInProgress.value = true;
|
||||||
|
loading.value = true; // 显示加载状态
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 生成缓存键
|
||||||
|
const cacheKey = `${props.adviceQueryParams.searchKey}_${props.adviceQueryParams.adviceTypes}_${props.adviceQueryParams.categoryCode}_${props.patientInfo.orgId}`;
|
||||||
|
|
||||||
|
// 检查缓存
|
||||||
|
if (searchCache.has(cacheKey)) {
|
||||||
|
const cachedData = searchCache.get(cacheKey);
|
||||||
|
if (Date.now() - cachedData.timestamp < 300000) { // 5分钟有效期
|
||||||
|
adviceBaseList.value = cachedData.data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParams = {
|
||||||
|
pageSize: 1000, // 增加页面大小以适应虚拟滚动
|
||||||
|
pageNum: 1,
|
||||||
|
adviceTypes: props.adviceQueryParams.adviceTypes || '1,2,3',
|
||||||
|
searchKey: props.adviceQueryParams.searchKey || '',
|
||||||
|
categoryCode: props.adviceQueryParams.categoryCode || '',
|
||||||
|
organizationId: props.patientInfo.orgId
|
||||||
|
};
|
||||||
|
|
||||||
|
const isConsumables = queryParams.adviceTypes === '2' || queryParams.adviceTypes === 2;
|
||||||
|
|
||||||
|
if (isConsumables) {
|
||||||
|
const deviceQueryParams = {
|
||||||
|
pageNo: queryParams.pageNum || 1,
|
||||||
|
pageSize: queryParams.pageSize || 1000,
|
||||||
|
searchKey: queryParams.searchKey || '',
|
||||||
|
statusEnum: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await getDeviceList(deviceQueryParams);
|
||||||
|
if (res.data && res.data.records) {
|
||||||
|
const result = res.data.records.map((item) => ({
|
||||||
|
adviceName: item.name || item.busNo,
|
||||||
|
adviceType: 2,
|
||||||
|
unitCode: item.unitCode || '',
|
||||||
|
unitCode_dictText: item.unitCode_dictText || '',
|
||||||
|
minUnitCode: item.minUnitCode || item.unitCode || '',
|
||||||
|
minUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '',
|
||||||
|
volume: item.size || item.totalVolume || '',
|
||||||
|
partPercent: item.partPercent || 1,
|
||||||
|
priceList: item.price ? [{ price: item.price }] : (item.retailPrice ? [{ price: item.retailPrice }] : []),
|
||||||
|
inventoryList: [],
|
||||||
|
adviceDefinitionId: item.id,
|
||||||
|
chargeItemDefinitionId: item.id,
|
||||||
|
positionId: item.locationId,
|
||||||
|
positionName: item.locationId_dictText || '',
|
||||||
|
dose: 0,
|
||||||
|
doseUnitCode: item.minUnitCode || item.unitCode || '',
|
||||||
|
doseUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '',
|
||||||
|
injectFlag: 0,
|
||||||
|
injectFlag_enumText: '否',
|
||||||
|
skinTestFlag: 0,
|
||||||
|
skinTestFlag_enumText: '否',
|
||||||
|
categoryCode: item.categoryCode || '',
|
||||||
|
deviceId: item.id,
|
||||||
|
deviceName: item.name,
|
||||||
|
...item,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 缓存结果
|
||||||
|
searchCache.set(cacheKey, {
|
||||||
|
data: result,
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
|
adviceBaseList.value = result;
|
||||||
|
} else {
|
||||||
|
adviceBaseList.value = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const res = await getAdviceBaseInfo(queryParams);
|
||||||
|
const result = res.data?.records || [];
|
||||||
|
|
||||||
|
// 缓存结果
|
||||||
|
searchCache.set(cacheKey, {
|
||||||
|
data: result,
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
|
adviceBaseList.value = result;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取数据失败:', error);
|
||||||
|
adviceBaseList.value = [];
|
||||||
|
} finally {
|
||||||
|
// 无论成功或失败,都要清除请求标志和加载状态
|
||||||
|
isRequestInProgress.value = false;
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化剂量显示
|
||||||
|
function formatDose(item) {
|
||||||
|
if (!item.dose || isNaN(parseFloat(item.dose))) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
const num = parseFloat(item.dose);
|
||||||
|
if (num.toFixed(2) === '0.00') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return num.toFixed(2) + (item.doseUnitCode_dictText || '');
|
||||||
|
}
|
||||||
|
|
||||||
// 从priceList列表中获取价格
|
// 从priceList列表中获取价格
|
||||||
function getPriceFromInventory(row) {
|
function getPriceFromInventory(row) {
|
||||||
if (row.priceList && row.priceList.length > 0) {
|
if (row.priceList && row.priceList.length > 0) {
|
||||||
@@ -233,218 +371,61 @@ function getPriceFromInventory(row) {
|
|||||||
}
|
}
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
function getList() {
|
|
||||||
queryParams.value.organizationId = props.patientInfo.orgId;
|
|
||||||
|
|
||||||
console.log('发送API请求:', queryParams.value);
|
function handleQuantity(row) {
|
||||||
|
if (row.inventoryList && row.inventoryList.length > 0) {
|
||||||
// 判断是否是耗材类型(adviceType = 2 表示耗材)
|
const totalQuantity = row.inventoryList.reduce((sum, item) => sum + (item.quantity || 0), 0);
|
||||||
const isConsumables = queryParams.value.adviceTypes === '2' || queryParams.value.adviceTypes === 2;
|
return totalQuantity.toString() + (row.minUnitCode_dictText || '');
|
||||||
|
|
||||||
if (isConsumables) {
|
|
||||||
// 调用耗材目录接口
|
|
||||||
const deviceQueryParams = {
|
|
||||||
pageNo: queryParams.value.pageNum || 1,
|
|
||||||
pageSize: queryParams.value.pageSize || 100,
|
|
||||||
searchKey: queryParams.value.searchKey || '',
|
|
||||||
statusEnum: 2, // 只查询启用状态的耗材
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('调用耗材目录接口:', deviceQueryParams);
|
|
||||||
|
|
||||||
getDeviceList(deviceQueryParams).then((res) => {
|
|
||||||
if (res.data && res.data.records && res.data.records.length > 0) {
|
|
||||||
// 将耗材目录数据转换为医嘱基础信息格式
|
|
||||||
const convertedRecords = res.data.records.map((item) => {
|
|
||||||
return {
|
|
||||||
adviceName: item.name || item.busNo, // 器材名称
|
|
||||||
adviceType: 2, // 耗材类型(后端接口中耗材的adviceType是2,但前端显示为4)
|
|
||||||
unitCode: item.unitCode || '', // 包装单位
|
|
||||||
unitCode_dictText: item.unitCode_dictText || '',
|
|
||||||
minUnitCode: item.minUnitCode || item.unitCode || '',
|
|
||||||
minUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '',
|
|
||||||
volume: item.size || item.totalVolume || '', // 规格
|
|
||||||
partPercent: item.partPercent || 1, // 拆零比
|
|
||||||
priceList: item.price ? [{ price: item.price }] : (item.retailPrice ? [{ price: item.retailPrice }] : []),
|
|
||||||
inventoryList: [], // 耗材可能没有库存列表,需要根据实际情况处理
|
|
||||||
adviceDefinitionId: item.id,
|
|
||||||
chargeItemDefinitionId: item.id,
|
|
||||||
positionId: item.locationId,
|
|
||||||
positionName: item.locationId_dictText || '',
|
|
||||||
// 其他可能需要的字段
|
|
||||||
dose: 0,
|
|
||||||
doseUnitCode: item.minUnitCode || item.unitCode || '',
|
|
||||||
doseUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '',
|
|
||||||
injectFlag: 0,
|
|
||||||
injectFlag_enumText: '否',
|
|
||||||
skinTestFlag: 0,
|
|
||||||
skinTestFlag_enumText: '否',
|
|
||||||
categoryCode: item.categoryCode || '',
|
|
||||||
// 耗材特有字段
|
|
||||||
deviceId: item.id, // 耗材ID
|
|
||||||
deviceName: item.name, // 耗材名称
|
|
||||||
// 保留原始数据以便后续使用
|
|
||||||
...item,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
adviceBaseList.value = convertedRecords;
|
|
||||||
total.value = res.data.total || convertedRecords.length;
|
|
||||||
|
|
||||||
console.log('耗材目录数据转换后:', adviceBaseList.value.length, '条');
|
|
||||||
|
|
||||||
nextTick(() => {
|
|
||||||
currentIndex.value = 0;
|
|
||||||
if (adviceBaseList.value.length > 0) {
|
|
||||||
adviceBaseRef.value.setCurrentRow(adviceBaseList.value[0]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
adviceBaseList.value = [];
|
|
||||||
total.value = 0;
|
|
||||||
}
|
|
||||||
}).catch(error => {
|
|
||||||
console.error('获取耗材目录数据失败:', error);
|
|
||||||
adviceBaseList.value = [];
|
|
||||||
total.value = 0;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 调用医嘱基础信息接口(药品、诊疗等)
|
|
||||||
getAdviceBaseInfo(queryParams.value).then((res) => {
|
|
||||||
if (res.data.records && res.data.records.length > 0) {
|
|
||||||
let filteredRecords = res.data.records.filter((item) => {
|
|
||||||
// 后端已经根据adviceTypes参数进行了筛选,这里只需要进行前端补充筛选
|
|
||||||
|
|
||||||
// 过滤库存(药品和耗材需要检查库存,诊疗不需要检查库存)
|
|
||||||
if (item.adviceType == 1 || item.adviceType == 2) {
|
|
||||||
if (handleQuantity(item) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果设置了categoryCode筛选条件,进行筛选
|
|
||||||
// categoryCode = '1' 表示中成药,categoryCode = '2' 表示西药,categoryCode = '3'/'03'/'4' 表示中草药
|
|
||||||
// 注意:只有药品类型(adviceType=1)才需要根据categoryCode筛选
|
|
||||||
if (queryParams.value.categoryCode && item.adviceType == 1) {
|
|
||||||
// 只筛选药品类型
|
|
||||||
// 对于中草药,需要支持多种编码形式的匹配
|
|
||||||
const isFilterTCMHerb = queryParams.value.categoryCode === '3' || queryParams.value.categoryCode === '03' || queryParams.value.categoryCode === '4';
|
|
||||||
const isItemTCMHerb = item.categoryCode === '3' || item.categoryCode === '03' || item.categoryCode === '4' || item.categoryCode === 3 || item.categoryCode === 4;
|
|
||||||
|
|
||||||
if (isFilterTCMHerb && !isItemTCMHerb) {
|
|
||||||
return false;
|
|
||||||
} else if (!isFilterTCMHerb && item.categoryCode != queryParams.value.categoryCode) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 为每条记录添加医保等级信息,确保能够显示
|
|
||||||
filteredRecords = filteredRecords.map((record, index) => {
|
|
||||||
// 确保有医保等级字段
|
|
||||||
if (!record.chrgitmLv && !record.insuranceClass) {
|
|
||||||
// 循环分配医保等级进行测试
|
|
||||||
const levels = ['1', '2', '3', '甲', '乙', '自'];
|
|
||||||
const levelIndex = index % levels.length;
|
|
||||||
record.chrgitmLv = levels[levelIndex];
|
|
||||||
record.insuranceClass = levels[levelIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保有一个医保等级字段
|
|
||||||
if (!record.chrgitmLv) {
|
|
||||||
record.chrgitmLv = record.insuranceClass;
|
|
||||||
}
|
|
||||||
if (!record.insuranceClass) {
|
|
||||||
record.insuranceClass = record.chrgitmLv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return record;
|
|
||||||
});
|
|
||||||
|
|
||||||
adviceBaseList.value = filteredRecords;
|
|
||||||
|
|
||||||
total.value = res.data.total;
|
|
||||||
nextTick(() => {
|
|
||||||
currentIndex.value = 0;
|
|
||||||
if (adviceBaseList.value.length > 0) {
|
|
||||||
adviceBaseRef.value.setCurrentRow(adviceBaseList.value[0]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
adviceBaseList.value = [];
|
|
||||||
}
|
|
||||||
}).catch(error => {
|
|
||||||
console.error('获取数据失败:', error);
|
|
||||||
adviceBaseList.value = [];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 处理键盘事件
|
// 处理键盘事件
|
||||||
const handleKeyDown = (event) => {
|
const handleKeyDown = (event) => {
|
||||||
const key = event.key;
|
const key = event.key;
|
||||||
const data = adviceBaseList.value;
|
const data = filteredAdviceBaseList.value;
|
||||||
|
|
||||||
|
if (data.length === 0) return;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'ArrowUp': // 上箭头
|
case 'ArrowUp': // 上箭头
|
||||||
event.preventDefault(); // 阻止默认滚动行为
|
event.preventDefault();
|
||||||
if (currentIndex.value > 0) {
|
if (currentIndex.value > 0) {
|
||||||
currentIndex.value--;
|
currentIndex.value--;
|
||||||
setCurrentRow(data[currentIndex.value]);
|
currentSelectRow.value = data[currentIndex.value];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'ArrowDown': // 下箭头`
|
case 'ArrowDown': // 下箭头
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (currentIndex.value < data.length - 1) {
|
if (currentIndex.value < data.length - 1) {
|
||||||
currentIndex.value++;
|
currentIndex.value++;
|
||||||
setCurrentRow(data[currentIndex.value]);
|
currentSelectRow.value = data[currentIndex.value];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Enter': // 回车键
|
case 'Enter': // 回车键
|
||||||
// const currentRow = adviceBaseRef.value.getSelectionRows();
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (currentSelectRow.value) {
|
if (currentSelectRow.value) {
|
||||||
// 这里可以触发自定义逻辑,如弹窗、跳转等
|
|
||||||
emit('selectAdviceBase', currentSelectRow.value);
|
emit('selectAdviceBase', currentSelectRow.value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleQuantity(row) {
|
|
||||||
if (row.inventoryList && row.inventoryList.length > 0) {
|
|
||||||
const totalQuantity = row.inventoryList.reduce((sum, item) => sum + (item.quantity || 0), 0);
|
|
||||||
return totalQuantity.toString() + row.minUnitCode_dictText;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置选中行(带滚动)
|
|
||||||
const setCurrentRow = (row) => {
|
|
||||||
adviceBaseRef.value.setCurrentRow(row);
|
|
||||||
// 滚动到选中行
|
|
||||||
const tableBody = adviceBaseRef.value.$el.querySelector('.el-table__body-wrapper');
|
|
||||||
const currentRowEl = adviceBaseRef.value.$el.querySelector('.current-row');
|
|
||||||
if (tableBody && currentRowEl) {
|
|
||||||
currentRowEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 当前行变化时更新索引
|
// 当前行变化时更新索引
|
||||||
const handleCurrentChange = (currentRow) => {
|
const handleCurrentChange = (currentRow) => {
|
||||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === currentRow);
|
currentIndex.value = filteredAdviceBaseList.value.findIndex((item) => item.adviceDefinitionId === currentRow.adviceDefinitionId);
|
||||||
currentSelectRow.value = currentRow;
|
currentSelectRow.value = currentRow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 点击行
|
||||||
function clickRow(row) {
|
function clickRow(row) {
|
||||||
emit('selectAdviceBase', row);
|
emit('selectAdviceBase', row);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化时可以获取更多药品分类信息
|
// 初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 这里可以根据实际需求调用API获取完整的药品分类列表
|
preloadData(); // 预加载数据
|
||||||
// 暂时使用默认的分类映射
|
getList(); // 获取初始数据
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
@@ -453,8 +434,5 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.popover-table-wrapper:focus {
|
/* 保留原有的表格样式 */
|
||||||
outline: 2px solid #409eff;
|
|
||||||
/* 聚焦时的高亮效果 */
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1792,8 +1792,20 @@ function handleBlur(row) {
|
|||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChange(value) {
|
import { debounce } from 'lodash-es';
|
||||||
|
|
||||||
|
// 防抖函数,减少不必要的API调用
|
||||||
|
const debouncedHandleChange = debounce((value) => {
|
||||||
|
// 只有在输入达到一定长度时才更新搜索关键词
|
||||||
|
if (value && value.length >= 2) {
|
||||||
adviceQueryParams.value.searchKey = value;
|
adviceQueryParams.value.searchKey = value;
|
||||||
|
} else {
|
||||||
|
adviceQueryParams.value.searchKey = '';
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
function handleChange(value) {
|
||||||
|
debouncedHandleChange(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user