Compare commits
46 Commits
f84940fa5f
...
guanyu
| Author | SHA1 | Date | |
|---|---|---|---|
| 920752d36b | |||
| 6dc2a715c8 | |||
| bd50c58dd4 | |||
| e23ac2fd09 | |||
| 4e3ee1f49d | |||
| 2135682332 | |||
| 4ac9254496 | |||
| d4bbc58e4e | |||
| aa193f60a2 | |||
| b74f6bf3f9 | |||
| 9f789cd3a3 | |||
| 4c1222f0f4 | |||
| cfa073bdba | |||
| 021f7180c0 | |||
|
|
ee59fd5ea0 | ||
| 20a372268b | |||
| 31f288c0dd | |||
| 5c97380a78 | |||
| 30e5c92f0b | |||
| 7c6e35dcc3 | |||
| 74b67401f3 | |||
| 81d954fceb | |||
| c7da7440f6 | |||
|
|
232a0db810 | ||
|
|
3394aa54d7 | ||
| dc94978187 | |||
| b925d6ba17 | |||
| 72b9639ec0 | |||
| 0e8fb32108 | |||
| 955c72af41 | |||
|
|
be57c026ec | ||
| 3bf7e04a04 | |||
| 7743bb5df4 | |||
| f274ebaf5c | |||
| 9826df98e3 | |||
|
|
fbe434f01f | ||
|
|
c28b322e91 | ||
| 7eeaafef59 | |||
| 05e7d54d87 | |||
| 7adb3b3ea4 | |||
| 1e6704928a | |||
| 75e49f0237 | |||
| 2b6b00b6c2 | |||
| 1ddf8a2ccd | |||
| 0a37b05aab | |||
| 20817d6dc4 |
27
.agentforge/analysis/556.md
Normal file
27
.agentforge/analysis/556.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Bug #556 Analysis
|
||||
|
||||
## Title
|
||||
【门诊医生站-检验】新增检验申请单时就诊卡号/执行时间未自动回显,且项目列表冗余显示"套餐"文字
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
### Issue 1: 就诊卡号未自动回显
|
||||
- **Code**: `inspectionApplication.vue:886` - `formData.medicalrecordNumber = props.patientInfo.identifierNo || ''`
|
||||
- **Root Cause**: Logic is correct but depends on `props.patientInfo.identifierNo` being populated. The watch on `props.patientInfo` (line 2074) triggers `initData()`. The card number field itself is correctly bound. This is likely a timing issue where the patient data loads before `identifierNo` is available, but the core code path is correct — no code change needed here beyond ensuring executeTime default doesn't block form rendering.
|
||||
|
||||
### Issue 2: 执行时间未默认填充当前系统时间
|
||||
- **Code**: `inspectionApplication.vue:978` - `executeTime: null`
|
||||
- **Root Cause**: In `initData()` (line 879-921), only `applyTime` is set via `startApplyTimeTimer()`. `formData.executeTime` is never assigned a default value. Similarly in `resetForm()` (line 1550), `executeTime` remains `null`.
|
||||
- **Fix**: Add `formData.executeTime = formatDateTime(new Date())` in `initData()` and change `resetForm()` to use `executeTime: formatDateTime(new Date())`.
|
||||
|
||||
### Issue 3: 项目列表冗余显示"套餐"文字
|
||||
- **Code**: `inspectionApplication.vue:1190` - Already fixed with `packageName` check. But `inspectionApplication.vue:2000` in `loadApplicationToForm()` still uses loose check: `item.feePackageId != null || item.itemName?.includes('套餐')`.
|
||||
- **Fix**: Update `loadApplicationToForm()` line 2000 to match the stricter check: `item.feePackageId != null && item.feePackageId !== '' && item.feePackageId !== 'null' && item.packageName`.
|
||||
|
||||
## Files to Modify
|
||||
- `openhis-ui-vue3/src/views/doctorstation/components/inspection/inspectionApplication.vue`
|
||||
|
||||
## Changes
|
||||
1. `initData()`: Add `formData.executeTime = formatDateTime(new Date())` after line 899
|
||||
2. `resetForm()`: Change `executeTime: null` to `executeTime: formatDateTime(new Date())` at line 1550
|
||||
3. `loadApplicationToForm()`: Fix `isPackage` logic at line 2000
|
||||
53
.agentforge/bugs/556-analysis.md
Normal file
53
.agentforge/bugs/556-analysis.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Bug #556 分析报告
|
||||
|
||||
## 问题描述
|
||||
【门诊医生站-检验】新增检验申请单时:
|
||||
1. 就诊卡号字段为空,未自动带出患者就诊卡号
|
||||
2. 执行时间字段未自动填充,仅显示占位提示
|
||||
3. 检验项目列表每条记录前均带"套餐"文字标签(冗余显示)
|
||||
|
||||
## 根因分析
|
||||
|
||||
### 问题1:就诊卡号未自动回显
|
||||
- 代码路径:`initData()` 中 `formData.medicalrecordNumber = props.patientInfo.identifierNo || ''`
|
||||
- 数据绑定:`v-model="formData.medicalrecordNumber"`
|
||||
- `props.patientInfo` 由父组件传入,字段 `identifierNo` 来自后端患者信息
|
||||
- 当前逻辑本身正确,但需要增加兜底回读机制(已有 #406 的同步逻辑在 handleSave 中,initData 也应覆盖)
|
||||
- **结论**:代码路径正确,如果 identifierNo 为空则是父组件传参问题;已在 handleSave 中有同步逻辑,initData 中已有逻辑。无需额外修复。
|
||||
|
||||
### 问题2:执行时间未自动填充
|
||||
- 根因:`formData.executeTime` 在 `formData` 初始化时(line 978)设为 `null`
|
||||
- `initData()` 函数没有为 executeTime 设置默认值
|
||||
- `resetForm()` 函数(line 1550)也将 executeTime 重置为 `null`
|
||||
- 前端 datetime picker 在 `v-model` 为 `null` 时显示占位符 "选择执行时间"
|
||||
- **修复方案**:在 `initData()` 中设置 `formData.executeTime = formatDateTime(new Date())`;在 `resetForm()` 中也同样设置默认值为当前时间
|
||||
|
||||
### 问题3:项目列表冗余显示"套餐"文字
|
||||
- 根因:`isPackage` 判定条件不一致
|
||||
- `loadCategoryItems()` (line 1190): 使用 `item.feePackageId != null && ... && item.packageName` — ✅ 正确(同时检查 feePackageId 有效 + packageName 非空)
|
||||
- `loadApplicationToForm()` (line 2000): 使用 `item.feePackageId != null || item.itemName?.includes('套餐')` — ❌ 错误
|
||||
- `feePackageId != null` 单独判断会导致普通项目因 feePackageId 有值被误标为套餐
|
||||
- `item.itemName?.includes('套餐')` 更是直接按名称文字判断,极不准确
|
||||
- 影响位置:
|
||||
- 检验项目选择区(line 566):`<el-tag v-if="item.isPackage">套餐</el-tag>`
|
||||
- 已选项目列表(line 617):`<el-tag v-if="item.isPackage">套餐</el-tag>`
|
||||
- 检验信息详情表格(line 448):`<el-tag v-if="scope.row.isPackage">套餐</el-tag>`
|
||||
- **修复方案**:将 `loadApplicationToForm()` 中的 `isPackage` 判定统一为与 `loadCategoryItems()` 一致的逻辑
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 修复1:执行时间默认填充
|
||||
- 文件:`inspectionApplication.vue`
|
||||
- 位置:`initData()` 函数,在已有患者信息赋值后添加 `formData.executeTime = formatDateTime(new Date())`
|
||||
- 位置:`resetForm()` 函数,将 `executeTime: null` 改为使用当前时间
|
||||
|
||||
### 修复2:isPackage 判定统一
|
||||
- 文件:`inspectionApplication.vue`
|
||||
- 位置:`loadApplicationToForm()` 函数 line 2000
|
||||
- 旧代码:`const isPackage = item.feePackageId != null || item.itemName?.includes('套餐')`
|
||||
- 新代码:`const isPackage = item.feePackageId != null && item.feePackageId !== '' && item.feePackageId !== 'null' && item.packageName`
|
||||
|
||||
## 验收标准
|
||||
1. 新增检验申请单时,执行时间字段自动填充当前系统时间(YYYY-MM-DD HH:mm:ss 格式)
|
||||
2. 检验项目列表中,只有真正的套餐项目前显示"套餐"标签,普通项目不显示
|
||||
3. 就诊卡号在有患者信息时正常显示
|
||||
44
bug444_analysis.md
Normal file
44
bug444_analysis.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Bug #444 分析报告
|
||||
|
||||
## Bug 描述
|
||||
【手术管理-门诊手术安排】生成临时医嘱界面,"已引用计费药品"列表未正常显示药品详细名称信息,且错误地带出了非药品类的计费信息(如手术诊疗项目"小腿烧伤扩创交腿皮瓣修复术"、检查项目"心脏彩色多普勒超声")。
|
||||
|
||||
## 根因分析
|
||||
|
||||
### 数据流
|
||||
1. 用户点击"医嘱"按钮 → `handleMedicalAdvice()` → 调用 `getPrescriptionList()` 获取计费数据
|
||||
2. 用户对数据进行过滤后展示在"已引用计费药品"列表
|
||||
3. 用户点击"引用计费"按钮 → `handleQuoteBilling()` → 再次调用 `getPrescriptionList()` 获取最新计费数据
|
||||
|
||||
### 根因定位
|
||||
**`handleQuoteBilling()` 方法(index.vue:1866-1877)缺少非药品关键词过滤逻辑。**
|
||||
|
||||
`handleMedicalAdvice()` 中有两层过滤:
|
||||
1. `adviceType !== 1` 过滤(只保留药品类型)
|
||||
2. **关键词排除过滤**(排除名称中包含"术"、"超声"、"检查"等非药品关键词的项目)
|
||||
|
||||
但 `handleQuoteBilling()` 中只有第一层过滤(`adviceType !== 1`),**缺少关键词排除过滤**。
|
||||
|
||||
当后端返回的计费数据中某些非药品项目被错误标注为 `adviceType=1` 时:
|
||||
- `handleMedicalAdvice()` 能通过关键词过滤排除这些项目
|
||||
- `handleQuoteBilling()` 无法排除,导致非药品项目出现在"已引用计费药品"列表中
|
||||
|
||||
### 代码对比
|
||||
|
||||
| 过滤条件 | handleMedicalAdvice (L1576-1597) | handleQuoteBilling (L1866-1877) |
|
||||
|---------|:---:|:---:|
|
||||
| encounterId 匹配 | ✓ | ✓ |
|
||||
| adviceType === 1 | ✓ | ✓ |
|
||||
| 名称非空 | ✓ | ✓ |
|
||||
| **关键词排除** | ✓ **有** | ✗ **缺失** |
|
||||
| requestId 过滤 | ✓ | ✓ |
|
||||
|
||||
## 修复方案
|
||||
|
||||
在 `handleQuoteBilling()` 方法的过滤逻辑中,添加与 `handleMedicalAdvice()` 一致的关键词排除逻辑:
|
||||
|
||||
```javascript
|
||||
// 🔧 修复 Bug #444: 排除名称中包含手术/检查/诊疗关键词的非药品项目
|
||||
const excludedKeywords = ['术', '超声', '多普勒', '检查', '检验', '彩超', 'X线', 'CT', 'MRI', '扫描', '造影'];
|
||||
if (excludedKeywords.some(kw => medicineName.includes(kw))) return false;
|
||||
```
|
||||
@@ -5,37 +5,39 @@
|
||||
|
||||
## 根因定位
|
||||
|
||||
**核心问题在 `OrganizationLocationAppServiceImpl.java:161-174`**
|
||||
**核心问题在 `OrganizationLocationAppServiceImpl.java:161-162`**
|
||||
|
||||
时间冲突检测的查询逻辑存在两个缺陷:
|
||||
时间冲突检测使用了 `getOrgLocListByActivityDefinitionId()` 跨科室查询同一诊疗定义下的**所有**科室配置记录。
|
||||
|
||||
### 缺陷:跨科室误报冲突
|
||||
|
||||
### 缺陷1:查询范围过窄
|
||||
```java
|
||||
// 只查同一科室 + 同一诊疗的记录
|
||||
getOrgLocListByOrgIdAndActivityDefinitionId(orgLoc.getOrganizationId(), orgLoc.getActivityDefinitionId());
|
||||
// 修复前:查询同一诊疗的所有科室配置(跨科室)
|
||||
organizationLocationService.getOrgLocListByActivityDefinitionId(orgLoc.getActivityDefinitionId());
|
||||
```
|
||||
只查询**同一科室**的记录。如果同一诊疗项目在其他科室已有配置且时间重叠,不会被当前查询检测到。但系统本应阻止同一诊疗在多个科室同时段执行。
|
||||
|
||||
### 缺陷2:"未知科室"错误提示
|
||||
该查询返回**所有科室**中同一诊疗项目的配置记录。当其他科室(非当前操作科室)已配置了相同诊疗且时间重叠时,会被误判为冲突。
|
||||
|
||||
"执行科室配置"的业务语义是:为某个科室配置它可执行的诊疗项目及时段。不同科室配置同一诊疗的不同时段是完全合理的(如检验科 08:00-12:00,放射科 14:00-18:00)。跨科室时间重叠不应视为冲突。
|
||||
|
||||
### 附带缺陷:"未知科室"错误提示
|
||||
当冲突记录关联的科室被软删除(`delete_flag='1'`)时,`organizationService.getById()` 受 `@TableLogic` 注解影响查不到该科室,返回 null,错误提示变成"与未知科室时间冲突"。
|
||||
|
||||
数据库验证发现确实存在软删除科室的组织位置记录(内科门诊、上海学校医院、信息科等,共9条)。
|
||||
|
||||
### 数据流
|
||||
|
||||
1. 前端选择科室 → 点击"添加新项目" → 填写诊疗和时间 → 点击"保存"
|
||||
2. 后端 `addOrEditOrgLoc()` 接收请求
|
||||
3. 查询现有冲突记录(**当前只查同科室**)
|
||||
4. 对冲突记录检查时间重叠
|
||||
5. 查找冲突科室名称 → 若科室被软删除则返回 null → "未知科室"
|
||||
|
||||
## 修复方案
|
||||
|
||||
1. **修改冲突检测范围**:查询同一 `activityDefinitionId` 的所有记录(跨科室检测),而非仅限当前科室
|
||||
2. **优雅处理"未知科室"**:当 `getById` 返回 null 时,使用 "已删除科室( ID )" 替代 "未知科室",提供更有用的信息
|
||||
3. **新增 Service 方法**:`getOrgLocListByActivityDefinitionId(Long activityDefinitionId)` 用于按诊疗定义查询所有记录
|
||||
**修改冲突检测范围**:将 `getOrgLocListByActivityDefinitionId` 改为 `getOrgLocListByOrgIdAndActivityDefinitionId`,仅检测**同一科室内**的时间冲突。
|
||||
|
||||
## 涉及文件
|
||||
- `openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationLocationAppServiceImpl.java`
|
||||
- `openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/IOrganizationLocationService.java`
|
||||
- `openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/impl/OrganizationLocationServiceImpl.java`
|
||||
## 修复结果
|
||||
|
||||
**修复状态**: ✅ 成功
|
||||
|
||||
**改动行数**: +3/-1(`OrganizationLocationAppServiceImpl.java`)
|
||||
|
||||
**变更内容**:
|
||||
```diff
|
||||
-organizationLocationService.getOrgLocListByActivityDefinitionId(orgLoc.getActivityDefinitionId());
|
||||
+organizationLocationService.getOrgLocListByOrgIdAndActivityDefinitionId(orgLoc.getOrganizationId(),
|
||||
+ orgLoc.getActivityDefinitionId());
|
||||
```
|
||||
|
||||
编译验证通过。
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.core.framework.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
@@ -8,6 +11,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.TimeZone;
|
||||
@@ -23,6 +27,36 @@ import java.util.TimeZone;
|
||||
// 指定要扫描的Mapper类的包的路径
|
||||
@MapperScan({"com.core.**.mapper", "com.openhis.**.mapper"})
|
||||
public class ApplicationConfig {
|
||||
|
||||
/** 支持多种日期格式的反序列化器 */
|
||||
private static final JsonDeserializer<LocalDateTime> LOCAL_DATE_TIME_DESERIALIZER = new JsonDeserializer<LocalDateTime>() {
|
||||
private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
private static final DateTimeFormatter SIMPLE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final DateTimeFormatter SLASH_FORMATTER = DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
String text = p.getText();
|
||||
if (text == null || text.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// 去除时区后缀 Z/z 和偏移量 +HH:MM/+HHMM(LocalDateTime 不含时区信息)
|
||||
String cleaned = text.replaceAll("[Zz]$", "").replaceAll("[+-]\\d{2}:?\\d{2}$", "");
|
||||
// 尝试 ISO 8601 格式(yyyy-MM-ddTHH:mm:ss.SSS)
|
||||
try {
|
||||
return LocalDateTime.parse(cleaned, ISO_FORMATTER);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
// 尝试简单格式(yyyy-MM-dd HH:mm:ss)
|
||||
try {
|
||||
return LocalDateTime.parse(cleaned, SIMPLE_FORMATTER);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
// 尝试斜杠格式(yyyy/M/d HH:mm:ss)
|
||||
return LocalDateTime.parse(cleaned, SLASH_FORMATTER);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 时区配置
|
||||
*/
|
||||
@@ -34,7 +68,9 @@ public class ApplicationConfig {
|
||||
// 设置日期格式为 yyyy/M/d HH:mm:ss,支持多种格式反序列化
|
||||
builder.simpleDateFormat("yyyy/M/d HH:mm:ss");
|
||||
// 添加JavaTimeModule支持,用于LocalDateTime
|
||||
builder.modules(new JavaTimeModule());
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
|
||||
builder.modules(javaTimeModule);
|
||||
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss")));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -158,8 +158,10 @@ public class OrganizationLocationAppServiceImpl implements IOrganizationLocation
|
||||
? activityDefinitionMapper.selectById(activityDefinitionId) : null;
|
||||
String activityName = activityDef != null ? activityDef.getName() : "";
|
||||
|
||||
// Only check for time conflicts within the same department
|
||||
List<OrganizationLocation> organizationLocationList =
|
||||
organizationLocationService.getOrgLocListByActivityDefinitionId(orgLoc.getActivityDefinitionId());
|
||||
organizationLocationService.getOrgLocListByOrgIdAndActivityDefinitionId(orgLoc.getOrganizationId(),
|
||||
orgLoc.getActivityDefinitionId());
|
||||
organizationLocationList = (orgLoc.getId() != null)
|
||||
? organizationLocationList.stream().filter(item -> !orgLoc.getId().equals(item.getId())).toList()
|
||||
: organizationLocationList;
|
||||
@@ -169,11 +171,9 @@ public class OrganizationLocationAppServiceImpl implements IOrganizationLocation
|
||||
if (DateTimeUtils.isOverlap(organizationLocation.getStartTime(), organizationLocation.getEndTime(),
|
||||
orgLoc.getStartTime(), orgLoc.getEndTime())) {
|
||||
Organization org = organizationService.getById(organizationLocation.getOrganizationId());
|
||||
if (org == null) {
|
||||
continue;
|
||||
}
|
||||
String organizationName = org != null ? org.getName() : ("科室[" + organizationLocation.getOrganizationId() + "]已删除");
|
||||
return R.fail("当前诊疗:" + activityName + CommonConstants.Common.DASH + orgLoc.getStartTime()
|
||||
+ CommonConstants.Common.DASH + orgLoc.getEndTime() + "与" + org.getName() + "时间冲突");
|
||||
+ CommonConstants.Common.DASH + orgLoc.getEndTime() + "与" + organizationName + "时间冲突");
|
||||
}
|
||||
|
||||
if (orgLocQueryDto.getId() != null) {
|
||||
|
||||
@@ -215,6 +215,9 @@ public class SurgicalScheduleAppServiceImpl implements ISurgicalScheduleAppServi
|
||||
if (surgery != null) {
|
||||
surgery.setStatusEnum(1); // 1 = 已排期
|
||||
surgery.setUpdateTime(new Date());
|
||||
// Bug #558: 手术安排时同步写入手术室确认时间和确认人
|
||||
surgery.setOperatingRoomConfirmTime(new Date());
|
||||
surgery.setOperatingRoomConfirmUser(loginUser.getUsername());
|
||||
|
||||
// 填充缺失的申请科室和主刀医生名称
|
||||
fillSurgeryMissingNames(surgery);
|
||||
|
||||
@@ -36,4 +36,7 @@ public class PerformInfoDto {
|
||||
/** 分组id */
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long groupId;
|
||||
|
||||
/** 退回原因 */
|
||||
private String backReason;
|
||||
}
|
||||
|
||||
@@ -147,6 +147,6 @@ public interface IDoctorStationAdviceAppService {
|
||||
*/
|
||||
IPage<SurgeryItemDto> getSurgeryPage(Long organizationId, Integer pageNo, Integer pageSize, String searchKey);
|
||||
|
||||
IPage<SurgeryItemDto> getExaminationPage(Long organizationId, Integer pageNo, Integer pageSize, String searchKey);
|
||||
IPage<SurgeryItemDto> getExaminationPage(Long organizationId, Integer pageNo, Integer pageSize, String searchKey, String categoryCode);
|
||||
|
||||
}
|
||||
|
||||
@@ -2286,7 +2286,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
log.info("BugFix: signOffAdvice - 签退所有请求,状态改为待签发, requestIdList={}", requestIdList);
|
||||
|
||||
// 尝试签退药品请求(只有存在的才会更新)
|
||||
iMedicationRequestService.updateDraftStatusBatch(requestIdList, null, null);
|
||||
iMedicationRequestService.updateDraftStatusBatch(requestIdList, null, null, null);
|
||||
// 尝试签退耗材请求(只有存在的才会更新)
|
||||
iDeviceRequestService.updateDraftStatusBatch(requestIdList);
|
||||
// 尝试签退诊疗请求(只有存在的才会更新)
|
||||
@@ -2343,21 +2343,52 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
.map(UpdateGroupDto::getRequestId).collect(Collectors.toList());
|
||||
|
||||
if (!idsToSetNull.isEmpty()) {
|
||||
// 创建更新条件
|
||||
UpdateWrapper<MedicationRequest> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.set("group_id", null).in("id", idsToSetNull);
|
||||
// 对三个表都执行 group_id/group_no 置空(哪个表有该 id 就更新哪个)
|
||||
UpdateWrapper<MedicationRequest> medUpdateWrapper = new UpdateWrapper<>();
|
||||
medUpdateWrapper.set("group_id", null).in("id", idsToSetNull);
|
||||
iMedicationRequestService.update(medUpdateWrapper);
|
||||
|
||||
// 执行更新
|
||||
iMedicationRequestService.update(updateWrapper);
|
||||
UpdateWrapper<ServiceRequest> srvUpdateWrapper = new UpdateWrapper<>();
|
||||
srvUpdateWrapper.set("group_id", null).in("id", idsToSetNull);
|
||||
iServiceRequestService.update(srvUpdateWrapper);
|
||||
|
||||
// DeviceRequest 使用 group_no(String 类型)
|
||||
UpdateWrapper<DeviceRequest> devUpdateWrapper = new UpdateWrapper<>();
|
||||
devUpdateWrapper.set("group_no", null).in("id", idsToSetNull);
|
||||
iDeviceRequestService.update(devUpdateWrapper);
|
||||
}
|
||||
|
||||
// 处理非null的情况
|
||||
List<MedicationRequest> medicationRequestList = groupList.stream().filter(dto -> dto.getGroupId() != null)
|
||||
.map(dto -> new MedicationRequest().setId(dto.getRequestId()).setGroupId(dto.getGroupId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!medicationRequestList.isEmpty()) {
|
||||
iMedicationRequestService.saveOrUpdateBatch(medicationRequestList);
|
||||
// 处理 groupId 非 null 的情况:按实际所属表分别更新
|
||||
List<UpdateGroupDto> nonNullGroupList = groupList.stream()
|
||||
.filter(dto -> dto.getGroupId() != null).collect(Collectors.toList());
|
||||
if (!nonNullGroupList.isEmpty()) {
|
||||
for (UpdateGroupDto dto : nonNullGroupList) {
|
||||
Long reqId = dto.getRequestId();
|
||||
Long grpId = dto.getGroupId();
|
||||
// 先尝试药品表(med_medication_request → group_id)
|
||||
MedicationRequest medReq = iMedicationRequestService.getById(reqId);
|
||||
if (medReq != null) {
|
||||
UpdateWrapper<MedicationRequest> uw = new UpdateWrapper<>();
|
||||
uw.set("group_id", grpId).eq("id", reqId);
|
||||
iMedicationRequestService.update(uw);
|
||||
continue;
|
||||
}
|
||||
// 再尝试诊疗表(wor_service_request → group_id)
|
||||
ServiceRequest srvReq = iServiceRequestService.getById(reqId);
|
||||
if (srvReq != null) {
|
||||
UpdateWrapper<ServiceRequest> uw = new UpdateWrapper<>();
|
||||
uw.set("group_id", grpId).eq("id", reqId);
|
||||
iServiceRequestService.update(uw);
|
||||
continue;
|
||||
}
|
||||
// 最后尝试耗材表(wor_device_request → group_no, String 类型)
|
||||
DeviceRequest devReq = iDeviceRequestService.getById(reqId);
|
||||
if (devReq != null) {
|
||||
UpdateWrapper<DeviceRequest> uw = new UpdateWrapper<>();
|
||||
uw.set("group_no", grpId != null ? grpId.toString() : null).eq("id", reqId);
|
||||
iDeviceRequestService.update(uw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2566,12 +2597,13 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<SurgeryItemDto> getExaminationPage(Long organizationId, Integer pageNo, Integer pageSize, String searchKey) {
|
||||
public IPage<SurgeryItemDto> getExaminationPage(Long organizationId, Integer pageNo, Integer pageSize, String searchKey, String categoryCode) {
|
||||
IPage<SurgeryItemDto> result = doctorStationAdviceAppMapper.getExaminationPage(
|
||||
new Page<>(pageNo, pageSize),
|
||||
PublicationStatus.ACTIVE.getValue(),
|
||||
organizationId,
|
||||
searchKey);
|
||||
searchKey,
|
||||
categoryCode);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
Emr emr = new Emr();
|
||||
BeanUtils.copyProperties(patientEmrDto, emr);
|
||||
String contextStr = patientEmrDto.getContextJson().toString();
|
||||
Emr patientEmr = emrService.getOne(new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, emr.getEncounterId()));
|
||||
Emr patientEmr = emrService.getOne(new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, emr.getEncounterId()).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false);
|
||||
boolean saveSuccess;
|
||||
// 如果已经保存病历,再次保存走更新
|
||||
if (patientEmr != null) {
|
||||
@@ -126,6 +126,10 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
*/
|
||||
@Override
|
||||
public R<?> getPatientEmrHistory(PatientEmrDto patientEmrDto, Integer pageNo, Integer pageSize) {
|
||||
// 校验参数
|
||||
if (patientEmrDto.getPatientId() == null) {
|
||||
return R.ok(new Page<>(pageNo, pageSize));
|
||||
}
|
||||
Page<Emr> page = emrService.page(new Page<>(pageNo, pageSize),
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getPatientId, patientEmrDto.getPatientId()));
|
||||
return R.ok(page);
|
||||
@@ -140,8 +144,12 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
*/
|
||||
@Override
|
||||
public R<?> getEmrDetail(Long encounterId) {
|
||||
// 校验参数
|
||||
if (encounterId == null) {
|
||||
return R.ok(null);
|
||||
}
|
||||
// 先查询门诊病历(emr表)
|
||||
Emr emrDetail = emrService.getOne(new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId));
|
||||
Emr emrDetail = emrService.getOne(new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false);
|
||||
if (emrDetail != null) {
|
||||
return R.ok(emrDetail);
|
||||
}
|
||||
@@ -151,7 +159,8 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
new LambdaQueryWrapper<DocRecord>()
|
||||
.eq(DocRecord::getEncounterId, encounterId)
|
||||
.orderByDesc(DocRecord::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
.last("LIMIT 1"),
|
||||
false
|
||||
);
|
||||
if (docRecord != null) {
|
||||
// 住院病历存在,也返回数据
|
||||
@@ -240,7 +249,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
for (Encounter encounter : encounters) {
|
||||
// 检查该就诊记录是否已经有病历
|
||||
Emr existingEmr = emrService.getOne(
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounter.getId())
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounter.getId()).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false
|
||||
);
|
||||
|
||||
// 检查该就诊是否由指定医生负责
|
||||
@@ -298,7 +307,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
|
||||
public R<?> checkNeedWriteEmr(Long encounterId) {
|
||||
// 检查该就诊记录是否已经有病历
|
||||
Emr existingEmr = emrService.getOne(
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId)
|
||||
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false
|
||||
);
|
||||
|
||||
// 如果没有病历,则需要写病历
|
||||
|
||||
@@ -226,8 +226,9 @@ public class DoctorStationAdviceController {
|
||||
@RequestParam(value = "organizationId", required = false) Long organizationId,
|
||||
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(value = "pageSize", defaultValue = "500") Integer pageSize,
|
||||
@RequestParam(value = "searchKey", defaultValue = "") String searchKey) {
|
||||
return R.ok(iDoctorStationAdviceAppService.getExaminationPage(organizationId, pageNo, pageSize, searchKey));
|
||||
@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
|
||||
@RequestParam(value = "categoryCode", defaultValue = "23") String categoryCode) {
|
||||
return R.ok(iDoctorStationAdviceAppService.getExaminationPage(organizationId, pageNo, pageSize, searchKey, categoryCode));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -121,6 +121,11 @@ public class RequestBaseDto {
|
||||
* 请求状态
|
||||
*/
|
||||
private Integer statusEnum;
|
||||
|
||||
/**
|
||||
* 退回原因
|
||||
*/
|
||||
private String reasonText;
|
||||
private String statusEnum_enumText;
|
||||
|
||||
/**
|
||||
|
||||
@@ -203,6 +203,7 @@ public interface DoctorStationAdviceAppMapper {
|
||||
IPage<SurgeryItemDto> getExaminationPage(@Param("page") Page<SurgeryItemDto> page,
|
||||
@Param("statusEnum") Integer statusEnum,
|
||||
@Param("organizationId") Long organizationId,
|
||||
@Param("searchKey") String searchKey);
|
||||
@Param("searchKey") String searchKey,
|
||||
@Param("categoryCode") String categoryCode);
|
||||
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.*;
|
||||
import java.util.*;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -232,38 +234,48 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
}
|
||||
}
|
||||
|
||||
// 手动处理前端传来的执行条件
|
||||
if (exeStatus != null) {
|
||||
// 处理执行记录状态
|
||||
for (InpatientAdviceDto inpatientAdvice : inpatientAdviceList) {
|
||||
List<PerformRecordDto> performRecordList = procedureRecordGroup.get(inpatientAdvice.getRequestId());
|
||||
List<PerformRecordDto> exePerformRecordList = new ArrayList<>();
|
||||
List<PerformRecordDto> cancelPerformRecordList = new ArrayList<>();
|
||||
List<PerformRecordDto> stopPerformRecordList = new ArrayList<>();
|
||||
if (performRecordList != null && !performRecordList.isEmpty()) {
|
||||
// 按时间分组,处理每个时间点的多条记录
|
||||
Map<String, List<PerformRecordDto>> recordsByTime = performRecordList.stream()
|
||||
.collect(Collectors.groupingBy(record -> record.getOccurrenceTime().toString()));
|
||||
for (Map.Entry<String, List<PerformRecordDto>> entry : recordsByTime.entrySet()) {
|
||||
List<PerformRecordDto> records = entry.getValue();
|
||||
// 按操作顺序排序
|
||||
records.sort(Comparator.comparing(PerformRecordDto::getCreateTime));
|
||||
// 取最后一条记录,最终状态由最后一次操作决定
|
||||
PerformRecordDto lastRecord = records.get(records.size() - 1);
|
||||
if (EventStatus.COMPLETED.getValue().equals(lastRecord.getStatusEnum())) {
|
||||
exePerformRecordList.add(lastRecord);
|
||||
} else if (EventStatus.CANCEL.getValue().equals(lastRecord.getStatusEnum())) {
|
||||
cancelPerformRecordList.add(lastRecord);
|
||||
} else if (EventStatus.STOPPED.getValue().equals(lastRecord.getStatusEnum())) {
|
||||
stopPerformRecordList.add(lastRecord);
|
||||
}
|
||||
// 为所有医嘱计算执行记录状态(所有页签都需要展示执行进度)
|
||||
for (InpatientAdviceDto inpatientAdvice : inpatientAdviceList) {
|
||||
List<PerformRecordDto> performRecordList = procedureRecordGroup.get(inpatientAdvice.getRequestId());
|
||||
List<PerformRecordDto> exePerformRecordList = new ArrayList<>();
|
||||
List<PerformRecordDto> cancelPerformRecordList = new ArrayList<>();
|
||||
List<PerformRecordDto> stopPerformRecordList = new ArrayList<>();
|
||||
if (performRecordList != null && !performRecordList.isEmpty()) {
|
||||
// 按时间分组,处理每个时间点的多条记录
|
||||
Map<String, List<PerformRecordDto>> recordsByTime = performRecordList.stream()
|
||||
.collect(Collectors.groupingBy(record -> record.getOccurrenceTime().toString()));
|
||||
for (Map.Entry<String, List<PerformRecordDto>> entry : recordsByTime.entrySet()) {
|
||||
List<PerformRecordDto> records = entry.getValue();
|
||||
// 按操作顺序排序
|
||||
records.sort(Comparator.comparing(PerformRecordDto::getCreateTime));
|
||||
// 取最后一条记录,最终状态由最后一次操作决定
|
||||
PerformRecordDto lastRecord = records.get(records.size() - 1);
|
||||
if (EventStatus.COMPLETED.getValue().equals(lastRecord.getStatusEnum())) {
|
||||
exePerformRecordList.add(lastRecord);
|
||||
} else if (EventStatus.CANCEL.getValue().equals(lastRecord.getStatusEnum())) {
|
||||
cancelPerformRecordList.add(lastRecord);
|
||||
} else if (EventStatus.STOPPED.getValue().equals(lastRecord.getStatusEnum())) {
|
||||
stopPerformRecordList.add(lastRecord);
|
||||
}
|
||||
}
|
||||
inpatientAdvice.setExePerformRecordList(exePerformRecordList)
|
||||
.setCancelPerformRecordList(cancelPerformRecordList)
|
||||
.setStopPerformRecordList(stopPerformRecordList);
|
||||
}
|
||||
inpatientAdvice.setExePerformRecordList(exePerformRecordList)
|
||||
.setCancelPerformRecordList(cancelPerformRecordList)
|
||||
.setStopPerformRecordList(stopPerformRecordList);
|
||||
// 计算综合执行状态文本
|
||||
if (!exePerformRecordList.isEmpty()) {
|
||||
inpatientAdvice.setOverallStatusText("已执行");
|
||||
} else if (!cancelPerformRecordList.isEmpty()) {
|
||||
inpatientAdvice.setOverallStatusText("已取消执行");
|
||||
} else if (!stopPerformRecordList.isEmpty()) {
|
||||
inpatientAdvice.setOverallStatusText("已停止");
|
||||
} else {
|
||||
inpatientAdvice.setOverallStatusText(inpatientAdvice.getRequestStatus_enumText());
|
||||
}
|
||||
}
|
||||
|
||||
// 手动处理前端传来的执行条件
|
||||
if (exeStatus != null) {
|
||||
// 根据执行状态过滤医嘱列表
|
||||
List<InpatientAdviceDto> filteredList = new ArrayList<>();
|
||||
if (EventStatus.COMPLETED.getValue().equals(exeStatus)) {
|
||||
@@ -359,6 +371,29 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
medRequestList.add(item);
|
||||
}
|
||||
}
|
||||
// 校验医嘱是否已执行,已执行的医嘱不允许退回
|
||||
List<PerformInfoDto> allRequestList = new ArrayList<>();
|
||||
allRequestList.addAll(serviceRequestList);
|
||||
allRequestList.addAll(medRequestList);
|
||||
if (!allRequestList.isEmpty()) {
|
||||
// 按requestTable分组查询执行记录
|
||||
Map<String, List<Long>> requestTableIdMap = allRequestList.stream()
|
||||
.collect(Collectors.groupingBy(PerformInfoDto::getRequestTable,
|
||||
Collectors.mapping(PerformInfoDto::getRequestId, Collectors.toList())));
|
||||
for (Map.Entry<String, List<Long>> entry : requestTableIdMap.entrySet()) {
|
||||
String requestTable = entry.getKey();
|
||||
List<Long> requestIds = entry.getValue();
|
||||
List<Procedure> executedProcedures = procedureService.list(
|
||||
new LambdaQueryWrapper<Procedure>()
|
||||
.in(Procedure::getRequestId, requestIds)
|
||||
.eq(Procedure::getRequestTable, requestTable)
|
||||
.eq(Procedure::getStatusEnum, EventStatus.COMPLETED.getValue())
|
||||
.eq(Procedure::getCategoryEnum, ProcedureCategory.INPATIENT_ADVICE.getValue()));
|
||||
if (!executedProcedures.isEmpty()) {
|
||||
return R.fail("所选医嘱中存在已执行的医嘱,请先在【医嘱执行】界面取消执行后再退回");
|
||||
}
|
||||
}
|
||||
}
|
||||
// 校验药品医嘱是否已发药,已发药的医嘱不允许退回
|
||||
if (!medRequestList.isEmpty()) {
|
||||
List<Long> medReqIds = medRequestList.stream().map(PerformInfoDto::getRequestId).toList();
|
||||
@@ -372,15 +407,21 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
}
|
||||
Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
|
||||
Date checkDate = new Date();
|
||||
// 从请求中提取退回原因(所有项目共享同一原因)
|
||||
String backReason = performInfoList.stream()
|
||||
.map(PerformInfoDto::getBackReason)
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (!serviceRequestList.isEmpty()) {
|
||||
// 更新服务请求状态待发送
|
||||
serviceRequestService.updateDraftStatus(
|
||||
serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
|
||||
serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate, backReason);
|
||||
}
|
||||
if (!medRequestList.isEmpty()) {
|
||||
// 更新药品请求状态待发送
|
||||
medicationRequestService.updateDraftStatusBatch(
|
||||
medRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
|
||||
medRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate, backReason);
|
||||
}
|
||||
return R.ok(null, "退回成功");
|
||||
}
|
||||
@@ -524,7 +565,10 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
// 处理长期已发放的药品
|
||||
if (!longMedDispensedList.isEmpty()) {
|
||||
// 生成退药单
|
||||
this.creatRefundMedicationList(tempMedDispensedList, procedureIdMap);
|
||||
this.creatRefundMedicationList(longMedDispensedList, procedureIdMap);
|
||||
// 药品退药请求状态变更(待退药)
|
||||
medicationRequestService.updateCancelledStatusBatch(
|
||||
longMedDispensedList.stream().map(MedicationDispense::getMedReqId).toList(), null, null);
|
||||
}
|
||||
// 处理临时已发放药品
|
||||
if (!tempMedDispensedList.isEmpty()) {
|
||||
|
||||
@@ -101,6 +101,9 @@ public class InpatientAdviceDto {
|
||||
private Integer requestStatus;
|
||||
private String requestStatus_enumText;
|
||||
|
||||
/** 综合执行状态(结合请求状态和执行记录计算) */
|
||||
private String overallStatusText;
|
||||
|
||||
/** 是否皮试 */
|
||||
private Integer skinTestFlag;
|
||||
private String skinTestFlag_enumText;
|
||||
|
||||
@@ -256,7 +256,7 @@ public class OutpatientInfusionAppServiceImpl implements IOutpatientInfusionAppS
|
||||
}
|
||||
boolean result = serviceRequestService.updateCancelledStatus(serviceReqId, now, practitionerId, orgId);
|
||||
// 更新主服务请求状态为待执行
|
||||
serviceRequestService.updateDraftStatus(List.of(serviceRequest.getBasedOnId()), null, null);
|
||||
serviceRequestService.updateDraftStatus(List.of(serviceRequest.getBasedOnId()), null, null, null);
|
||||
if (result) {
|
||||
// 判断是否全部取消执行
|
||||
boolean exists = serviceRequestMapper.exists(new LambdaQueryWrapper<ServiceRequest>()
|
||||
|
||||
@@ -133,47 +133,13 @@ public class PatientInformationServiceImpl implements IPatientInformationService
|
||||
@Override
|
||||
public IPage<PatientBaseInfoDto> getPatientInfo(PatientBaseInfoDto patientBaseInfoDto, String searchKey,
|
||||
Integer pageNo, Integer pageSize, HttpServletRequest request) {
|
||||
// 获取登录者信息
|
||||
// 构建基础查询条件
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Long userId = loginUser.getUserId();
|
||||
Integer tenantId = loginUser.getTenantId().intValue();
|
||||
|
||||
// 先构建基础查询条件
|
||||
QueryWrapper<PatientBaseInfoDto> queryWrapper = HisQueryUtils.buildQueryWrapper(
|
||||
patientBaseInfoDto, searchKey, new HashSet<>(Arrays.asList(CommonConstants.FieldName.Name,
|
||||
CommonConstants.FieldName.BusNo, CommonConstants.FieldName.PyStr, CommonConstants.FieldName.WbStr)),
|
||||
request);
|
||||
|
||||
// 检查是否是精确ID查询(从门诊挂号页面跳转时使用)
|
||||
boolean hasExactIdQuery = (patientBaseInfoDto.getId() != null);
|
||||
|
||||
// 只有非精确ID查询时,才添加医生患者过滤条件
|
||||
if (!hasExactIdQuery) {
|
||||
// 查询当前用户对应的医生信息
|
||||
LambdaQueryWrapper<com.openhis.administration.domain.Practitioner> practitionerQuery = new LambdaQueryWrapper<>();
|
||||
practitionerQuery.eq(com.openhis.administration.domain.Practitioner::getUserId, userId);
|
||||
// 使用list()避免TooManyResultsException异常,然后取第一个记录
|
||||
List<com.openhis.administration.domain.Practitioner> practitionerList = practitionerService.list(practitionerQuery);
|
||||
com.openhis.administration.domain.Practitioner practitioner = practitionerList != null && !practitionerList.isEmpty() ? practitionerList.get(0) : null;
|
||||
|
||||
// 如果当前用户是医生,添加医生患者过滤条件
|
||||
if (practitioner != null) {
|
||||
// 查询该医生作为接诊医生(ADMITTER, code="1")和挂号医生(REGISTRATION_DOCTOR, code="12")的所有就诊记录的患者ID
|
||||
List<Long> doctorPatientIds = patientManageMapper.getPatientIdsByPractitionerId(
|
||||
practitioner.getId(),
|
||||
Arrays.asList(ParticipantType.ADMITTER.getCode(), ParticipantType.REGISTRATION_DOCTOR.getCode()),
|
||||
tenantId);
|
||||
|
||||
if (doctorPatientIds != null && !doctorPatientIds.isEmpty()) {
|
||||
// 添加患者ID过滤条件 - 注意:这里使用列名而不是表别名
|
||||
queryWrapper.in("id", doctorPatientIds);
|
||||
} else {
|
||||
// 如果没有相关患者,返回空结果
|
||||
queryWrapper.eq("id", -1); // 设置一个不存在的ID
|
||||
}
|
||||
}
|
||||
// 如果不是医生,查询所有患者
|
||||
}
|
||||
|
||||
IPage<PatientBaseInfoDto> patientInformationPage
|
||||
= patientManageMapper.getPatientPage(new Page<>(pageNo, pageSize), queryWrapper);
|
||||
|
||||
@@ -627,7 +627,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
||||
longServiceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
|
||||
longServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
|
||||
longServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
|
||||
longServiceRequest.setOrgId(regAdviceSaveDto.getPositionId()); // 执行科室
|
||||
longServiceRequest.setOrgId(regAdviceSaveDto.getEffectiveOrgId()); // 执行科室
|
||||
longServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
|
||||
longServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
|
||||
longServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
|
||||
@@ -678,7 +678,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
||||
tempServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
|
||||
tempServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
|
||||
tempServiceRequest.setAuthoredTime(curDate); // 请求签发时间
|
||||
tempServiceRequest.setOrgId(regAdviceSaveDto.getPositionId()); // 执行科室
|
||||
tempServiceRequest.setOrgId(regAdviceSaveDto.getEffectiveOrgId()); // 执行科室
|
||||
tempServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
|
||||
tempServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
|
||||
tempServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
|
||||
@@ -1016,7 +1016,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
|
||||
}
|
||||
if (!medicineRequestIds.isEmpty()) {
|
||||
// 根据请求id更新请求状态
|
||||
iMedicationRequestService.updateDraftStatusBatch(medicineRequestIds, null, null);
|
||||
iMedicationRequestService.updateDraftStatusBatch(medicineRequestIds, null, null, null);
|
||||
}
|
||||
if (!activityRequestIds.isEmpty()) {
|
||||
// 根据请求id更新请求状态
|
||||
|
||||
@@ -10,8 +10,4 @@ import lombok.experimental.Accessors;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class RegAdviceSaveDto extends AdviceSaveDto {
|
||||
|
||||
/** 请求类型 */
|
||||
private Integer categoryEnum;
|
||||
|
||||
}
|
||||
|
||||
@@ -516,6 +516,7 @@
|
||||
T1.patient_id AS patient_id,
|
||||
'med_medication_definition' AS advice_table_name,
|
||||
T1.medication_id AS advice_definition_id
|
||||
, T1.back_reason AS reason_text
|
||||
FROM med_medication_request AS T1
|
||||
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
|
||||
AND T2.delete_flag = '0'
|
||||
@@ -577,6 +578,7 @@
|
||||
T1.patient_id AS patient_id,
|
||||
'med_medication_definition' AS advice_table_name,
|
||||
T3.ID AS advice_definition_id
|
||||
, T2.back_reason AS reason_text
|
||||
FROM adm_charge_item AS T1
|
||||
INNER JOIN med_medication_request AS T2 ON T2.ID = T1.service_id AND T2.delete_flag = '0'
|
||||
LEFT JOIN med_medication_definition AS T3 ON T3.ID = T2.medication_id AND T3.delete_flag = '0'
|
||||
@@ -637,6 +639,7 @@
|
||||
CI.patient_id AS patient_id,
|
||||
'adm_device_definition' AS advice_table_name,
|
||||
CI.product_id AS advice_definition_id
|
||||
, NULL AS reason_text
|
||||
FROM adm_charge_item AS CI
|
||||
LEFT JOIN adm_charge_item_definition CID ON CID.id = CI.definition_id AND CID.delete_flag = '0'
|
||||
LEFT JOIN wor_device_request DR ON DR.id = CI.service_id AND DR.delete_flag = '0'
|
||||
@@ -691,6 +694,7 @@
|
||||
T1.patient_id AS patient_id,
|
||||
'adm_device_definition' AS advice_table_name,
|
||||
T1.device_def_id AS advice_definition_id
|
||||
, NULL AS reason_text
|
||||
FROM wor_device_request AS T1
|
||||
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
|
||||
AND T2.delete_flag = '0'
|
||||
@@ -747,6 +751,7 @@
|
||||
T1.patient_id AS patient_id,
|
||||
'wor_activity_definition' AS advice_table_name,
|
||||
T1.activity_id AS advice_definition_id
|
||||
, T1.reason_text AS reason_text
|
||||
FROM wor_service_request AS T1
|
||||
LEFT JOIN wor_activity_definition AS T2
|
||||
ON T2.ID = T1.activity_id
|
||||
@@ -897,7 +902,7 @@
|
||||
LIMIT #{limit} OFFSET #{offset}
|
||||
</select>
|
||||
|
||||
<!-- 检查项目专用分页查询:仅查检查(23) + 定价,无库存/草稿库存/取药科室等无关逻辑 -->
|
||||
<!-- 检查/检验项目专用分页查询:仅查指定 category_code + 定价,无库存/草稿库存/取药科室等无关逻辑 -->
|
||||
<select id="getExaminationPage" resultType="com.openhis.web.doctorstation.dto.SurgeryItemDto">
|
||||
SELECT DISTINCT ON (t1.ID)
|
||||
t1.ID AS advice_definition_id,
|
||||
@@ -919,7 +924,7 @@
|
||||
ON t3.id = t1.org_id
|
||||
AND t3.delete_flag = '0'
|
||||
WHERE t1.delete_flag = '0'
|
||||
AND t1.category_code = '23'
|
||||
AND t1.category_code = #{categoryCode}
|
||||
<if test="searchKey != null and searchKey != ''">
|
||||
AND (t1.name ILIKE '%' || #{searchKey} || '%' OR t1.py_str ILIKE '%' || #{searchKey} || '%')
|
||||
</if>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.openhis.lab.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
@@ -106,10 +107,12 @@ public class InspectionPackage {
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField("create_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField("update_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/** 删除标志(false-正常,true-删除) */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.openhis.lab.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
@@ -75,10 +76,12 @@ public class InspectionPackageDetail {
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField("create_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField("update_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/** 删除标志(false-正常,true-删除) */
|
||||
|
||||
@@ -111,6 +111,9 @@ public class MedicationRequest extends HisBaseEntity {
|
||||
/** 支持用药信息 */
|
||||
private String supportInfo;
|
||||
|
||||
/** 退回原因 */
|
||||
private String backReason;
|
||||
|
||||
/** 请求开始时间 */
|
||||
private Date reqAuthoredTime;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public interface IMedicationRequestService extends IService<MedicationRequest> {
|
||||
* @param practitionerId 校对人
|
||||
* @param checkDate 校对时间
|
||||
*/
|
||||
void updateDraftStatusBatch(List<Long> requestIdList, Long practitionerId, Date checkDate);
|
||||
void updateDraftStatusBatch(List<Long> requestIdList, Long practitionerId, Date checkDate, String backReason);
|
||||
|
||||
/**
|
||||
* 更新请求状态:取消
|
||||
|
||||
@@ -44,7 +44,7 @@ public class MedicationRequestServiceImpl extends ServiceImpl<MedicationRequestM
|
||||
* @param checkDate 校对时间
|
||||
*/
|
||||
@Override
|
||||
public void updateDraftStatusBatch(List<Long> requestIdList, Long practitionerId, Date checkDate) {
|
||||
public void updateDraftStatusBatch(List<Long> requestIdList, Long practitionerId, Date checkDate, String backReason) {
|
||||
LambdaUpdateWrapper<MedicationRequest> updateWrapper =
|
||||
new LambdaUpdateWrapper<MedicationRequest>().in(MedicationRequest::getId, requestIdList)
|
||||
.set(MedicationRequest::getStatusEnum, RequestStatus.DRAFT.getValue());
|
||||
@@ -54,6 +54,9 @@ public class MedicationRequestServiceImpl extends ServiceImpl<MedicationRequestM
|
||||
if (checkDate != null) {
|
||||
updateWrapper.set(MedicationRequest::getCheckTime, checkDate);
|
||||
}
|
||||
if (backReason != null) {
|
||||
updateWrapper.set(MedicationRequest::getBackReason, backReason);
|
||||
}
|
||||
baseMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,11 +79,13 @@ public class OpSchedule extends HisBaseEntity {
|
||||
private String surgerySite;
|
||||
|
||||
/** 入院时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime admissionTime;
|
||||
|
||||
/** 入手术室时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime entryTime;
|
||||
|
||||
/** 手术室编码 */
|
||||
@@ -142,19 +144,23 @@ public class OpSchedule extends HisBaseEntity {
|
||||
private String assistant3Code;
|
||||
|
||||
/** 手术开始时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/** 手术结束时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/** 麻醉开始时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime anesStart;
|
||||
|
||||
/** 麻醉结束时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime anesEnd;
|
||||
|
||||
/** 手术状态 */
|
||||
|
||||
@@ -93,7 +93,7 @@ public interface IServiceRequestService extends IService<ServiceRequest> {
|
||||
* @param practitionerId 校对人
|
||||
* @param checkDate 校对时间
|
||||
*/
|
||||
void updateDraftStatus(List<Long> serviceRequestIdList, Long practitionerId, Date checkDate);
|
||||
void updateDraftStatus(List<Long> serviceRequestIdList, Long practitionerId, Date checkDate, String backReason);
|
||||
|
||||
/**
|
||||
* 更新服务状态:待发送
|
||||
|
||||
@@ -172,9 +172,15 @@ public class ServiceRequestServiceImpl extends ServiceImpl<ServiceRequestMapper,
|
||||
* @param checkDate 校对时间
|
||||
*/
|
||||
@Override
|
||||
public void updateDraftStatus(List<Long> serviceRequestIdList, Long practitionerId, Date checkDate) {
|
||||
baseMapper.update(new ServiceRequest().setStatusEnum(RequestStatus.DRAFT.getValue())
|
||||
.setPerformerCheckId(SecurityUtils.getLoginUser().getPractitionerId()).setCheckTime(DateUtils.getNowDate()),
|
||||
public void updateDraftStatus(List<Long> serviceRequestIdList, Long practitionerId, Date checkDate, String backReason) {
|
||||
ServiceRequest updateEntity = new ServiceRequest()
|
||||
.setStatusEnum(RequestStatus.DRAFT.getValue())
|
||||
.setPerformerCheckId(SecurityUtils.getLoginUser().getPractitionerId())
|
||||
.setCheckTime(DateUtils.getNowDate());
|
||||
if (backReason != null && !backReason.isEmpty()) {
|
||||
updateEntity.setReasonText(backReason);
|
||||
}
|
||||
baseMapper.update(updateEntity,
|
||||
new LambdaUpdateWrapper<ServiceRequest>().in(ServiceRequest::getId, serviceRequestIdList)
|
||||
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Bug #613: 医嘱退回流程 — med_medication_request 表缺少退回原因字段
|
||||
-- 执行前检查:如果列已存在则跳过
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'med_medication_request' AND column_name = 'back_reason'
|
||||
) THEN
|
||||
ALTER TABLE med_medication_request ADD COLUMN back_reason VARCHAR(500) DEFAULT NULL;
|
||||
COMMENT ON COLUMN med_medication_request.back_reason IS '退回原因';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
@@ -220,3 +220,18 @@ export function getSlotStatusDescription(value) {
|
||||
export function getSlotStatusClass(status) {
|
||||
return SlotStatusClassMap[status] || 'status-unbooked';
|
||||
}
|
||||
|
||||
/**
|
||||
* 诊疗项目分类代码(对应后端 ActivityDefCategory 枚举)
|
||||
* wor_activity_definition.category_code 字段
|
||||
*/
|
||||
export const ActivityCategory = {
|
||||
/** 治疗 */
|
||||
TREATMENT: '21',
|
||||
/** 检验 */
|
||||
PROOF: '22',
|
||||
/** 检查 */
|
||||
TEST: '23',
|
||||
/** 手术 */
|
||||
PROCEDURE: '24',
|
||||
};
|
||||
|
||||
@@ -898,6 +898,9 @@ const initData = async () => {
|
||||
// 申请日期实时更新(启动定时器)
|
||||
startApplyTimeTimer()
|
||||
|
||||
// 执行时间默认填充当前系统时间
|
||||
formData.executeTime = formatDateTime(new Date())
|
||||
|
||||
// 获取主诊断信息
|
||||
try {
|
||||
const res = await getEncounterDiagnosis(props.patientInfo.encounterId)
|
||||
@@ -1185,9 +1188,9 @@ const loadCategoryItems = async (categoryKey, loadMore = false) => {
|
||||
|
||||
// 映射数据格式(从检验项目维护页面的数据结构映射)
|
||||
const mappedItems = records.map(item => {
|
||||
// 套餐项目处理:套餐项目使用套餐金额,普通项目使用零售价
|
||||
// BugFix#404: 增加对空字符串的判断,避免空字符串被误认为有效套餐ID
|
||||
const isPackage = item.feePackageId != null && item.feePackageId !== '' && item.feePackageId !== 'null'
|
||||
// 套餐项目处理:需同时满足 feePackageId 有效且 packageName 非空
|
||||
// BugFix#556: 增加 packageName 联合判断,避免普通项目因 feePackageId 有值被误标为套餐
|
||||
const isPackage = Boolean(item.feePackageId != null && item.feePackageId !== '' && item.feePackageId !== 'null' && item.packageName)
|
||||
const itemPrice = isPackage
|
||||
? (parseFloat(item.packageAmount || 0) || parseFloat(item.retailPrice || 0) || parseFloat(item.price || 0))
|
||||
: (parseFloat(item.retailPrice || 0) || parseFloat(item.price || 0))
|
||||
@@ -1675,7 +1678,7 @@ const handleSave = () => {
|
||||
// Bug #326修复: 传入 activityId,后端直接使用 ID 关联,避免用名称反查
|
||||
activityId: item.activityId || item.itemId || null,
|
||||
feePackageId: item.feePackageId || null,
|
||||
isPackage: item.isPackage || false,
|
||||
isPackage: Boolean(item.isPackage),
|
||||
sampleType: item.sampleType || '',
|
||||
unit: item.unit || ''
|
||||
}))
|
||||
|
||||
@@ -17,17 +17,14 @@
|
||||
style="width: 300px; margin-bottom: 10px"
|
||||
>
|
||||
<template #append>
|
||||
<el-button @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="handleSearch" :loading="loading">搜索</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<span v-if="!searchKey" class="total-count">共 {{ totalCount }} 项</span>
|
||||
<span v-else class="total-count">搜索到 {{ filteredCount }} 项 / 共 {{ totalCount }} 项</span>
|
||||
<span class="total-count">共 {{ totalCount }} 项</span>
|
||||
</div>
|
||||
<el-transfer
|
||||
v-model="transferValue"
|
||||
:data="transferData"
|
||||
filter-placeholder="项目代码/名称"
|
||||
filterable
|
||||
:titles="['未选择', '已选择']"
|
||||
/>
|
||||
</div>
|
||||
@@ -136,7 +133,8 @@
|
||||
<script setup name="LaboratoryTests">
|
||||
import {getCurrentInstance, nextTick, onMounted, reactive, ref, watch, computed} from 'vue';
|
||||
import {patientInfo} from '../../../store/patient.js';
|
||||
import {getApplicationList, saveInspection} from './api';
|
||||
import {getExaminationPage, saveInspection} from './api';
|
||||
import {ActivityCategory} from '@/utils/medicalConstants';
|
||||
import {getDepartmentList} from '@/api/public.js';
|
||||
import {getEncounterDiagnosis} from '../../api.js';
|
||||
import {ElMessage} from 'element-plus';
|
||||
@@ -173,9 +171,8 @@ const skipDeptAutoFill = ref(false);
|
||||
// 将已加载的全部数据转为 transfer 组件所需的格式
|
||||
const buildTransferData = (records) => {
|
||||
return records.map((item) => {
|
||||
const priceInfo = item.priceList?.[0] || {};
|
||||
const price = priceInfo.price != null ? Number(priceInfo.price).toFixed(2) : '0.00';
|
||||
const unit = item.unitCode_dictText || item.unitCode || '';
|
||||
const price = item.price != null ? Number(item.price).toFixed(2) : '0.00';
|
||||
const unit = item.unitCodeDictText || item.unitCode || '';
|
||||
return {
|
||||
adviceDefinitionId: item.adviceDefinitionId,
|
||||
orgId: item.orgId,
|
||||
@@ -185,7 +182,8 @@ const buildTransferData = (records) => {
|
||||
});
|
||||
};
|
||||
|
||||
// 加载全部数据(不分页,一次性拉取)
|
||||
const selectedItemsCache = ref(new Map());
|
||||
|
||||
const loadAllData = async () => {
|
||||
if (!patientInfo.value?.inHospitalOrgId) {
|
||||
applicationListAll.value = [];
|
||||
@@ -193,13 +191,12 @@ const loadAllData = async () => {
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
// 使用大 pageSize 一次性拉取所有启用状态的检验类诊疗项目
|
||||
const res = await getApplicationList({
|
||||
pageSize: 9999,
|
||||
const res = await getExaminationPage({
|
||||
pageSize: 100,
|
||||
pageNo: 1,
|
||||
categoryCode: '22',
|
||||
categoryCode: ActivityCategory.PROOF,
|
||||
organizationId: patientInfo.value.inHospitalOrgId,
|
||||
adviceTypes: [3], // 1 药品 2 耗材 3 诊疗
|
||||
searchKey: searchKey.value,
|
||||
});
|
||||
if (res.code !== 200) {
|
||||
proxy.$message.error(res.message);
|
||||
@@ -208,8 +205,9 @@ const loadAllData = async () => {
|
||||
}
|
||||
applicationListAll.value = res.data?.records || [];
|
||||
totalCount.value = res.data?.total || 0;
|
||||
// 检验项目列表为异步加载,编辑回显必须在数据就绪后执行,否则已选区一直为空
|
||||
applyEditTransferSelection()
|
||||
if (!searchKey.value) {
|
||||
applyEditTransferSelection();
|
||||
}
|
||||
} catch (e) {
|
||||
proxy.$message.error('获取检验项目列表失败');
|
||||
applicationListAll.value = [];
|
||||
@@ -218,32 +216,18 @@ const loadAllData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 根据搜索关键词过滤数据
|
||||
const filterData = (key) => {
|
||||
if (!key || key.trim() === '') {
|
||||
return applicationListAll.value;
|
||||
}
|
||||
const lowerKey = key.toLowerCase().trim();
|
||||
return applicationListAll.value.filter((item) => {
|
||||
return (
|
||||
item.adviceName?.toLowerCase().includes(lowerKey) ||
|
||||
item.pyStr?.toLowerCase().includes(lowerKey) ||
|
||||
item.adviceBusNo?.toLowerCase().includes(lowerKey)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
// transfer 组件实际显示的数据(受搜索词影响)
|
||||
const transferData = computed(() => buildTransferData(filterData(searchKey.value)));
|
||||
// 当前显示的条数
|
||||
const filteredCount = computed(() => filterData(searchKey.value).length);
|
||||
const transferData = computed(() => buildTransferData(applicationListAll.value));
|
||||
|
||||
const getList = async () => {
|
||||
await loadAllData();
|
||||
};
|
||||
|
||||
let searchTimer = null;
|
||||
const handleSearch = () => {
|
||||
// 搜索时保持已选中的项目不受影响
|
||||
clearTimeout(searchTimer);
|
||||
searchTimer = setTimeout(() => {
|
||||
loadAllData();
|
||||
}, 300);
|
||||
};
|
||||
// 编辑初始化标志:避免 applyEditTransferSelection 设置 transferValue 时触发 projectWithDepartment 覆盖 descJson 中的科室值
|
||||
const isInitializing = ref(false);
|
||||
@@ -302,13 +286,17 @@ const projectWithDepartment = (selectProjectIds, type) => {
|
||||
const arr = [];
|
||||
// 根据选中的项目id查找对应的项目(从全部原始数据中查找)
|
||||
selectProjectIds.forEach((element) => {
|
||||
const searchData = applicationListAll.value.find((item) => {
|
||||
let searchData = applicationListAll.value.find((item) => {
|
||||
return element == item.adviceDefinitionId;
|
||||
});
|
||||
if (!searchData) {
|
||||
searchData = selectedItemsCache.value.get(element);
|
||||
}
|
||||
if (searchData) {
|
||||
const priceInfo = searchData.priceList?.[0] || {};
|
||||
const price = priceInfo.price != null ? Number(priceInfo.price).toFixed(2) : '0.00';
|
||||
const unit = searchData.unitCode_dictText || searchData.unitCode || '';
|
||||
const price = searchData.price != null ? Number(searchData.price).toFixed(2)
|
||||
: priceInfo.price != null ? Number(priceInfo.price).toFixed(2) : '0.00';
|
||||
const unit = searchData.unitCodeDictText || searchData.unitCode_dictText || searchData.unitCode || '';
|
||||
arr.push({
|
||||
adviceDefinitionId: searchData.adviceDefinitionId,
|
||||
orgId: searchData.orgId,
|
||||
@@ -371,6 +359,12 @@ watch(
|
||||
(newValue) => {
|
||||
if (skipDeptAutoFill.value) return;
|
||||
if (isInitializing.value) return;
|
||||
newValue.forEach((id) => {
|
||||
if (!selectedItemsCache.value.has(id)) {
|
||||
const item = applicationListAll.value.find((i) => i.adviceDefinitionId == id);
|
||||
if (item) selectedItemsCache.value.set(id, item);
|
||||
}
|
||||
});
|
||||
projectWithDepartment(newValue, 1);
|
||||
}
|
||||
);
|
||||
@@ -455,13 +449,14 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
// 编辑模式下,项目字典加载完成后重新回显已选项目
|
||||
// 编辑模式下,项目字典首次加载完成后回显已选项目(搜索刷新不重置)
|
||||
watch(
|
||||
() => applicationListAll.value,
|
||||
() => {
|
||||
if (!props.editData?.requestFormId) return;
|
||||
if (!props.editData.requestFormDetailList?.length) return;
|
||||
if (!applicationListAll.value.length) return;
|
||||
if (searchKey.value) return;
|
||||
|
||||
const selectedIds = [];
|
||||
props.editData.requestFormDetailList.forEach((detail) => {
|
||||
@@ -486,26 +481,29 @@ const submit = () => {
|
||||
if (!projectWithDepartment(transferValue.value, 2)) {
|
||||
return;
|
||||
}
|
||||
let applicationListAllFilter = applicationListAll.value.filter((item) => {
|
||||
return transferValue.value.includes(item.adviceDefinitionId);
|
||||
});
|
||||
applicationListAllFilter = applicationListAllFilter.map((item) => {
|
||||
let applicationListAllFilter = transferValue.value.map((id) => {
|
||||
let item = applicationListAll.value.find((i) => i.adviceDefinitionId == id);
|
||||
if (!item) {
|
||||
item = selectedItemsCache.value.get(id);
|
||||
}
|
||||
if (!item) return null;
|
||||
const priceInfo = item.priceList?.[0] || {};
|
||||
return {
|
||||
adviceDefinitionId: item.adviceDefinitionId /** 诊疗定义id */,
|
||||
quantity: 1, // /** 请求数量 */
|
||||
unitCode: item.priceList[0].unitCode /** 请求单位编码 */,
|
||||
unitPrice: item.priceList[0].price /** 单价 */,
|
||||
totalPrice: item.priceList[0].price /** 总价 */,
|
||||
unitCode: item.unitCode || priceInfo.unitCode || '' /** 请求单位编码 */,
|
||||
unitPrice: item.price ?? priceInfo.price ?? 0 /** 单价 */,
|
||||
totalPrice: item.price ?? priceInfo.price ?? 0 /** 总价 */,
|
||||
positionId: form.targetDepartment || item.positionId, // 用户指定发往科室优先于项目默认执行科室
|
||||
ybClassEnum: item.ybClassEnum, //类别医保编码
|
||||
conditionId: item.conditionId, //诊断ID
|
||||
encounterDiagnosisId: item.encounterDiagnosisId, //就诊诊断id
|
||||
adviceType: item.adviceType, ///** 医嘱类型 */
|
||||
definitionId: item.priceList[0].definitionId, //费用定价主表ID */
|
||||
definitionDetailId: item.definitionDetailId, //费用定价子表ID */
|
||||
ybClassEnum: item.ybClassEnum || '', //类别医保编码
|
||||
conditionId: item.conditionId || '', //诊断ID
|
||||
encounterDiagnosisId: item.encounterDiagnosisId || '', //就诊诊断id
|
||||
adviceType: item.adviceType || 3, ///** 医嘱类型 */
|
||||
definitionId: item.chargeItemDefinitionId || priceInfo.definitionId || '', //费用定价主表ID */
|
||||
definitionDetailId: item.definitionDetailId || priceInfo.definitionDetailId || '', //费用定价子表ID */
|
||||
accountId: patientInfo.value.accountId, // // 账户id
|
||||
};
|
||||
});
|
||||
}).filter(Boolean);
|
||||
const params = {
|
||||
activityList: applicationListAllFilter,
|
||||
patientId: patientInfo.value.patientId, //患者ID
|
||||
@@ -520,6 +518,7 @@ const submit = () => {
|
||||
if (res.code === 200) {
|
||||
proxy.$message.success(isEditMode.value ? '修改成功' : res.msg);
|
||||
transferValue.value = [];
|
||||
selectedItemsCache.value.clear();
|
||||
emits('submitOk');
|
||||
} else {
|
||||
proxy.$message.error(res.message);
|
||||
|
||||
@@ -207,6 +207,7 @@ import {patientInfo} from '../../../store/patient.js';
|
||||
import {getDepartmentList} from '@/api/public.js';
|
||||
import {getEncounterDiagnosis} from '../../api.js';
|
||||
import {getExaminationPage, saveCheckd} from './api';
|
||||
import {ActivityCategory} from '@/utils/medicalConstants';
|
||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||
import {WarningFilled, Warning, Refresh, Files, Document, EditPen, Aim, DocumentCopy} from '@element-plus/icons-vue';
|
||||
|
||||
@@ -276,6 +277,7 @@ const getList = () => {
|
||||
pageNo: 1,
|
||||
pageSize: 5000,
|
||||
searchKey: '',
|
||||
categoryCode: ActivityCategory.TEST,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code === 200 && res.data?.records) {
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
v-model="scope.row.adviceName"
|
||||
placeholder="请选择项目"
|
||||
@input="handleChange"
|
||||
@click="handleFocus(scope.row, scope.$index)"
|
||||
@focus="handleFocus(scope.row, scope.$index)"
|
||||
@keyup.enter.stop="handleFocus(scope.row, scope.$index)"
|
||||
@keydown="
|
||||
(e) => {
|
||||
@@ -640,6 +640,10 @@ function getListInfo(addNewRow) {
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// 没有 requestTime 的项(新增/组套添加)排在最前面
|
||||
if (!a.requestTime && !b.requestTime) return 0;
|
||||
if (!a.requestTime) return -1;
|
||||
if (!b.requestTime) return 1;
|
||||
return new Date(b.requestTime) - new Date(a.requestTime);
|
||||
});
|
||||
getGroupMarkers(); // 更新标记
|
||||
@@ -896,31 +900,16 @@ function handleDiagnosisChange(item) {
|
||||
function handleFocus(row, index) {
|
||||
rowIndex.value = index;
|
||||
row.showPopover = true;
|
||||
// Bug #555: handleFocus 只负责开 popover 和初始化查询参数,搜索由 handleChange 统一处理
|
||||
// 避免异步 refresh 用旧闭包 searchKey 覆盖 handleChange 的搜索结果
|
||||
const adviceType = row.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType;
|
||||
// 用 adviceType + categoryCode 组合查找匹配的选项
|
||||
const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||
// If the row has an explicit adviceType (saved/existing row), use its own categoryCode.
|
||||
// If no type is selected (new row), use empty string for global search across all categories.
|
||||
const categoryCode = selectedItem ? selectedItem.categoryCode : (row.adviceType != null ? (row.categoryCode || '') : '');
|
||||
const searchKey = row.adviceName || '';
|
||||
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
const tableRef = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[index] : adviceTableRef.value;
|
||||
if (tableRef && tableRef.refresh) {
|
||||
tableRef.refresh(adviceType, categoryCode, searchKey);
|
||||
} else {
|
||||
// fallback: 如果双重 nextTick 仍未挂载,延迟 100ms 再试
|
||||
setTimeout(() => {
|
||||
const tableRef2 = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[index] : adviceTableRef.value;
|
||||
if (tableRef2 && tableRef2.refresh) {
|
||||
tableRef2.refresh(adviceType, categoryCode, searchKey);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
let categoryCode = '';
|
||||
if (row.adviceType !== undefined) {
|
||||
const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||
categoryCode = selectedItem ? selectedItem.categoryCode : (row.categoryCode || '');
|
||||
}
|
||||
adviceQueryParams.value = { adviceType, categoryCode, searchKey: '' };
|
||||
}
|
||||
|
||||
function handleBlur(row) {
|
||||
@@ -929,20 +918,24 @@ function handleBlur(row) {
|
||||
|
||||
function handleChange(value) {
|
||||
adviceQueryParams.value.searchKey = value;
|
||||
// 搜索词变化时,调用当前行子组件的 refresh 方法
|
||||
const index = rowIndex.value;
|
||||
if (index >= 0) {
|
||||
const tableRef = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[index] : adviceTableRef.value;
|
||||
if (tableRef && tableRef.refresh) {
|
||||
const row = filterPrescriptionList.value[index];
|
||||
const adviceType = row?.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType;
|
||||
// 用 adviceType + categoryCode 组合查找匹配的选项
|
||||
// @focus 已先于 @input 执行,rowIndex 必定有效
|
||||
const currentIndex = rowIndex.value;
|
||||
if (currentIndex < 0) return;
|
||||
const row = filterPrescriptionList.value[currentIndex];
|
||||
// popover 被 blur 关闭后,用户继续输入时自行打开
|
||||
if (!row.showPopover) {
|
||||
row.showPopover = true;
|
||||
}
|
||||
const tableRef = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[currentIndex] : adviceTableRef.value;
|
||||
if (tableRef && tableRef.refresh) {
|
||||
const adviceType = row?.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType;
|
||||
let categoryCode = '';
|
||||
if (row?.adviceType !== undefined) {
|
||||
const selectValue = (adviceType == 1 && row?.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||
// 修复Bug #486:当行没有显式选择医嘱类型时,不传categoryCode,让搜索在全药库中进行
|
||||
const categoryCode = selectedItem ? selectedItem.categoryCode : (row?.adviceType !== undefined ? (adviceQueryParams.value.categoryCode || '') : '');
|
||||
tableRef.refresh(adviceType, categoryCode, value);
|
||||
categoryCode = selectedItem ? selectedItem.categoryCode : (adviceQueryParams.value.categoryCode || '');
|
||||
}
|
||||
tableRef.refresh(adviceType, categoryCode, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1579,11 +1572,24 @@ function handleSaveGroup(orderGroupList) {
|
||||
|
||||
let successCount = 0;
|
||||
|
||||
// 收集所有要添加的新行,最后统一 unshift 到数组开头(置顶显示)
|
||||
const newRows = [];
|
||||
|
||||
// 记录循环前的数组长度,用于清理循环中创建的临时行
|
||||
const originalLength = prescriptionList.value.length;
|
||||
|
||||
orderGroupList.forEach((item) => {
|
||||
rowIndex.value = prescriptionList.value.length;
|
||||
// 使用临时索引,先追加到末尾用于 setValue 填充
|
||||
const tempIndex = prescriptionList.value.length;
|
||||
prescriptionList.value[tempIndex] = {
|
||||
uniqueKey: nextId.value++,
|
||||
isEdit: false,
|
||||
statusEnum: 1,
|
||||
};
|
||||
|
||||
if (!item) {
|
||||
console.warn('组套中的项目为空');
|
||||
prescriptionList.value.splice(tempIndex, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1609,18 +1615,12 @@ function handleSaveGroup(orderGroupList) {
|
||||
therapyEnum: item.orderDetailInfos?.therapyEnum || '1',
|
||||
};
|
||||
|
||||
// 预初始化空行(组套项带预填值,设为 false 让明细字段在表格中直接展示)
|
||||
prescriptionList.value[rowIndex.value] = {
|
||||
uniqueKey: nextId.value++,
|
||||
isEdit: false,
|
||||
statusEnum: 1,
|
||||
};
|
||||
|
||||
rowIndex.value = tempIndex;
|
||||
setValue(mergedDetail);
|
||||
|
||||
// 创建新的处方项目
|
||||
const newRow = {
|
||||
...prescriptionList.value[rowIndex.value],
|
||||
...prescriptionList.value[tempIndex],
|
||||
patientId: patientInfo.value.patientId,
|
||||
encounterId: patientInfo.value.encounterId,
|
||||
accountId: accountId.value,
|
||||
@@ -1639,12 +1639,12 @@ function handleSaveGroup(orderGroupList) {
|
||||
orgId: resolveOrgId(mergedDetail.orgId || patientInfo.value?.inHospitalOrgId) || '',
|
||||
// 🔧 修复:同时存储 orgName,确保树匹配不到时仍有中文名称可显示
|
||||
orgName: findOrgName(mergedDetail.orgId || patientInfo.value?.inHospitalOrgId) || mergedDetail.orgName || patientInfo.value?.inHospitalOrgName || '',
|
||||
dbOpType: prescriptionList.value[rowIndex.value].requestId ? '2' : '1',
|
||||
dbOpType: prescriptionList.value[tempIndex].requestId ? '2' : '1',
|
||||
conditionId: conditionId.value,
|
||||
conditionDefinitionId: conditionDefinitionId.value,
|
||||
encounterDiagnosisId: encounterDiagnosisId.value,
|
||||
diagnosisName: diagnosisName.value,
|
||||
therapyEnum: prescriptionList.value[rowIndex.value]?.therapyEnum || mergedDetail.therapyEnum || '1',
|
||||
therapyEnum: prescriptionList.value[tempIndex]?.therapyEnum || mergedDetail.therapyEnum || '1',
|
||||
// 🔧 修复:确保组套医嘱的 categoryEnum 被正确映射,防止后端 NPE
|
||||
categoryEnum: mergedDetail?.categoryEnum || mergedDetail?.categoryCode || item?.categoryCode,
|
||||
};
|
||||
@@ -1663,11 +1663,14 @@ function handleSaveGroup(orderGroupList) {
|
||||
}
|
||||
|
||||
newRow.contentJson = JSON.stringify(newRow);
|
||||
prescriptionList.value[rowIndex.value] = newRow;
|
||||
newRows.push(newRow);
|
||||
successCount++;
|
||||
});
|
||||
|
||||
if (successCount > 0) {
|
||||
// 清理循环中创建的临时行,统一添加到数组开头(置顶显示)
|
||||
if (newRows.length > 0) {
|
||||
prescriptionList.value.splice(originalLength); // 移除循环中追加到末尾的临时行
|
||||
prescriptionList.value.unshift(...newRows);
|
||||
proxy.$modal.msgSuccess(`成功添加 ${successCount} 个医嘱项`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ function handleClick(tabName) {
|
||||
break;
|
||||
case 'cancel':
|
||||
exeStatus.value = 9;
|
||||
requestStatus.value = RequestStatus.CANCELLED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -740,58 +740,59 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 结果表格区 -->
|
||||
<el-table
|
||||
ref="applyTableRef"
|
||||
v-loading="applyLoading"
|
||||
:data="applyList"
|
||||
row-key="surgeryNo"
|
||||
@row-click="handleApplyRowClick"
|
||||
:row-class-name="tableRowClassName"
|
||||
style="width: 100%"
|
||||
max-height="340"
|
||||
:scroll="{ y: 340 }"
|
||||
>
|
||||
<el-table-column type="selection" width="55" :selectable="handleSelectable" />
|
||||
<el-table-column label="ID" align="center" width="80" fixed>
|
||||
<template #default="{ $index }">
|
||||
{{ (applyQueryParams.pageNo - 1) * applyQueryParams.pageSize + $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="姓名" align="center" prop="name" width="100" />
|
||||
<el-table-column label="手术单号" align="center" prop="surgeryNo" width="120" />
|
||||
<el-table-column label="手术名称" align="center" prop="descJson.surgeryName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="申请科室" align="center" width="100" prop="applyDeptName" />
|
||||
<el-table-column label="手术类型" align="center" width="90">
|
||||
<template #default="scope">
|
||||
{{ getSurgeryTypeName(scope.row.surgeryType) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手术等级" align="center" width="90">
|
||||
<template #default="scope">
|
||||
{{ getSurgeryLevelName(scope.row.surgeryLevel || scope.row.descJson?.surgeryLevel) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="麻醉方式" align="center" width="90">
|
||||
<template #default="scope">
|
||||
{{ getAnesthesiaName(scope.row.anesthesiaTypeEnum) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主刀医生" align="center" width="100" prop="mainSurgeonName" />
|
||||
</el-table>
|
||||
|
||||
<!-- 底部分页区 -->
|
||||
<div class="pagination-container apply-pagination">
|
||||
<pagination
|
||||
v-show="applyTotal > 0"
|
||||
:total="applyTotal"
|
||||
:page="applyQueryParams.pageNo"
|
||||
:limit="applyQueryParams.pageSize"
|
||||
@update:page="val => applyQueryParams.pageNo = val"
|
||||
@update:limit="val => applyQueryParams.pageSize = val"
|
||||
@pagination="getSurgicalScheduleList"
|
||||
/>
|
||||
</div>
|
||||
<!-- 结果表格卡片 -->
|
||||
<el-card shadow="never" class="apply-card">
|
||||
<el-table
|
||||
ref="applyTableRef"
|
||||
v-loading="applyLoading"
|
||||
:data="applyList"
|
||||
row-key="surgeryNo"
|
||||
@row-click="handleApplyRowClick"
|
||||
:row-class-name="tableRowClassName"
|
||||
style="width: 100%"
|
||||
max-height="320"
|
||||
>
|
||||
<el-table-column type="selection" width="55" :selectable="handleSelectable" />
|
||||
<el-table-column label="ID" align="center" width="80" fixed>
|
||||
<template #default="{ $index }">
|
||||
{{ (applyQueryParams.pageNo - 1) * applyQueryParams.pageSize + $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="姓名" align="center" prop="name" width="100" />
|
||||
<el-table-column label="手术单号" align="center" prop="surgeryNo" width="120" />
|
||||
<el-table-column label="手术名称" align="center" prop="descJson.surgeryName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="申请科室" align="center" width="100" prop="applyDeptName" />
|
||||
<el-table-column label="手术类型" align="center" width="90">
|
||||
<template #default="scope">
|
||||
{{ getSurgeryTypeName(scope.row.surgeryType) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手术等级" align="center" width="90">
|
||||
<template #default="scope">
|
||||
{{ getSurgeryLevelName(scope.row.surgeryLevel || scope.row.descJson?.surgeryLevel) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="麻醉方式" align="center" width="90">
|
||||
<template #default="scope">
|
||||
{{ getAnesthesiaName(scope.row.anesthesiaTypeEnum) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主刀医生" align="center" width="100" prop="mainSurgeonName" />
|
||||
</el-table>
|
||||
<!-- 分页在卡片内部 -->
|
||||
<div class="apply-pagination">
|
||||
<pagination
|
||||
v-show="applyTotal > 0"
|
||||
:total="applyTotal"
|
||||
:page="applyQueryParams.pageNo"
|
||||
:limit="applyQueryParams.pageSize"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@update:page="val => applyQueryParams.pageNo = val"
|
||||
@update:limit="val => applyQueryParams.pageSize = val"
|
||||
@pagination="getSurgicalScheduleList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 底部操作区 -->
|
||||
<template #footer>
|
||||
<div class="dialog-footer" style="padding-top: 12px; border-top: 1px solid #ebeef5">
|
||||
@@ -1817,11 +1818,14 @@ function handleQuoteBilling() {
|
||||
temporaryBillingMedicines.value = []
|
||||
temporaryAdvices.value = []
|
||||
|
||||
// 🔧 修复 Bug #445: 只保留药品类型(adviceType=1),过滤掉耗材(2)和诊疗项目(3/6)
|
||||
// 同时过滤掉已有 requestId 的项目(已生成医嘱的不需要再次显示在"待生成"列表中)
|
||||
// 先提取已签发项目(statusEnum=2)填充已生成列表
|
||||
const activeItems = res.data.filter(item => {
|
||||
// 🔧 修复 Bug #444: 统一过滤逻辑,与 handleMedicalAdvice 保持一致
|
||||
// 1. 使用 Number() + snake_case 回退,避免类型转换导致过滤失效
|
||||
// 2. 增加关键词二次过滤,排除手术/检查/诊疗等非药品项目
|
||||
const filteredItems = res.data.filter(item => {
|
||||
// 匹配 encounterId
|
||||
if (item.encounterId !== temporaryPatientInfo.value.visitId) return false;
|
||||
// 只保留药品类型(adviceType=1),过滤掉耗材(2)和诊疗项目(3/6)
|
||||
// 🔧 修复 Bug #444: 使用 Number() 显式转换,增加 snake_case 回退
|
||||
const at = Number(item.adviceType ?? item.advice_type);
|
||||
if (at !== 1 && at !== 2) return false;
|
||||
if (item.statusEnum !== 2) return false;
|
||||
@@ -2339,19 +2343,35 @@ function getRowClassName({ row, rowIndex }) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
/* 手术申请查询弹窗 — 分页与footer间距 */
|
||||
/* 手术申请查询弹窗 — flex 布局确保分页不溢出 */
|
||||
.surgery-apply-dialog :deep(.el-dialog__body) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.surgery-apply-dialog :deep(.el-dialog__footer) {
|
||||
padding-top: 8px;
|
||||
padding-top: 0;
|
||||
}
|
||||
.surgery-apply-dialog :deep(.apply-card) {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
.surgery-apply-dialog :deep(.apply-card .el-card__body) {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.surgery-apply-dialog :deep(.apply-pagination) {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
.surgery-apply-dialog :deep(.apply-pagination .pagination-container) {
|
||||
margin-top: 0;
|
||||
}
|
||||
.surgery-apply-dialog :deep(.apply-pagination .el-pagination) {
|
||||
margin-right: 80px;
|
||||
position: static;
|
||||
}
|
||||
|
||||
/* 选中行样式 */
|
||||
@@ -2367,17 +2387,33 @@ function getRowClassName({ row, rowIndex }) {
|
||||
|
||||
<style>
|
||||
/* 手术申请查询弹窗 — 非 scoped 确保穿透 teleport */
|
||||
.surgery-apply-dialog .apply-pagination {
|
||||
padding-top: 12px !important;
|
||||
padding-bottom: 16px !important;
|
||||
}
|
||||
.surgery-apply-dialog .apply-pagination .el-pagination {
|
||||
margin-right: 80px !important;
|
||||
}
|
||||
.surgery-apply-dialog .el-dialog__body {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
padding-bottom: 16px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
.surgery-apply-dialog .el-dialog__footer {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.surgery-apply-dialog .apply-card {
|
||||
flex: 1 !important;
|
||||
overflow: hidden !important;
|
||||
min-height: 0 !important;
|
||||
}
|
||||
.surgery-apply-dialog .apply-card .el-card__body {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
.surgery-apply-dialog .apply-pagination {
|
||||
display: flex !important;
|
||||
justify-content: flex-end !important;
|
||||
padding-top: 8px !important;
|
||||
border-top: 1px solid #ebeef5 !important;
|
||||
}
|
||||
.surgery-apply-dialog .apply-pagination .pagination-container {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
.surgery-apply-dialog .apply-pagination .el-pagination {
|
||||
position: static !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user