feat(medicalOrderSet): 优化医嘱组套功能实现

- 实现医嘱基础列表的分页功能,添加loading状态和缓存机制
- 添加防抖处理和组织机构ID参数支持,优化性能表现
- 实现医嘱组套的完整编辑功能,包括增删改查操作界面
- 添加医嘱组套预览、应用和管理功能模块
- 实现西医组套筛选功能,确保tcmFlag参数正确传递
- 优化医嘱组套数据结构,完善明细项信息处理逻辑
- 添加表单验证和错误处理,提升用户体验和系统稳定性
- 重构代码结构,采用响应式设计提高可维护性
This commit is contained in:
2026-03-17 09:57:21 +08:00
parent 03939fb232
commit 8a7d2abb4a
30 changed files with 2066 additions and 543 deletions

View File

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.core.redis.RedisCache;
import com.core.common.enums.TenantOptionDict;
import com.core.common.exception.ServiceException;
import com.core.common.utils.AssignSeqUtil;
@@ -99,6 +100,14 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
@Resource
DoctorStationSendApplyUtil doctorStationSendApplyUtil;
@Resource
RedisCache redisCache;
// 缓存 key 前缀
private static final String ADVICE_BASE_INFO_CACHE_PREFIX = "advice:base:info:";
// 缓存过期时间(小时)
private static final long CACHE_EXPIRE_HOURS = 24;
/**
* 查询医嘱信息
@@ -132,14 +141,40 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
String safePageNo = pageNo != null ? pageNo.toString() : "";
String safePageSize = pageSize != null ? pageSize.toString() : "";
log.info("从数据库查询医嘱基础信息");
// 设置默认科室:仅当前端/调用方未传 organizationId 时才回退到登录人科室
// 否则会导致门诊划价等场景(按患者挂号科室查询)返回空
if (organizationId == null) {
organizationId = SecurityUtils.getLoginUser().getOrgId();
}
// 只有在没有搜索关键字时才尝试使用缓存
boolean useCache = (searchKey == null || searchKey.trim().isEmpty())
&& (adviceDefinitionIdParamList == null || adviceDefinitionIdParamList.isEmpty());
String cacheKey = null;
if (useCache) {
// 生成缓存 key无搜索关键字时按科室缓存
cacheKey = ADVICE_BASE_INFO_CACHE_PREFIX + organizationId + ":" + safeAdviceTypesStr + ":" + safePageNo + ":" + safePageSize;
// 先清除可能存在的无效缓存JSONObject类型
if (redisCache.hasKey(cacheKey)) {
Object cachedObj = redisCache.getCacheObject(cacheKey);
if (cachedObj instanceof com.alibaba.fastjson2.JSONObject) {
redisCache.deleteObject(cacheKey);
log.info("清除无效缓存, key: {}", cacheKey);
} else if (cachedObj instanceof com.baomidou.mybatisplus.extension.plugins.pagination.Page) {
log.info("从缓存获取医嘱基础信息, key: {}, records: {}", cacheKey, ((IPage<?>)cachedObj).getRecords().size());
return (IPage<AdviceBaseDto>) cachedObj;
}
}
log.info("缓存未命中,准备查询数据库, key: {}", cacheKey);
} else {
log.info("不使用缓存条件: searchKey={}, adviceDefinitionIdParamList={}", searchKey, adviceDefinitionIdParamList);
}
log.info("从数据库查询医嘱基础信息");
// 医嘱定价来源
String orderPricingSource = TenantOptionUtil.getOptionContent(TenantOptionDict.ORDER_PRICING_SOURCE);
if (StringUtils.isEmpty(orderPricingSource) && StringUtils.isEmpty(orderPricing)) {
@@ -160,7 +195,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
new Page<>(pageNo, pageSize), PublicationStatus.ACTIVE.getValue(), organizationId,
CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION,
CommonConstants.TableName.WOR_ACTIVITY_DEFINITION, pricingFlag, adviceDefinitionIdParamList,
adviceTypes,
adviceTypes, searchKey,
queryWrapper);
List<AdviceBaseDto> adviceBaseDtoList = adviceBaseInfo.getRecords();
@@ -390,6 +425,15 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
}
}
// 缓存结果(只有无搜索关键字时才缓存)
if (useCache && cacheKey != null && adviceBaseInfo != null) {
// 确保是 IPage 类型再缓存,避免缓存无效数据
if (adviceBaseInfo instanceof com.baomidou.mybatisplus.extension.plugins.pagination.Page) {
redisCache.setCacheObject(cacheKey, adviceBaseInfo, (int) CACHE_EXPIRE_HOURS, java.util.concurrent.TimeUnit.HOURS);
log.info("缓存医嘱基础信息, key: {}, 过期时间: {} 小时", cacheKey, CACHE_EXPIRE_HOURS);
}
}
return adviceBaseInfo;
}

View File

@@ -4,6 +4,7 @@
package com.openhis.web.doctorstation.controller;
import com.core.common.core.domain.R;
import com.core.common.utils.SecurityUtils;
import com.openhis.common.enums.AdviceOpType;
import com.openhis.common.enums.Whether;
import com.openhis.web.doctorstation.appservice.IDoctorStationAdviceAppService;
@@ -109,9 +110,13 @@ public class DoctorStationChineseMedicalController {
@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
@RequestParam(value = "locationId", required = false) Long locationId,
@RequestParam(value = "adviceDefinitionIdParamList", required = false) List<Long> adviceDefinitionIdParamList,
@RequestParam(value = "organizationId") Long organizationId,
@RequestParam(value = "organizationId", required = false) Long organizationId,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
// 从当前登录用户获取科室 ID 作为默认值
if (organizationId == null) {
organizationId = SecurityUtils.getLoginUser().getOrgId();
}
return R.ok(iDoctorStationChineseMedicalAppService.getTcmAdviceBaseInfo(adviceBaseDto, searchKey, locationId,
adviceDefinitionIdParamList, organizationId, pageNo, pageSize, Whether.NO.getValue()));
}

View File

@@ -37,6 +37,7 @@ public interface DoctorStationAdviceAppMapper {
@Param("activityTableName") String activityTableName, @Param("pricingFlag") Integer pricingFlag,
@Param("adviceDefinitionIdParamList") List<Long> adviceDefinitionIdParamList,
@Param("adviceTypes") List<Integer> adviceTypes,
@Param("searchKey") String searchKey,
@Param(Constants.WRAPPER) QueryWrapper<AdviceBaseDto> queryWrapper);
/**

View File

@@ -30,9 +30,10 @@ public interface IOrdersGroupPackageAppService {
*
* @param packageTypeEnum 类型枚举
* @param searchKey 模糊查询关键字
* @param tcmFlag 中医标识0-西医 1-中医
* @return 组合套餐
*/
List<OrdersGroupPackageQueryDto> getGroupPackage(Integer packageTypeEnum, String searchKey);
List<OrdersGroupPackageQueryDto> getGroupPackage(Integer packageTypeEnum, String searchKey, Integer tcmFlag);
/**
* 查询组合套餐明细
@@ -54,8 +55,9 @@ public interface IOrdersGroupPackageAppService {
* 查询组合套餐,供开立医嘱使用
*
* @param organizationId 患者挂号对应的科室id
* @param tcmFlag 中医标识0-西医 1-中医
* @return 组合套餐
*/
OrdersGroupPackageUseDto getGroupPackageForOrder(Long organizationId);
OrdersGroupPackageUseDto getGroupPackageForOrder(Long organizationId, Integer tcmFlag);
}

View File

@@ -1,8 +1,16 @@
package com.openhis.web.personalization.appservice.impl;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.core.common.core.domain.R;
import com.core.common.exception.ServiceException;
import com.core.common.utils.MessageUtils;
import com.core.common.utils.SecurityUtils;
import com.openhis.common.constant.PromptMsgConstant;
@@ -18,13 +26,8 @@ import com.openhis.web.doctorstation.dto.AdviceBaseDto;
import com.openhis.web.personalization.appservice.IOrdersGroupPackageAppService;
import com.openhis.web.personalization.dto.*;
import com.openhis.web.personalization.mapper.OrdersGroupPackageAppMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.core.framework.datasource.DynamicDataSourceContextHolder.log;
/**
* 组合套餐 实现类
@@ -61,10 +64,12 @@ public class OrdersGroupPackageAppServiceImpl implements IOrdersGroupPackageAppS
if (BindingType.PERSONAL.getValue().equals(packageTypeEnum)
&& ordersGroupPackageSaveDto.getPractitionerId() == null) {
throw new ServiceException("个人组套需选择人员");
// throw new ServiceException("个人组套需选择人员");
ordersGroupPackageSaveDto.setPractitionerId(SecurityUtils.getLoginUser().getPractitionerId());
} else if (BindingType.ORGANIZATION.getValue().equals(packageTypeEnum)
&& ordersGroupPackageSaveDto.getOrganizationId() == null) {
throw new ServiceException("科室组套需选择科室");
// throw new ServiceException("科室组套需选择科室");
ordersGroupPackageSaveDto.setOrganizationId(SecurityUtils.getLoginUser().getOrgId());
}
// 保存主表
OrdersGroupPackage ordersGroupPackage = new OrdersGroupPackage();
@@ -73,6 +78,7 @@ public class OrdersGroupPackageAppServiceImpl implements IOrdersGroupPackageAppS
ordersGroupPackage.setPackageTypeEnum(packageTypeEnum);// 组套包类型
ordersGroupPackage.setOrganizationId(ordersGroupPackageSaveDto.getOrganizationId()); // 科室id
ordersGroupPackage.setPractitionerId(ordersGroupPackageSaveDto.getPractitionerId()); // 参与者id
ordersGroupPackage.setTcmFlag(ordersGroupPackageSaveDto.getTcmFlag()); // 中医标识
ordersGroupPackageService.saveOrUpdate(ordersGroupPackage);
// 编辑场景时,先删除原有的明细再新增
@@ -96,6 +102,7 @@ public class OrdersGroupPackageAppServiceImpl implements IOrdersGroupPackageAppS
ordersGroupPackageDetail.setMethodCode(ordersGroupPackageDetailSaveDto.getMethodCode()); // 给药途径
ordersGroupPackageDetail.setDoseQuantity(ordersGroupPackageDetailSaveDto.getDoseQuantity()); // 小单位单次剂量
ordersGroupPackageDetail.setGroupId(ordersGroupPackageDetailSaveDto.getGroupId()); // 组号
ordersGroupPackageDetail.setTherapyEnum(ordersGroupPackageDetailSaveDto.getTherapyEnum()); // 治疗类型
ordersGroupPackageDetailService.save(ordersGroupPackageDetail);
}
@@ -107,12 +114,14 @@ public class OrdersGroupPackageAppServiceImpl implements IOrdersGroupPackageAppS
*
* @param packageTypeEnum 类型枚举
* @param searchKey 模糊查询关键字
* @param tcmFlag 中医标识
* @return 组合套餐
*/
@Override
public List<OrdersGroupPackageQueryDto> getGroupPackage(Integer packageTypeEnum, String searchKey) {
public List<OrdersGroupPackageQueryDto> getGroupPackage(Integer packageTypeEnum, String searchKey,
Integer tcmFlag) {
List<OrdersGroupPackageQueryDto> groupPackage =
ordersGroupPackageAppMapper.getGroupPackage(packageTypeEnum, null, null, searchKey);
ordersGroupPackageAppMapper.getGroupPackage(packageTypeEnum, null, null, searchKey, tcmFlag);
for (OrdersGroupPackageQueryDto ordersGroupPackageQueryDto : groupPackage) {
ordersGroupPackageQueryDto.setPackageTypeEnum_enumText(
EnumUtils.getInfoByValue(BindingType.class, ordersGroupPackageQueryDto.getPackageTypeEnum()));
@@ -151,19 +160,23 @@ public class OrdersGroupPackageAppServiceImpl implements IOrdersGroupPackageAppS
* 查询组合套餐,供开立医嘱使用
*
* @param organizationId 患者挂号对应的科室id
* @param tcmFlag 中医标识
* @return 组合套餐
*/
@Override
public OrdersGroupPackageUseDto getGroupPackageForOrder(Long organizationId) {
public OrdersGroupPackageUseDto getGroupPackageForOrder(Long organizationId, Integer tcmFlag) {
OrdersGroupPackageUseDto ordersGroupPackageUseDto = new OrdersGroupPackageUseDto();
// 当前参参与者id
Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
// 当前登录账号的科室id
Long orgId = SecurityUtils.getLoginUser().getOrgId();
log.info("[getGroupPackageForOrder] 当前登录用户 practitionerId: {}, orgId: {}", practitionerId, orgId);
// 个人组套
List<OrdersGroupPackageQueryDto> personalGroupPackage =
ordersGroupPackageAppMapper.getGroupPackage(BindingType.PERSONAL.getValue(), null, practitionerId, null);
List<OrdersGroupPackageQueryDto> personalGroupPackage = ordersGroupPackageAppMapper
.getGroupPackage(BindingType.PERSONAL.getValue(), null, practitionerId, null, tcmFlag);
log.info("[getGroupPackageForOrder] 个人组套查询结果数: {}", personalGroupPackage.size());
if (!personalGroupPackage.isEmpty()) {
List<OrdersGroupPackageDto> personalList = personalGroupPackage.stream().map(queryDto -> {
OrdersGroupPackageDto dto = new OrdersGroupPackageDto();
@@ -208,10 +221,13 @@ public class OrdersGroupPackageAppServiceImpl implements IOrdersGroupPackageAppS
});
}
ordersGroupPackageUseDto.setPersonalList(personalList);
log.info("[getGroupPackageForOrder] 个人组套已设置,数量: {}", personalList.size());
} else {
log.info("[getGroupPackageForOrder] 个人组套查询结果为空");
}
// 科室组套
List<OrdersGroupPackageQueryDto> organizationGroupPackage =
ordersGroupPackageAppMapper.getGroupPackage(BindingType.ORGANIZATION.getValue(), orgId, null, null);
List<OrdersGroupPackageQueryDto> organizationGroupPackage = ordersGroupPackageAppMapper
.getGroupPackage(BindingType.ORGANIZATION.getValue(), orgId, null, null, tcmFlag);
if (!organizationGroupPackage.isEmpty()) {
List<OrdersGroupPackageDto> organizationList = organizationGroupPackage.stream().map(queryDto -> {
OrdersGroupPackageDto dto = new OrdersGroupPackageDto();
@@ -260,7 +276,7 @@ public class OrdersGroupPackageAppServiceImpl implements IOrdersGroupPackageAppS
// 全院组套
List<OrdersGroupPackageQueryDto> hospitalGroupPackage =
ordersGroupPackageAppMapper.getGroupPackage(BindingType.HOSPITAL.getValue(), null, null, null);
ordersGroupPackageAppMapper.getGroupPackage(BindingType.HOSPITAL.getValue(), null, null, null, tcmFlag);
if (!hospitalGroupPackage.isEmpty()) {
List<OrdersGroupPackageDto> hospitalList = hospitalGroupPackage.stream().map(queryDto -> {
OrdersGroupPackageDto dto = new OrdersGroupPackageDto();

View File

@@ -65,33 +65,39 @@ public class OrdersGroupPackageController {
* 查询个人组套
*
* @param searchKey 模糊查询关键字
* @param tcmFlag 中医标识0-西医 1-中医
* @return 个人组套
*/
@GetMapping(value = "/get-personal")
public R<?> getPersonal(@RequestParam(value = "searchKey", defaultValue = "") String searchKey) {
return R.ok(ordersGroupPackageAppService.getGroupPackage(BindingType.PERSONAL.getValue(), searchKey));
public R<?> getPersonal(@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
@RequestParam(value = "tcmFlag", defaultValue = "0") Integer tcmFlag) {
return R.ok(ordersGroupPackageAppService.getGroupPackage(BindingType.PERSONAL.getValue(), searchKey, tcmFlag));
}
/**
* 查询科室组套
*
* @param searchKey 模糊查询关键字
* @param tcmFlag 中医标识0-西医 1-中医
* @return 科室组套
*/
@GetMapping(value = "/get-organization")
public R<?> getOrganization(@RequestParam(value = "searchKey", defaultValue = "") String searchKey) {
return R.ok(ordersGroupPackageAppService.getGroupPackage(BindingType.ORGANIZATION.getValue(), searchKey));
public R<?> getOrganization(@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
@RequestParam(value = "tcmFlag", defaultValue = "0") Integer tcmFlag) {
return R.ok(ordersGroupPackageAppService.getGroupPackage(BindingType.ORGANIZATION.getValue(), searchKey, tcmFlag));
}
/**
* 查询全院组套
*
* @param searchKey 模糊查询关键字
* @param tcmFlag 中医标识0-西医 1-中医
* @return 全院组套
*/
@GetMapping(value = "/get-hospital")
public R<?> getHospital(@RequestParam(value = "searchKey", defaultValue = "") String searchKey) {
return R.ok(ordersGroupPackageAppService.getGroupPackage(BindingType.HOSPITAL.getValue(), searchKey));
public R<?> getHospital(@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
@RequestParam(value = "tcmFlag", defaultValue = "0") Integer tcmFlag) {
return R.ok(ordersGroupPackageAppService.getGroupPackage(BindingType.HOSPITAL.getValue(), searchKey, tcmFlag));
}
/**
@@ -120,12 +126,13 @@ public class OrdersGroupPackageController {
* 查询组合套餐,供开立医嘱使用
*
* @param organizationId 患者挂号对应的科室id
* @param tcmFlag 中医标识0-西医 1-中医,不传则不过滤
* @return 组合套餐
*/
@GetMapping(value = "/group-package-for-order")
public R<?>
getGroupPackageForOrder(@RequestParam(value = "organizationId", defaultValue = "0") Long organizationId) {
return R.ok(ordersGroupPackageAppService.getGroupPackageForOrder(organizationId));
public R<?> getGroupPackageForOrder(@RequestParam(value = "organizationId", required = false) Long organizationId,
@RequestParam(value = "tcmFlag", required = false) Integer tcmFlag) {
return R.ok(ordersGroupPackageAppService.getGroupPackageForOrder(organizationId, tcmFlag));
}
}

View File

@@ -63,4 +63,9 @@ public class OrdersGroupPackageDetailSaveDto {
*/
private Long groupId;
/**
* 治疗类型1-长期 2-临时
*/
private Integer therapyEnum;
}

View File

@@ -48,6 +48,11 @@ public class OrdersGroupPackageSaveDto {
@JsonSerialize(using = ToStringSerializer.class)
private Long practitionerId;
/**
* 中医标识0-西医 1-中医
*/
private Integer tcmFlag;
/**
* 明细集合
*/

View File

@@ -26,11 +26,12 @@ public interface OrdersGroupPackageAppMapper {
* @param organizationId 科室id
* @param practitionerId 参与者id
* @param searchKey 模糊查询关键字
* @param tcmFlag 中医标识0-西医 1-中医
* @return 组合套餐
*/
List<OrdersGroupPackageQueryDto> getGroupPackage(@Param("packageTypeEnum") Integer packageTypeEnum,
@Param("organizationId") Long organizationId, @Param("practitionerId") Long practitionerId,
@Param("searchKey") String searchKey);
@Param("searchKey") String searchKey, @Param("tcmFlag") Integer tcmFlag);
/**
* 查询组合套餐明细