Compare commits

..

27 Commits

Author SHA1 Message Date
bd50c58dd4 fix(#644): 请修复 Bug #644:[住院护士站-医嘱校对] 医嘱执行后状态未同步更新为“已执行”,且允许退回已执行医嘱(校验缺失)
根因:
- Issue 2 — 退回校验缺失**:`adviceReject` 方法仅校验了药品是否已发药(`DispenseStatus.COMPLETED`),但未校验医嘱是否已执行(`cli_procedure` 表中 `status_enum = COMPLETED` 的记录)。已执行的医嘱可以被直接退回。

修复:
- | 文件 | 修改 | 说明 |
- |------|------|------|
- | `AdviceProcessAppServiceImpl.java:235-280` | 将执行记录计算逻辑移到 `if (exeStatus != null)` 之前,所有页签都计算 | 所有页签的医嘱都能获取执行记录 |
- | `AdviceProcessAppServiceImpl.java:266-274` | 新增 `overallStatusText` 计算逻辑 | 有已执行记录→"已执行",有取消记录→"已取消执行",有停止记录→"已停止",否则回退到请求状态文本 |
- | `AdviceProcessAppServiceImpl.java:362-382` | `adviceReject` 方法新增已执行校验 | 查询 `cli_procedure` 中 `EventStatus.COMPLETED` + `ProcedureCategory.INPATIENT_ADVICE` 记录,存在则拒绝退回 |
- | `InpatientAdviceDto.java` | 新增 `overallStatusText` 字段 | 前端可通过此字段展示综合执行状态 |
- ### 全链路 6 环验证
- | 环节 | 状态 | 说明 |
- |------|------|------|
- | ①前端/页面 |  正常 | 新增 `overallStatusText` 字段,前端可直接绑定展示 |
- | ②Controller |  正常 | `adviceReject` 参数 `List<PerformInfoDto>` 无需变更 |
- | ③Service | 🔧 已修改 | `getInpatientAdvicePage` 重构执行记录计算;`adviceReject` 增加校验 |
- | ④Mapper XML |  正常 | SQL 查询无需变更,执行记录通过 Java 代码计算 |
- | ⑤DB |  正常 | `cli_procedure` 表已存储执行状态,无需变更 |
- | ⑥关联模块 |  正常 | `adviceCancel`(取消执行)不受影响,取消后执行记录变为 CANCEL,退回校验自动放行 |
2026-06-02 00:31:32 +08:00
e23ac2fd09 fix(#640): 请修复 Bug #640: web_ui 手动入列
根因:
- 文件**:`openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java:2340` → `updateGroupId()` 方法
- 全链路 6 环分析**:
- | 环节 | 状态 | 说明 |
- |------|------|------|
- | ①前端 |  正常 | `combination()` 发送 `{requestId, groupId}` 到后端 |
- | ②Controller |  正常 | `PUT /doctor-station/advice/update-groupid` 接收参数 |
- | ③Service | 🔧 已修改 | **问题所在** — 原代码把所有 requestId 都当 MedicationRequest 处理 |
- | ④Mapper/DB |  遗漏 | 当诊疗医嘱(ID属于 `wor_service_request`)的 requestId 被当作 MedicationRequest 保存时,`saveOrUpdateBatch` 尝试 INSERT 新记录,`medication_id` NOT NULL 约束失败 |

修复:
- 修改 `updateGroupId` 方法,按医嘱实际所属表分别更新:
- 1. **拆组(groupId=null)**:对三个表(MedicationRequest、ServiceRequest、DeviceRequest)都执行 `group_id` 置空
- 2. **组合(groupId!=null)**:先查 `MedicationRequest` → 再查 `ServiceRequest` → 最后查 `DeviceRequest`,找到所属表后用 `UpdateWrapper` 精准更新 `group_id`(DeviceRequest 用 `group_no`,String 类型)
- ### 验证结果
-  `mvn compile -pl openhis-application -am` 编译通过
-  修改范围仅限一个方法,不影响其他模块
-  拆组和组合两个方向都走全链路验证
2026-06-01 16:26:31 +08:00
4e3ee1f49d fix(#632): 请修复 Bug #632: web_ui 手动入列
由 AI Agent (guanyu) 自动修复,请查看 diff 确认变更内容。
2026-06-01 16:00:45 +08:00
2135682332 fix(#634): 请修复 Bug #634: web_ui 手动入列
根因:
- **
- `InspectionPackage.java` 和 `InspectionPackageDetail.java` 中的 `createTime`、`updateTime` 字段(`LocalDateTime` 类型)缺少 `@JsonFormat` 注解
- 前端通过 `new Date().toISOString()` 发送 ISO 8601 格式日期字符串(如 `"2026-06-01T01:45:06.439Z"`),Jackson 反序列化时无法自动识别格式,抛出 `JSON parse error: Cannot deserialize value of type java.time.LocalDateTime from String`
- 项目全局有自定义反序列化器(`ApplicationConfig.java`),但字段级 `@JsonFormat` 注解缺失导致 Jackson 在某些场景下未走自定义逻辑

修复:
- **
- `openhis-domain/src/main/java/com/openhis/lab/domain/InspectionPackage.java:79-83` — `createTime`、`updateTime` 字段添加 `@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")`
- `openhis-domain/src/main/java/com/openhis/lab/domain/InspectionPackageDetail.java:70-74` — `createTime`、`updateTime` 字段添加 `@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")`
- 6 环验证:**
- | 环节 | 状态 | 说明 |
- |---|---|---|
- | ①前端录入 |  正常 | 前端发送 `new Date().toISOString()` 格式 |
- | ②Controller |  正常 | `@RequestBody InspectionPackage` 接收无误 |
- | ③Service |  正常 | Service 层不涉及日期格式处理 |
- | ④Mapper |  正常 | MyBatis Plus 自动映射 |
- | ⑤DB |  正常 | PostgreSQL `timestamp` 字段匹配 |
- 验证结果:**
- `mvn compile -pl openhis-application -am` → **BUILD SUCCESS**(0 error)
- 与项目中其他实体类(如 `Instrument.java`)保持一致的 `@JsonFormat` 模式
2026-06-01 15:26:52 +08:00
4ac9254496 fix(#634): 请修复 Bug #634: web_ui 手动入列
根因:
- **
- `core-framework/.../ApplicationConfig.java:39` — `LocalDateTimeDeserializer` 只配置了 `yyyy-MM-dd HH:mm:ss` 格式
- 前端发送 ISO 8601 格式日期字符串 `"2026-06-01T01:45:06.439Z"`(含毫秒 + `Z` 时区后缀),Jackson 反序列化失败抛出 `JsonParseException`

修复:
- **
- 修改 `ApplicationConfig.java`,将单一格式的 `LocalDateTimeDeserializer` 替换为自定义多格式反序列化器
- 新反序列化器依次尝试:ISO 8601(`yyyy-MM-ddTHH:mm:ss.SSS`)→ 简单格式(`yyyy-MM-dd HH:mm:ss`)→ 斜杠格式(`yyyy/M/d HH:mm:ss`)
- 自动剥离 `Z`/`z` 时区后缀和 `+HH:MM` 偏移量(`LocalDateTime` 不含时区信息)
- 6 环验证:**
- ①前端 → ②Controller:`@RequestBody` 反序列化现在支持 ISO 8601 格式 
- ③Service:无需修改,DTO 字段类型未变 
- ④Mapper:无需修改,SQL 映射未变 
- ⑤DB:无需修改,字段类型未变 
- ⑥关联模块:全局生效,所有使用 `LocalDateTime` 的实体均受益 
- 编译验证:** `mvn compile -pl openhis-application -am` → BUILD SUCCESS 
- 变更文件:** `core-framework/src/main/java/com/core/framework/config/ApplicationConfig.java`
2026-06-01 14:35:17 +08:00
d4bbc58e4e fix(#630): 请修复 Bug #630:[门诊医生站] 点击选择现诊患者列表报错
根因:
- `DoctorStationEmrAppServiceImpl` 中多处 `emrService.getOne()` / `docRecordService.getOne()` 调用存在同一个缺陷:当同一 `encounterId` 对应多条病历记录时,MyBatis-Plus 的 `getOne()` 方法默认会在多条记录时抛出 `IncorrectResultSizeDataAccessException` 异常。

修复:
- commit b74f6bf3f**:为 `getEmrDetail` 和 `getPatientEmrHistory` 增加了空值校验,`getOne` 第二个参数改为 `false` →  有效
- commit aa193f60a**:为 `getEmrDetail` 的 EMR 查询增加了 `orderByDesc + LIMIT 1` 排序 →  有效
- 历史修复**不完整**——只修了 `getEmrDetail`,遗漏了同文件中另外 3 处相同的 `getOne` 问题
- 修改文件:`DoctorStationEmrAppServiceImpl.java`(共 4 处)
- |---|---|---|
- | `addPatientEmr` | 82 | 添加 `orderByDesc + LIMIT 1` + 第二参数 `false` |
- | `getEmrDetail` (DocRecord) | 158 | 添加第二参数 `false` |
- | `getPendingEmrList` | 250 | 添加 `orderByDesc + LIMIT 1` + 第二参数 `false` |
- | `checkNeedWriteEmr` | 308 | 添加 `orderByDesc + LIMIT 1` + 第二参数 `false` |
- ### 全链路 6 环确认
- | 环节 | 状态 | 说明 |
- |---|---|---|
- | 1. 录入 |  正常 | 前端 `handleCardClick` 正确传递 `encounterId` |
- | 4. 修改 |  正常 | 编辑回显走 `loadLatestMedicalRecord`,不涉及 `getOne` |
- | 5. 删除 |  正常 | 软删除机制,不涉及 `getOne` |
- ### 验证
- `mvn compile -pl openhis-application -am` → **BUILD SUCCESS** 
2026-05-31 22:28:33 +08:00
aa193f60a2 fix(#630): 请修复 Bug #630:[门诊医生站] 点击选择现诊患者列表报错
根因:
- Bug #请修复 Bug #630 存在的问题

修复:
- :getCreateTime).last("LIMIT 1")`),导致当同一个 `encounterId` 对应多条病历记录时,`getOne` 方法可能返回非最新的病历记录。
- 恢复门诊病历查询的排序逻辑,确保返回最新的病历记录。
- 保留 `getOne` 方法的第二个参数为 `false`,避免多条记录时抛出异常。
- 保留空值校验逻辑,确保 `encounterId` 为 null 时返回 `R.ok(null)`。
- 全链路 6 环分析:
- 1. **录入** → 【 正常】前端点击患者时正确传递 `encounterId` 参数。
- 2. **保存** → 【 正常】不涉及当前 bug。
- 3. **查询** → 【🔧 已修改】恢复排序逻辑,确保返回最新病历。
- 4. **修改** → 【 正常】不涉及当前 bug。
- 5. **删除** → 【 正常】不涉及当前 bug。
- 6. **关联模块** → 【 正常】`DoctorStationMainAppServiceImpl` 中的调用逻辑正确。
- 修改文件:
- `openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationEmrAppServiceImpl.java:152`
- 编译验证:
- `mvn compile -pl openhis-application -am` → BUILD SUCCESS
2026-05-31 14:49:37 +08:00
b74f6bf3f9 fix(#630): 请修复 Bug #630:[门诊医生站] 点击选择现诊患者列表报错
根因:
- **
- 门诊医生站点击现诊患者后,右侧病历区域加载失败,抛出异常。经过全链路分析(前端→Controller→Service→Mapper→DB),定位到两个可能的问题点:
- 1. `DoctorStationEmrController.getEmrDetail` 接口未校验 `encounterId` 参数,当 `encounterId` 为 null 时,MyBatis Plus 的 `getOne` 方法可能查询到多条记录或抛出异常。
- 2. `DoctorStationEmrController.getPatientEmrHistory` 接口未校验 `patientId` 参数,可能导致查询条件异常。

修复:
- **
- 在 `DoctorStationEmrAppServiceImpl.getPatientEmrHistory` 方法中增加 `patientId` 空值校验,为空时返回空分页结果,避免查询异常。
- 在 `DoctorStationEmrAppServiceImpl.getEmrDetail` 方法中增加 `encounterId` 空值校验,为空时直接返回 null;同时将 `emrService.getOne` 的第二个参数设为 `false`,避免多条记录时抛出异常。
- 修改文件:**
- `openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationEmrAppServiceImpl.java`
- 编译验证:**
- 运行 `mvn compile -pl openhis-application -am`,编译成功,无新增错误。
2026-05-31 00:41:58 +08:00
9f789cd3a3 fix(#629): 请修复 Bug #629:[住院医生站-临床医嘱] 录入长期医嘱“荆防颗粒”点击保存报错,数据无法写入
根因:
- `RegAdviceSaveDto`(子类)重复声明了父类 `AdviceSaveDto` 已有的 `private Integer categoryEnum` 字段。Lombok `@Data` 在两个类上各生成独立的 getter/setter,子类方法覆盖父类。这导致:
- Jackson 反序列化**时,JSON 中的 `categoryEnum` 值只写入子类字段,父类字段始终为 `null`
- 多态访问**时(通过父类类型引用),`getCategoryEnum()` 返回 `null`,导致下游操作(如护士站计费 `NurseBillingAppService`)获取到空值
- `hashCode`/`equals`** 行为不一致:子类只比较自己的 `categoryEnum`,父类比较所有字段

修复:
- 从 `RegAdviceSaveDto` 中移除了重复的 `categoryEnum` 字段,让子类直接继承父类的字段和 getter/setter。
- | 文件 | 变更 |
- |---|---|
- | `RegAdviceSaveDto.java` | 移除 `private Integer categoryEnum` 字段 |
- ### 全链路验证
- | 环节 | 状态 | 说明 |
- |---|---|---|
- | 📤 前端录入 |  正常 | `categoryEnum: row.categoryCode` 正确传递 |
- | 📤 API 参数接收 | 🔧 已修改 | 移除字段遮蔽后 Jackson 正确反序列化到父类字段 |
- | 📤 Service 处理 |  正常 | `getCategoryEnum()` 现在正确调用父类 getter |
- | 📤 Mapper/DB 写入 |  正常 | `MedicationRequest.categoryEnum` 正确赋值 |
- | 📥 查询展示 |  正常 | 数据正确入库,查询不受影响 |
- ### 编译验证
- `mvn compile -pl openhis-application -am`  通过
2026-05-30 16:37:41 +08:00
4c1222f0f4 fix(#631): 请修复 Bug #631:[住院医生站-临床医嘱] 诊疗类医嘱(如肌肉注射)录入执行科室后,医嘱列表“药房/科室”列未回显数据
根因:
- Bug #请修复 Bug #631 存在的问题

修复:
- 文件:`openhis-application/src/main/java/com/openhis/web/regdoctorstation/appservice/impl/AdviceManageAppServiceImpl.java`
- 第 630 行:`getPositionId()` → `getEffectiveOrgId()`
- 第 681 行:`getPositionId()` → `getEffectiveOrgId()`
- `getEffectiveOrgId()` 方法优先取 `orgId`,fallback 到 `positionId`,已在 `AdviceSaveDto` 中定义
- 验证**:`mvn compile -pl openhis-application -am -q` 
2026-05-30 09:45:21 +08:00
cfa073bdba Fix Bug #547: 执行科室配置保存时时间冲突检测范围错误 — 根因:addOrEditOrgLoc 方法使用 getOrgLocListByActivityDefinitionId 跨科室查询同一诊疗的所有配置,导致不同科室间的正常时间重叠被误判为冲突;修复:改为 getOrgLocListByOrgIdAndActivityDefinitionId(orgId, activityDefId) 限定同科室范围;同时优化软删除科室处理,当冲突记录关联的科室已被删除时,使用"科室[ID]已删除"替代静默跳过
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 12:07:34 +08:00
021f7180c0 Fix Bug #559: 根因+修复方案摘要 2026-05-20 12:07:10 +08:00
Ranyunqiao
ee59fd5ea0 bug 555 558 2026-05-20 12:07:10 +08:00
20a372268b Fix Bug #559: 根因+修复方案摘要 2026-05-20 11:04:39 +08:00
31f288c0dd Fix Bug #559: 住院医生站-临床医嘱 组套功能添加医嘱后新增医嘱置顶显示
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 11:02:27 +08:00
5c97380a78 Fix Bug #547: 执行科室配置保存时时间冲突检测范围错误 — 根因:addOrEditOrgLoc 方法使用 getOrgLocListByActivityDefinitionId 跨科室查询同一诊疗的所有配置,导致不同科室间的正常时间重叠被误判为冲突;修复:改为 getOrgLocListByOrgIdAndActivityDefinitionId(orgId, activityDefId) 限定同科室范围;同时优化软删除科室处理,当冲突记录关联的科室已被删除时,使用"科室[ID]已删除"替代静默跳过
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 10:16:57 +08:00
30e5c92f0b docs: 更新 Bug #547 分析报告 — 修正根因描述为跨科室误报
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 10:16:56 +08:00
7c6e35dcc3 Fix Bug #547: 冲突检测改为同科室范围 — 跨科室时间重叠不应阻断同一诊疗在不同科室的独立配置
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 10:16:29 +08:00
74b67401f3 Fix Bug #547: 合并冲突解决 — 保留 HEAD 版本的软删除科室跳过逻辑(continue),合并远程的手术安排时间字段回显修复
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 10:13:50 +08:00
81d954fceb Fix Bug #547: 根因+修复方案摘要 2026-05-20 10:12:38 +08:00
7adb3b3ea4 bug542【病区护士站-住院记账】“补费”界面选择“耗材”类型时,即使后台已配置科室权限,仍检索不到任何耗材数据 2026-05-19 11:06:20 +08:00
1e6704928a Merge branch 'guanyu' of http://192.168.110.253:3000/wangyizhe/his into guanyu
# Conflicts:
#	openhis-ui-vue3/src/views/surgicalschedule/index.vue
2026-05-19 09:08:06 +08:00
75e49f0237 Fix Bug #547: 时间冲突校验中"未知科室"提示改进 — 当冲突记录关联的科室已被删除时,将模糊的"未知科室"改为显示具体科室ID及"已删除"状态,便于运维定位数据问题;同时清理数据库中14条organization_id指向已删除科室的孤脏记录
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 09:06:30 +08:00
2b6b00b6c2 Fix Bug #445: 根因+修复方案摘要 2026-05-18 23:03:39 +08:00
1ddf8a2ccd Fix Bug #444: 引用计费时"已引用计费药品"列表显示非药品项目 — handleQuoteBilling 过滤逻辑缺少 Number() 类型转换和 snake_case 回退,且缺少关键词二次过滤,导致手术/检查/诊疗等非药品项目出现在列表中;已统一与 handleMedicalAdvice 的过滤逻辑
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 23:03:39 +08:00
0a37b05aab Fix Bug #445: 引用计费时已生成医嘱项目重新出现在待生成列表 — handleQuoteBilling 中先清空 temporaryAdvices 再执行 ID 匹配过滤,导致过滤逻辑对空数组无效;且 ID 匹配不可靠(新医嘱无 requestId/chargeItemId),已改为在清空前提取复合键(名称|||规格|||数量)并在数据加载后用该键过滤
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 22:05:18 +08:00
20817d6dc4 Fix Bug #547: 执行科室配置保存时时间冲突检查未限定当前科室,导致误报"与未知科室时间冲突" — getOrgLocListByOrgIdAndActivityDefinitionId 方法签名仅含 activityDefinitionId 参数,实际 SQL 查询缺少 organizationId 过滤,时间重叠校验跨科室比对,已修复接口签名和实现同时过滤 activityDefinitionId 和 organizationId 2026-05-18 21:07:39 +08:00
635 changed files with 24950 additions and 77099 deletions

44
bug444_analysis.md Normal file
View 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;
```

View File

@@ -5,37 +5,39 @@
## 根因定位 ## 根因定位
**核心问题在 `OrganizationLocationAppServiceImpl.java:161-174`** **核心问题在 `OrganizationLocationAppServiceImpl.java:161-162`**
时间冲突检测的查询逻辑存在两个缺陷: 时间冲突检测使用了 `getOrgLocListByActivityDefinitionId()` 跨科室查询同一诊疗定义下的**所有**科室配置记录。
### 缺陷:跨科室误报冲突
### 缺陷1查询范围过窄
```java ```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错误提示变成"与未知科室时间冲突"。 当冲突记录关联的科室被软删除(`delete_flag='1'`)时,`organizationService.getById()``@TableLogic` 注解影响查不到该科室,返回 null错误提示变成"与未知科室时间冲突"。
数据库验证发现确实存在软删除科室的组织位置记录内科门诊、上海学校医院、信息科等共9条
### 数据流
1. 前端选择科室 → 点击"添加新项目" → 填写诊疗和时间 → 点击"保存"
2. 后端 `addOrEditOrgLoc()` 接收请求
3. 查询现有冲突记录(**当前只查同科室**
4. 对冲突记录检查时间重叠
5. 查找冲突科室名称 → 若科室被软删除则返回 null → "未知科室"
## 修复方案 ## 修复方案
1. **修改冲突检测范围**查询同一 `activityDefinitionId` 的所有记录(跨科室检测),而非仅限当前科室 **修改冲突检测范围**`getOrgLocListByActivityDefinitionId` 改为 `getOrgLocListByOrgIdAndActivityDefinitionId`,仅检测**同一科室内**的时间冲突。
2. **优雅处理"未知科室"**:当 `getById` 返回 null 时,使用 "已删除科室( ID )" 替代 "未知科室",提供更有用的信息
3. **新增 Service 方法**`getOrgLocListByActivityDefinitionId(Long activityDefinitionId)` 用于按诊疗定义查询所有记录
## 涉及文件 ## 修复结果
- `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());
```
编译验证通过。

Submodule his-repo updated: 515ed84118...5de8a22418

View File

@@ -1,7 +1,9 @@
package com.core.framework.config; 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.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
@@ -9,6 +11,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.io.IOException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.TimeZone; import java.util.TimeZone;
@@ -24,6 +27,36 @@ import java.util.TimeZone;
// 指定要扫描的Mapper类的包的路径 // 指定要扫描的Mapper类的包的路径
@MapperScan({"com.core.**.mapper", "com.openhis.**.mapper"}) @MapperScan({"com.core.**.mapper", "com.openhis.**.mapper"})
public class ApplicationConfig { 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/+HHMMLocalDateTime 不含时区信息)
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);
}
};
/** /**
* 时区配置 * 时区配置
*/ */
@@ -36,7 +69,7 @@ public class ApplicationConfig {
builder.simpleDateFormat("yyyy/M/d HH:mm:ss"); builder.simpleDateFormat("yyyy/M/d HH:mm:ss");
// 添加JavaTimeModule支持用于LocalDateTime // 添加JavaTimeModule支持用于LocalDateTime
JavaTimeModule javaTimeModule = new JavaTimeModule(); JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); javaTimeModule.addDeserializer(LocalDateTime.class, LOCAL_DATE_TIME_DESERIALIZER);
builder.modules(javaTimeModule); builder.modules(javaTimeModule);
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss"))); builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss")));
}; };

View File

@@ -199,7 +199,7 @@ public class TicketAppServiceImpl implements ITicketAppService {
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) { if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) {
dto.setStatus("已退号"); dto.setStatus("已退号");
} else { } else {
dto.setStatus("预约"); dto.setStatus("锁定");
} }
} else if (status == SlotStatus.BOOKED) { } else if (status == SlotStatus.BOOKED) {
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) { if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) {
@@ -380,7 +380,7 @@ public class TicketAppServiceImpl implements ITicketAppService {
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) { if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) {
dto.setStatus("已退号"); dto.setStatus("已退号");
} else { } else {
dto.setStatus("预约"); dto.setStatus("锁定");
} }
} else if (status == SlotStatus.BOOKED) { } else if (status == SlotStatus.BOOKED) {
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) { if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) {

View File

@@ -158,8 +158,10 @@ public class OrganizationLocationAppServiceImpl implements IOrganizationLocation
? activityDefinitionMapper.selectById(activityDefinitionId) : null; ? activityDefinitionMapper.selectById(activityDefinitionId) : null;
String activityName = activityDef != null ? activityDef.getName() : ""; String activityName = activityDef != null ? activityDef.getName() : "";
// Only check for time conflicts within the same department
List<OrganizationLocation> organizationLocationList = List<OrganizationLocation> organizationLocationList =
organizationLocationService.getOrgLocListByActivityDefinitionId(orgLoc.getActivityDefinitionId()); organizationLocationService.getOrgLocListByOrgIdAndActivityDefinitionId(orgLoc.getOrganizationId(),
orgLoc.getActivityDefinitionId());
organizationLocationList = (orgLoc.getId() != null) organizationLocationList = (orgLoc.getId() != null)
? organizationLocationList.stream().filter(item -> !orgLoc.getId().equals(item.getId())).toList() ? organizationLocationList.stream().filter(item -> !orgLoc.getId().equals(item.getId())).toList()
: organizationLocationList; : organizationLocationList;

View File

@@ -31,9 +31,4 @@ public class OrgLocQueryParam implements Serializable {
/** 发放类别 */ /** 发放类别 */
private String distributionCategoryCode; private String distributionCategoryCode;
/**
* 项目编码 | 药品:1 耗材:2
*/
private String itemCode;
} }

View File

@@ -36,7 +36,4 @@ public class PerformInfoDto {
/** 分组id */ /** 分组id */
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long groupId; private Long groupId;
/** 退回原因 */
private String backReason;
} }

View File

@@ -63,21 +63,17 @@ public interface IDoctorStationEmrAppService {
* 获取待写病历列表 * 获取待写病历列表
* *
* @param doctorId 医生ID * @param doctorId 医生ID
* @param pageNo 当前页码 * @return 待写病历列表
* @param pageSize 每页条数
* @param patientName 患者姓名(可选)
* @return 待写病历分页数据
*/ */
R<?> getPendingEmrList(Long doctorId, Integer pageNo, Integer pageSize, String patientName); R<?> getPendingEmrList(Long doctorId);
/** /**
* 获取待写病历数量 * 获取待写病历数量
* *
* @param doctorId 医生ID * @param doctorId 医生ID
* @param patientName 患者姓名(可选)
* @return 待写病历数量 * @return 待写病历数量
*/ */
R<?> getPendingEmrCount(Long doctorId, String patientName); R<?> getPendingEmrCount(Long doctorId);
/** /**
* 检查患者是否需要写病历 * 检查患者是否需要写病历

View File

@@ -2205,10 +2205,6 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
// 收费状态 // 收费状态
requestBaseDto.setChargeStatus_enumText( requestBaseDto.setChargeStatus_enumText(
EnumUtils.getInfoByValue(ChargeItemStatus.class, requestBaseDto.getChargeStatus())); EnumUtils.getInfoByValue(ChargeItemStatus.class, requestBaseDto.getChargeStatus()));
// 单位字典翻译失败时回退使用原始值(如手术申请硬编码了中文单位名)
if (StringUtils.isNotBlank(requestBaseDto.getUnitCode()) && StringUtils.isBlank(requestBaseDto.getUnitCode_dictText())) {
requestBaseDto.setUnitCode_dictText(requestBaseDto.getUnitCode());
}
} }
return R.ok(requestBaseInfo); return R.ok(requestBaseInfo);
} }
@@ -2347,21 +2343,52 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
.map(UpdateGroupDto::getRequestId).collect(Collectors.toList()); .map(UpdateGroupDto::getRequestId).collect(Collectors.toList());
if (!idsToSetNull.isEmpty()) { if (!idsToSetNull.isEmpty()) {
// 创建更新条件 // 对三个表都执行 group_id/group_no 置空(哪个表有该 id 就更新哪个)
UpdateWrapper<MedicationRequest> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<MedicationRequest> medUpdateWrapper = new UpdateWrapper<>();
updateWrapper.set("group_id", null).in("id", idsToSetNull); medUpdateWrapper.set("group_id", null).in("id", idsToSetNull);
iMedicationRequestService.update(medUpdateWrapper);
// 执行更新 UpdateWrapper<ServiceRequest> srvUpdateWrapper = new UpdateWrapper<>();
iMedicationRequestService.update(updateWrapper); srvUpdateWrapper.set("group_id", null).in("id", idsToSetNull);
iServiceRequestService.update(srvUpdateWrapper);
// DeviceRequest 使用 group_noString 类型)
UpdateWrapper<DeviceRequest> devUpdateWrapper = new UpdateWrapper<>();
devUpdateWrapper.set("group_no", null).in("id", idsToSetNull);
iDeviceRequestService.update(devUpdateWrapper);
} }
// 处理null的情况 // 处理 groupId 非 null 的情况:按实际所属表分别更新
List<MedicationRequest> medicationRequestList = groupList.stream().filter(dto -> dto.getGroupId() != null) List<UpdateGroupDto> nonNullGroupList = groupList.stream()
.map(dto -> new MedicationRequest().setId(dto.getRequestId()).setGroupId(dto.getGroupId())) .filter(dto -> dto.getGroupId() != null).collect(Collectors.toList());
.collect(Collectors.toList()); if (!nonNullGroupList.isEmpty()) {
for (UpdateGroupDto dto : nonNullGroupList) {
if (!medicationRequestList.isEmpty()) { Long reqId = dto.getRequestId();
iMedicationRequestService.saveOrUpdateBatch(medicationRequestList); 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);
}
}
} }
} }

View File

@@ -29,7 +29,6 @@ import com.openhis.document.service.IEmrTemplateService;
import com.openhis.web.doctorstation.appservice.IDoctorStationEmrAppService; import com.openhis.web.doctorstation.appservice.IDoctorStationEmrAppService;
import com.openhis.web.doctorstation.dto.EmrTemplateDto; import com.openhis.web.doctorstation.dto.EmrTemplateDto;
import com.openhis.web.doctorstation.dto.PatientEmrDto; import com.openhis.web.doctorstation.dto.PatientEmrDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -42,7 +41,6 @@ import java.util.stream.Collectors;
/** /**
* 医生站-电子病历 应用实现类 * 医生站-电子病历 应用实现类
*/ */
@Slf4j
@Service @Service
public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppService { public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppService {
@@ -62,7 +60,13 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
IDocRecordService docRecordService; IDocRecordService docRecordService;
@Resource @Resource
private com.openhis.web.doctorstation.mapper.DoctorStationEmrAppMapper doctorStationEmrAppMapper; private EncounterMapper encounterMapper;
@Resource
private PatientMapper patientMapper;
@Resource
private com.openhis.administration.mapper.EncounterParticipantMapper encounterParticipantMapper;
/** /**
* 添加病人病历信息 * 添加病人病历信息
@@ -75,7 +79,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
Emr emr = new Emr(); Emr emr = new Emr();
BeanUtils.copyProperties(patientEmrDto, emr); BeanUtils.copyProperties(patientEmrDto, emr);
String contextStr = patientEmrDto.getContextJson().toString(); 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; boolean saveSuccess;
// 如果已经保存病历,再次保存走更新 // 如果已经保存病历,再次保存走更新
if (patientEmr != null) { if (patientEmr != null) {
@@ -122,6 +126,10 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
*/ */
@Override @Override
public R<?> getPatientEmrHistory(PatientEmrDto patientEmrDto, Integer pageNo, Integer pageSize) { 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), Page<Emr> page = emrService.page(new Page<>(pageNo, pageSize),
new LambdaQueryWrapper<Emr>().eq(Emr::getPatientId, patientEmrDto.getPatientId())); new LambdaQueryWrapper<Emr>().eq(Emr::getPatientId, patientEmrDto.getPatientId()));
return R.ok(page); return R.ok(page);
@@ -136,8 +144,12 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
*/ */
@Override @Override
public R<?> getEmrDetail(Long encounterId) { public R<?> getEmrDetail(Long encounterId) {
// 校验参数
if (encounterId == null) {
return R.ok(null);
}
// 先查询门诊病历(emr表) // 先查询门诊病历(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) { if (emrDetail != null) {
return R.ok(emrDetail); return R.ok(emrDetail);
} }
@@ -147,7 +159,8 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
new LambdaQueryWrapper<DocRecord>() new LambdaQueryWrapper<DocRecord>()
.eq(DocRecord::getEncounterId, encounterId) .eq(DocRecord::getEncounterId, encounterId)
.orderByDesc(DocRecord::getCreateTime) .orderByDesc(DocRecord::getCreateTime)
.last("LIMIT 1") .last("LIMIT 1"),
false
); );
if (docRecord != null) { if (docRecord != null) {
// 住院病历存在,也返回数据 // 住院病历存在,也返回数据
@@ -219,29 +232,52 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
* @return 待写病历列表 * @return 待写病历列表
*/ */
@Override @Override
public R<?> getPendingEmrList(Long doctorId, Integer pageNo, Integer pageSize, String patientName) { public R<?> getPendingEmrList(Long doctorId) {
// 先查询总数 // 由于Encounter实体中没有jzPractitionerUserId字段我们需要通过关联查询来获取相关信息
Long total = doctorStationEmrAppMapper.getPendingEmrCount(doctorId, patientName); // 使用医生工作站的mapper来查询相关数据
// 这里我们直接使用医生工作站的查询逻辑
// 计算分页偏移量,再查询分页数据 // 查询当前医生负责的、状态为"就诊中"但还没有写病历的患者
int offset = (pageNo - 1) * pageSize; // 需要通过EncounterParticipant表来关联医生信息
List<Map<String, Object>> pageRows = doctorStationEmrAppMapper.getPendingEmrList(doctorId, patientName, pageSize, offset); List<Encounter> encounters = encounterMapper.selectList(
new LambdaQueryWrapper<Encounter>()
.eq(Encounter::getStatusEnum, EncounterStatus.IN_PROGRESS.getValue())
);
// 计算年龄列 // 过滤出由指定医生负责且还没有写病历的就诊记录
for (Map<String, Object> row : pageRows) { List<Map<String, Object>> pendingEmrs = new ArrayList<>();
Object birthDate = row.get("birthDate"); for (Encounter encounter : encounters) {
if (birthDate instanceof Date) { // 检查该就诊记录是否已经有病历
row.put("age", calculateAge((Date) birthDate)); Emr existingEmr = emrService.getOne(
} else { new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounter.getId()).orderByDesc(Emr::getCreateTime).last("LIMIT 1"), false
row.put("age", null); );
// 检查该就诊是否由指定医生负责
boolean isAssignedToDoctor = isEncounterAssignedToDoctor(encounter.getId(), doctorId);
if (existingEmr == null && isAssignedToDoctor) {
// 如果没有病历且由该医生负责,则添加到待写病历列表
Map<String, Object> pendingEmr = new java.util.HashMap<>();
// 获取患者信息
Patient patient = patientMapper.selectById(encounter.getPatientId());
pendingEmr.put("encounterId", encounter.getId());
pendingEmr.put("patientId", encounter.getPatientId());
pendingEmr.put("patientName", patient != null ? patient.getName() : "未知");
pendingEmr.put("gender", patient != null ? patient.getGenderEnum() : null);
// 使用出生日期计算年龄
pendingEmr.put("age", patient != null && patient.getBirthDate() != null ?
calculateAge(patient.getBirthDate()) : null);
// 使用创建时间作为挂号时间
pendingEmr.put("registerTime", encounter.getCreateTime());
pendingEmr.put("busNo", encounter.getBusNo()); // 病历号
pendingEmrs.add(pendingEmr);
} }
row.remove("birthDate");
} }
Map<String, Object> result = new java.util.HashMap<>(); return R.ok(pendingEmrs);
result.put("rows", pageRows);
result.put("total", total != null ? total : 0L);
return R.ok(result);
} }
/** /**
@@ -251,9 +287,14 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
* @return 待写病历数量 * @return 待写病历数量
*/ */
@Override @Override
public R<?> getPendingEmrCount(Long doctorId, String patientName) { public R<?> getPendingEmrCount(Long doctorId) {
Long count = doctorStationEmrAppMapper.getPendingEmrCount(doctorId, patientName); // 获取待写病历列表,然后返回数量
return R.ok(count != null ? count.intValue() : 0); R<?> result = getPendingEmrList(doctorId);
if (result.getCode() == 200) {
List<?> pendingEmrs = (List<?>) result.getData();
return R.ok(pendingEmrs.size());
}
return R.ok(0);
} }
/** /**
@@ -266,7 +307,7 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
public R<?> checkNeedWriteEmr(Long encounterId) { public R<?> checkNeedWriteEmr(Long encounterId) {
// 检查该就诊记录是否已经有病历 // 检查该就诊记录是否已经有病历
Emr existingEmr = emrService.getOne( 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
); );
// 如果没有病历,则需要写病历 // 如果没有病历,则需要写病历
@@ -274,6 +315,24 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
return R.ok(needWrite); return R.ok(needWrite);
} }
/**
* 检查就诊是否分配给指定医生
*
* @param encounterId 就诊ID
* @param doctorId 医生ID
* @return 是否分配给指定医生
*/
private boolean isEncounterAssignedToDoctor(Long encounterId, Long doctorId) {
// 查询就诊参与者表,检查是否有指定医生的接诊记录
com.openhis.administration.domain.EncounterParticipant participant =
encounterParticipantMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.openhis.administration.domain.EncounterParticipant>()
.eq(com.openhis.administration.domain.EncounterParticipant::getEncounterId, encounterId)
.eq(com.openhis.administration.domain.EncounterParticipant::getPractitionerId, doctorId)
);
return participant != null;
}
/** /**
* 根据出生日期计算年龄 * 根据出生日期计算年龄

View File

@@ -77,10 +77,8 @@ public class DoctorStationAdviceController {
*/ */
@PostMapping(value = "/save-advice") @PostMapping(value = "/save-advice")
@RepeatSubmit(interval = 5000, message = "请勿重复提交医嘱,请稍候再试") @RepeatSubmit(interval = 5000, message = "请勿重复提交医嘱,请稍候再试")
public R<?> saveAdvice(@RequestBody AdviceSaveParam adviceSaveParam, public R<?> saveAdvice(@RequestBody AdviceSaveParam adviceSaveParam) {
@RequestParam(required = false, defaultValue = "1") String adviceOpType) { return iDoctorStationAdviceAppService.saveAdvice(adviceSaveParam, AdviceOpType.SAVE_ADVICE.getCode());
// 🔧 Bug #445 修复:使用前端传入的 adviceOpType 参数1=保存草稿2=签发),而非硬编码
return iDoctorStationAdviceAppService.saveAdvice(adviceSaveParam, adviceOpType);
} }
/** /**

View File

@@ -26,36 +26,34 @@ public class PendingEmrController {
* 获取待写病历列表 * 获取待写病历列表
* *
* @param doctorId 医生ID * @param doctorId 医生ID
* @param pageNo 当前页码 * @return 待写病历列表
* @param pageSize 每页条数
* @param patientName 患者姓名(可选)
* @return 待写病历分页数据
*/ */
@GetMapping("/pending-list") @GetMapping("/pending-list")
public R<?> getPendingEmrList(@RequestParam(required = false) Long doctorId, public R<?> getPendingEmrList(@RequestParam(required = false) Long doctorId) {
@RequestParam(defaultValue = "1") Integer pageNum, // 如果没有传递医生ID则使用当前登录用户ID
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String patientName) {
if (doctorId == null) { if (doctorId == null) {
doctorId = com.core.common.utils.SecurityUtils.getLoginUser().getPractitionerId(); doctorId = com.core.common.utils.SecurityUtils.getLoginUser().getUserId();
} }
return iDoctorStationEmrAppService.getPendingEmrList(doctorId, pageNum, pageSize, patientName);
// 调用服务获取待写病历列表
return iDoctorStationEmrAppService.getPendingEmrList(doctorId);
} }
/** /**
* 获取待写病历数量 * 获取待写病历数量
* *
* @param doctorId 医生ID * @param doctorId 医生ID
* @param patientName 患者姓名(可选)
* @return 待写病历数量 * @return 待写病历数量
*/ */
@GetMapping("/pending-count") @GetMapping("/pending-count")
public R<?> getPendingEmrCount(@RequestParam(required = false) Long doctorId, public R<?> getPendingEmrCount(@RequestParam(required = false) Long doctorId) {
@RequestParam(required = false) String patientName) { // 如果没有传递医生ID则使用当前登录用户ID
if (doctorId == null) { if (doctorId == null) {
doctorId = com.core.common.utils.SecurityUtils.getLoginUser().getPractitionerId(); doctorId = com.core.common.utils.SecurityUtils.getLoginUser().getUserId();
} }
return iDoctorStationEmrAppService.getPendingEmrCount(doctorId, patientName);
// 调用服务获取待写病历数量
return iDoctorStationEmrAppService.getPendingEmrCount(doctorId);
} }
/** /**

View File

@@ -198,10 +198,8 @@ public class AdviceBaseDto {
/** /**
* 所属科室 * 所属科室
*/ */
@Dict(dictTable = "adm_organization", dictCode = "id", dictText = "name")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long orgId; private Long orgId;
private String orgId_dictText;
/** /**
* 所在位置 * 所在位置

View File

@@ -8,10 +8,6 @@ import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.math.BigDecimal; import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.annotation.Nulls;
@@ -30,14 +26,6 @@ public class AdviceSaveDto {
/** 医嘱类型 */ /** 医嘱类型 */
private Integer adviceType; // 1:药品 , 2: 耗材 , 3:项目 private Integer adviceType; // 1:药品 , 2: 耗材 , 3:项目
/**
* 医嘱开始时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/** /**
* 请求id * 请求id
*/ */

View File

@@ -63,18 +63,6 @@ public class PatientDetailsDto {
*/ */
private String address; private String address;
/** 地址省 */
private String addressProvince;
/** 地址市 */
private String addressCity;
/** 地址区 */
private String addressDistrict;
/** 地址街道 */
private String addressStreet;
/** /**
* 工作单位 * 工作单位
*/ */

View File

@@ -22,12 +22,6 @@ public class RequestBaseDto {
*/ */
private Integer adviceType; // 1:药品 , 2: 耗材 , 3:项目 private Integer adviceType; // 1:药品 , 2: 耗材 , 3:项目
/**
* 医嘱开始时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/** /**
* 唯一标识 * 唯一标识
*/ */
@@ -127,11 +121,6 @@ public class RequestBaseDto {
* 请求状态 * 请求状态
*/ */
private Integer statusEnum; private Integer statusEnum;
/**
* 退回原因
*/
private String reasonText;
private String statusEnum_enumText; private String statusEnum_enumText;
/** /**
@@ -249,15 +238,4 @@ public class RequestBaseDto {
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long patientId; private Long patientId;
/**
* 停嘱医生
*/
private String stopUserName;
/**
* 停嘱时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private Date stopTime;
} }

View File

@@ -1,22 +1,11 @@
package com.openhis.web.doctorstation.mapper; package com.openhis.web.doctorstation.mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/** /**
* 医生站-电子病历 应用Mapper * 医生站-电子病历 应用Mapper
*/ */
@Repository @Repository
public interface DoctorStationEmrAppMapper { public interface DoctorStationEmrAppMapper {
List<Map<String, Object>> getPendingEmrList(@Param("doctorId") Long doctorId,
@Param("patientName") String patientName,
@Param("pageSize") Integer pageSize,
@Param("offset") Integer offset);
Long getPendingEmrCount(@Param("doctorId") Long doctorId,
@Param("patientName") String patientName);
} }

View File

@@ -178,24 +178,11 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
inpatientAdviceParam.setEncounterIds(null); inpatientAdviceParam.setEncounterIds(null);
Integer exeStatus = inpatientAdviceParam.getExeStatus(); Integer exeStatus = inpatientAdviceParam.getExeStatus();
inpatientAdviceParam.setExeStatus(null); inpatientAdviceParam.setExeStatus(null);
// 提取requestStatus手动处理支持COMPLETED(3)和CHECK_VERIFIED(10)同时查询 // requestStatus由前端tab传入通过QueryWrapper自动添加到SQL外层WHERE过滤
Integer requestStatus = inpatientAdviceParam.getRequestStatus();
inpatientAdviceParam.setRequestStatus(null);
// 构建查询条件 // 构建查询条件
QueryWrapper<InpatientAdviceParam> queryWrapper QueryWrapper<InpatientAdviceParam> queryWrapper
= HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null, null, null); = HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null, null, null);
// 手动拼接requestStatus条件COMPLETED(3)时同时包含CHECK_VERIFIED(10)
// UNION查询外层列名为request_statusT1.status_enum AS request_status不是status_enum
if (requestStatus != null) {
if (RequestStatus.COMPLETED.getValue().equals(requestStatus)) {
queryWrapper.in("request_status",
RequestStatus.COMPLETED.getValue(), RequestStatus.CHECK_VERIFIED.getValue());
} else {
queryWrapper.eq("request_status", requestStatus);
}
}
// 手动拼接住院患者id条件 // 手动拼接住院患者id条件
if (encounterIds != null && !encounterIds.isEmpty()) { if (encounterIds != null && !encounterIds.isEmpty()) {
List<Long> encounterIdList List<Long> encounterIdList
@@ -245,9 +232,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
} }
} }
// 手动处理前端传来的执行条件 // 为所有医嘱计算执行记录状态(所有页签都需要展示执行进度)
if (exeStatus != null) {
// 处理执行记录状态
for (InpatientAdviceDto inpatientAdvice : inpatientAdviceList) { for (InpatientAdviceDto inpatientAdvice : inpatientAdviceList) {
List<PerformRecordDto> performRecordList = procedureRecordGroup.get(inpatientAdvice.getRequestId()); List<PerformRecordDto> performRecordList = procedureRecordGroup.get(inpatientAdvice.getRequestId());
List<PerformRecordDto> exePerformRecordList = new ArrayList<>(); List<PerformRecordDto> exePerformRecordList = new ArrayList<>();
@@ -275,8 +260,20 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
inpatientAdvice.setExePerformRecordList(exePerformRecordList) inpatientAdvice.setExePerformRecordList(exePerformRecordList)
.setCancelPerformRecordList(cancelPerformRecordList) .setCancelPerformRecordList(cancelPerformRecordList)
.setStopPerformRecordList(stopPerformRecordList); .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<>(); List<InpatientAdviceDto> filteredList = new ArrayList<>();
if (EventStatus.COMPLETED.getValue().equals(exeStatus)) { if (EventStatus.COMPLETED.getValue().equals(exeStatus)) {
@@ -328,29 +325,19 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId(); Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
Date checkDate = new Date(); Date checkDate = new Date();
if (!serviceRequestList.isEmpty()) { if (!serviceRequestList.isEmpty()) {
List<Long> serviceReqIds = serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(); // 更新服务请求状态已完成
// 先查询服务请求,按 categoryEnum 分流:检查类(23)走 CHECK_VERIFIED其余走 COMPLETED serviceRequestService.updateCompleteRequestStatus(
List<ServiceRequest> allServiceRequests = serviceRequestService.listByIds(serviceReqIds); serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
List<Long> checkReqIds = allServiceRequests.stream() List<ServiceRequest> serviceRequests = serviceRequestService
.filter(sr -> ActivityDefCategory.TEST.getValue().equals(sr.getCategoryEnum())) .listByIds(serviceRequestList.stream().map(PerformInfoDto::getRequestId).collect(Collectors.toList()));
.map(ServiceRequest::getId).toList(); for (ServiceRequest serviceRequest : serviceRequests) {
List<Long> otherReqIds = allServiceRequests.stream() // 判断医嘱类型
.filter(sr -> !ActivityDefCategory.TEST.getValue().equals(sr.getCategoryEnum()))
.map(ServiceRequest::getId).toList();
// 检查类 → 已校对CHECK_VERIFIED=10
if (!checkReqIds.isEmpty()) {
serviceRequestService.updateCheckVerifiedStatus(checkReqIds, practitionerId, checkDate);
}
// 其他类 → 已完成COMPLETED=3
if (!otherReqIds.isEmpty()) {
serviceRequestService.updateCompleteRequestStatus(otherReqIds, practitionerId, checkDate);
}
// 处理转科/出院等特殊医嘱
for (ServiceRequest serviceRequest : allServiceRequests) {
if (ActivityDefCategory.TRANSFER.getValue().equals(serviceRequest.getCategoryEnum())) { if (ActivityDefCategory.TRANSFER.getValue().equals(serviceRequest.getCategoryEnum())) {
// 更新患者状态 待转科
encounterService.updateEncounterStatus(serviceRequest.getEncounterId(), encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
EncounterZyStatus.PENDING_TRANSFER.getValue()); EncounterZyStatus.PENDING_TRANSFER.getValue());
} else if (ActivityDefCategory.DISCHARGE.getValue().equals(serviceRequest.getCategoryEnum())) { } else if (ActivityDefCategory.DISCHARGE.getValue().equals(serviceRequest.getCategoryEnum())) {
// 更新患者状态 待出院
encounterService.updateEncounterStatus(serviceRequest.getEncounterId(), encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
EncounterZyStatus.AWAITING_DISCHARGE.getValue()); EncounterZyStatus.AWAITING_DISCHARGE.getValue());
} }
@@ -382,23 +369,28 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
medRequestList.add(item); medRequestList.add(item);
} }
} }
// 校验医嘱是否已执行,已执行的医嘱需要先取消执行后才能退回 // 校验医嘱是否已执行,已执行的医嘱不允许退回
List<Long> allRequestIds = performInfoList.stream().map(PerformInfoDto::getRequestId).toList(); List<PerformInfoDto> allRequestList = new ArrayList<>();
List<Procedure> allProcedures = procedureService.list( 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>() new LambdaQueryWrapper<Procedure>()
.in(Procedure::getRequestId, allRequestIds) .in(Procedure::getRequestId, requestIds)
.eq(Procedure::getDeleteFlag, "0")); .eq(Procedure::getRequestTable, requestTable)
Set<Long> executedIds = allProcedures.stream() .eq(Procedure::getStatusEnum, EventStatus.COMPLETED.getValue())
.filter(p -> EventStatus.COMPLETED.getValue().equals(p.getStatusEnum())) .eq(Procedure::getCategoryEnum, ProcedureCategory.INPATIENT_ADVICE.getValue()));
.map(Procedure::getId) if (!executedProcedures.isEmpty()) {
.collect(Collectors.toSet()); return R.fail("所选医嘱中存在已执行的医嘱,请先在【医嘱执行】界面取消执行后再退回");
Set<Long> cancelledRefundIds = allProcedures.stream() }
.filter(p -> EventStatus.CANCEL.getValue().equals(p.getStatusEnum()) && p.getRefundId() != null) }
.map(Procedure::getRefundId)
.collect(Collectors.toSet());
executedIds.removeAll(cancelledRefundIds);
if (!executedIds.isEmpty()) {
return R.fail("该医嘱已执行,请先取消执行后再退回");
} }
// 校验药品医嘱是否已发药,已发药的医嘱不允许退回 // 校验药品医嘱是否已发药,已发药的医嘱不允许退回
if (!medRequestList.isEmpty()) { if (!medRequestList.isEmpty()) {
@@ -415,14 +407,13 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
Date checkDate = new Date(); Date checkDate = new Date();
if (!serviceRequestList.isEmpty()) { if (!serviceRequestList.isEmpty()) {
// 更新服务请求状态待发送 // 更新服务请求状态待发送
String backReason = performInfoList.get(0).getBackReason();
serviceRequestService.updateDraftStatus( serviceRequestService.updateDraftStatus(
serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate, backReason); serviceRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
} }
if (!medRequestList.isEmpty()) { if (!medRequestList.isEmpty()) {
// 更新药品请求状态待发送 // 更新药品请求状态待发送
medicationRequestService.updateDraftStatusBatch( medicationRequestService.updateDraftStatusBatch(
medRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate, backReason); medRequestList.stream().map(PerformInfoDto::getRequestId).toList(), practitionerId, checkDate);
} }
return R.ok(null, "退回成功"); return R.ok(null, "退回成功");
} }
@@ -466,15 +457,6 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
List<ServiceRequestUseExe> actUseExeList = this.assemblyActivity(activityList); List<ServiceRequestUseExe> actUseExeList = this.assemblyActivity(activityList);
// 处理诊疗执行 // 处理诊疗执行
this.exeActivity(actUseExeList, exeDate); this.exeActivity(actUseExeList, exeDate);
// 检查类医嘱执行后,状态改为"待接收"PENDING_RECEIVE=11
List<Long> actReqIds = activityList.stream().map(AdviceExecuteDetailParam::getRequestId).toList();
List<ServiceRequest> executedReqs = serviceRequestService.listByIds(actReqIds);
List<Long> checkReqIds = executedReqs.stream()
.filter(sr -> ActivityDefCategory.TEST.getValue().equals(sr.getCategoryEnum()))
.map(ServiceRequest::getId).toList();
if (!checkReqIds.isEmpty()) {
serviceRequestService.updatePendingReceiveStatus(checkReqIds);
}
} }
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"医嘱执行"})); return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"医嘱执行"}));
@@ -575,10 +557,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
// 处理长期已发放的药品 // 处理长期已发放的药品
if (!longMedDispensedList.isEmpty()) { if (!longMedDispensedList.isEmpty()) {
// 生成退药单 // 生成退药单
this.creatRefundMedicationList(longMedDispensedList, procedureIdMap); this.creatRefundMedicationList(tempMedDispensedList, procedureIdMap);
// 药品退药请求状态变更(待退药)
medicationRequestService.updateCancelledStatusBatch(
longMedDispensedList.stream().map(MedicationDispense::getMedReqId).toList(), null, null);
} }
// 处理临时已发放药品 // 处理临时已发放药品
if (!tempMedDispensedList.isEmpty()) { if (!tempMedDispensedList.isEmpty()) {

View File

@@ -78,10 +78,12 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService
.map(notPerformedReason -> new DispenseInitDto.NotPerformedReasonOption(notPerformedReason.getValue(), .map(notPerformedReason -> new DispenseInitDto.NotPerformedReasonOption(notPerformedReason.getValue(),
notPerformedReason.getInfo())) notPerformedReason.getInfo()))
.collect(Collectors.toList()); .collect(Collectors.toList());
// 发药状态(汇总单:待配药→已提交,已发放→已发药) // 发药状态
List<DispenseStatusOption> dispenseStatusOptions = new ArrayList<>(); List<DispenseStatusOption> dispenseStatusOptions = new ArrayList<>();
dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.PREPARATION.getValue(), "已提交")); dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.PREPARATION.getValue(),
dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.COMPLETED.getValue(), "已发药")); DispenseStatus.PREPARATION.getInfo()));
dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.COMPLETED.getValue(),
DispenseStatus.COMPLETED.getInfo()));
initDto.setNotPerformedReasonOptions(notPerformedReasonOptions).setDispenseStatusOptions(dispenseStatusOptions); initDto.setNotPerformedReasonOptions(notPerformedReasonOptions).setDispenseStatusOptions(dispenseStatusOptions);
return R.ok(initDto); return R.ok(initDto);
@@ -159,8 +161,8 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService
new Page<>(pageNo, pageSize), queryWrapper, DispenseStatus.COMPLETED.getValue(), new Page<>(pageNo, pageSize), queryWrapper, DispenseStatus.COMPLETED.getValue(),
DispenseStatus.PREPARATION.getValue(), SupplyType.SUMMARY_DISPENSE.getValue()); DispenseStatus.PREPARATION.getValue(), SupplyType.SUMMARY_DISPENSE.getValue());
medicineSummaryFormPage.getRecords().forEach(e -> { medicineSummaryFormPage.getRecords().forEach(e -> {
// 发药状态(汇总单展示文案) // 发药状态
e.setStatusEnum_enumText(getSummaryFormStatusText(e.getStatusEnum())); e.setStatusEnum_enumText(EnumUtils.getInfoByValue(DispenseStatus.class, e.getStatusEnum()));
}); });
return R.ok(medicineSummaryFormPage); return R.ok(medicineSummaryFormPage);
} }
@@ -290,17 +292,4 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService
} }
return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"取消"})); return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"取消"}));
} }
/**
* 汇总发药单状态展示文案(药品医嘱状态映射表:汇总申请→已提交,发药→已发药)
*/
private String getSummaryFormStatusText(Integer statusEnum) {
if (DispenseStatus.PREPARATION.getValue().equals(statusEnum)) {
return "已提交";
}
if (DispenseStatus.COMPLETED.getValue().equals(statusEnum)) {
return "已发药";
}
return EnumUtils.getInfoByValue(DispenseStatus.class, statusEnum);
}
} }

View File

@@ -101,6 +101,9 @@ public class InpatientAdviceDto {
private Integer requestStatus; private Integer requestStatus;
private String requestStatus_enumText; private String requestStatus_enumText;
/** 综合执行状态(结合请求状态和执行记录计算) */
private String overallStatusText;
/** 是否皮试 */ /** 是否皮试 */
private Integer skinTestFlag; private Integer skinTestFlag;
private String skinTestFlag_enumText; private String skinTestFlag_enumText;

View File

@@ -86,13 +86,8 @@ public class OutpatientRecordServiceImpl implements IOutpatientRecordService {
// 处理就诊对象状态筛选 // 处理就诊对象状态筛选
if (outpatientRecordSearchParam.getSubjectStatusEnum() != null) { if (outpatientRecordSearchParam.getSubjectStatusEnum() != null) {
if (outpatientRecordSearchParam.getSubjectStatusEnum() == 0) {
// 前端选择"无状态"(0)时,过滤 status_enum IS NULL 的记录
queryWrapper.isNull("enc.status_enum");
} else {
queryWrapper.eq("enc.status_enum", outpatientRecordSearchParam.getSubjectStatusEnum()); queryWrapper.eq("enc.status_enum", outpatientRecordSearchParam.getSubjectStatusEnum());
} }
}
// 处理医生姓名查询(支持模糊查询) // 处理医生姓名查询(支持模糊查询)
if (outpatientRecordSearchParam.getDoctorName() != null && !outpatientRecordSearchParam.getDoctorName().isEmpty()) { if (outpatientRecordSearchParam.getDoctorName() != null && !outpatientRecordSearchParam.getDoctorName().isEmpty()) {

View File

@@ -69,12 +69,4 @@ public interface IAdviceManageAppService {
*/ */
R<?> stopRegAdvice(List<AdviceBatchOpParam> paramList); R<?> stopRegAdvice(List<AdviceBatchOpParam> paramList);
/**
* 住院医嘱取消停嘱(恢复)
*
* @param paramList 恢复参数
* @return 结果
*/
R<?> cancelStopRegAdvice(List<AdviceBatchOpParam> paramList);
} }

View File

@@ -18,7 +18,6 @@ import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.*; import com.openhis.common.enums.*;
import com.openhis.common.utils.EnumUtils; import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils; import com.openhis.common.utils.HisQueryUtils;
import com.openhis.medication.domain.MedicationDispense;
import com.openhis.medication.domain.MedicationRequest; import com.openhis.medication.domain.MedicationRequest;
import com.openhis.medication.service.IMedicationDispenseService; import com.openhis.medication.service.IMedicationDispenseService;
import com.openhis.medication.service.IMedicationRequestService; import com.openhis.medication.service.IMedicationRequestService;
@@ -416,7 +415,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
} }
// 保存时处理的字段属性 // 保存时处理的字段属性
if (is_save) { if (is_save) {
longMedicationRequest.setEffectiveDoseStart(regAdviceSaveDto.getStartTime() != null ? regAdviceSaveDto.getStartTime() : startTime); // 医嘱开始时间 longMedicationRequest.setEffectiveDoseStart(startTime); // 医嘱开始时间
longMedicationRequest longMedicationRequest
.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.MEDICATION_RES_NO.getPrefix(), 4)); .setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.MEDICATION_RES_NO.getPrefix(), 4));
longMedicationRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源 longMedicationRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
@@ -504,7 +503,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
} }
// 保存时处理的字段属性 // 保存时处理的字段属性
if (is_save) { if (is_save) {
tempMedicationRequest.setEffectiveDoseStart(regAdviceSaveDto.getStartTime() != null ? regAdviceSaveDto.getStartTime() : startTime); // 医嘱开始时间 tempMedicationRequest.setEffectiveDoseStart(startTime); // 医嘱开始时间
tempMedicationRequest tempMedicationRequest
.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.MEDICATION_RES_NO.getPrefix(), 4)); .setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.MEDICATION_RES_NO.getPrefix(), 4));
tempMedicationRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源 tempMedicationRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
@@ -616,7 +615,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
} }
// 保存时处理的字段属性 // 保存时处理的字段属性
if (is_save) { if (is_save) {
longServiceRequest.setOccurrenceStartTime(regAdviceSaveDto.getStartTime() != null ? regAdviceSaveDto.getStartTime() : startTime); // 医嘱开始时间 longServiceRequest.setOccurrenceStartTime(startTime); // 医嘱开始时间
longServiceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4)); longServiceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4));
longServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源 longServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
longServiceRequest.setQuantity(new BigDecimal("1")); // 请求数量 | 诊疗的长期医嘱数量都是1 longServiceRequest.setQuantity(new BigDecimal("1")); // 请求数量 | 诊疗的长期医嘱数量都是1
@@ -628,7 +627,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
longServiceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者 longServiceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
longServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生 longServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
longServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id longServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
longServiceRequest.setOrgId(regAdviceSaveDto.getPositionId()); // 执行科室 longServiceRequest.setOrgId(regAdviceSaveDto.getEffectiveOrgId()); // 执行科室
longServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json longServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
longServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码 longServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
longServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id longServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
@@ -667,7 +666,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
} }
// 保存时处理的字段属性 // 保存时处理的字段属性
if (is_save) { if (is_save) {
tempServiceRequest.setOccurrenceStartTime(regAdviceSaveDto.getStartTime() != null ? regAdviceSaveDto.getStartTime() : startTime); // 医嘱开始时间 tempServiceRequest.setOccurrenceStartTime(startTime); // 医嘱开始时间
tempServiceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4)); tempServiceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4));
tempServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源 tempServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源
tempServiceRequest.setQuantity(regAdviceSaveDto.getQuantity()); // 请求数量 tempServiceRequest.setQuantity(regAdviceSaveDto.getQuantity()); // 请求数量
@@ -679,7 +678,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
tempServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生 tempServiceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
tempServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id tempServiceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
tempServiceRequest.setAuthoredTime(curDate); // 请求签发时间 tempServiceRequest.setAuthoredTime(curDate); // 请求签发时间
tempServiceRequest.setOrgId(regAdviceSaveDto.getPositionId()); // 执行科室 tempServiceRequest.setOrgId(regAdviceSaveDto.getEffectiveOrgId()); // 执行科室
tempServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json tempServiceRequest.setContentJson(regAdviceSaveDto.getContentJson()); // 请求内容json
tempServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码 tempServiceRequest.setYbClassEnum(regAdviceSaveDto.getYbClassEnum());// 类别医保编码
tempServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id tempServiceRequest.setConditionId(regAdviceSaveDto.getConditionId()); // 诊断id
@@ -813,7 +812,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
deviceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者 deviceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
deviceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生 deviceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
deviceRequest.setOrgId(regAdviceSaveDto.getFounderOrgId()); // 开方人科室 deviceRequest.setOrgId(regAdviceSaveDto.getFounderOrgId()); // 开方人科室
deviceRequest.setReqAuthoredTime(regAdviceSaveDto.getStartTime() != null ? regAdviceSaveDto.getStartTime() : startTime); // 医嘱开始时间 deviceRequest.setReqAuthoredTime(startTime); // 医嘱开始时间
deviceRequest.setPerformLocation(regAdviceSaveDto.getLocationId()); // 发放科室 deviceRequest.setPerformLocation(regAdviceSaveDto.getLocationId()); // 发放科室
deviceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id deviceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
deviceRequest.setPackageId(regAdviceSaveDto.getPackageId()); // 组套id deviceRequest.setPackageId(regAdviceSaveDto.getPackageId()); // 组套id
@@ -852,7 +851,7 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
deviceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者 deviceRequest.setPatientId(regAdviceSaveDto.getPatientId()); // 患者
deviceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生 deviceRequest.setRequesterId(regAdviceSaveDto.getPractitionerId()); // 开方医生
deviceRequest.setOrgId(regAdviceSaveDto.getFounderOrgId()); // 开方人科室 deviceRequest.setOrgId(regAdviceSaveDto.getFounderOrgId()); // 开方人科室
deviceRequest.setReqAuthoredTime(regAdviceSaveDto.getStartTime() != null ? regAdviceSaveDto.getStartTime() : startTime); // 医嘱开始时间 deviceRequest.setReqAuthoredTime(startTime); // 医嘱开始时间
deviceRequest.setPerformLocation(regAdviceSaveDto.getLocationId()); // 发放科室 deviceRequest.setPerformLocation(regAdviceSaveDto.getLocationId()); // 发放科室
deviceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id deviceRequest.setEncounterId(regAdviceSaveDto.getEncounterId()); // 就诊id
deviceRequest.setPackageId(regAdviceSaveDto.getPackageId()); // 组套id deviceRequest.setPackageId(regAdviceSaveDto.getPackageId()); // 组套id
@@ -1044,14 +1043,8 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
*/ */
@Override @Override
public R<?> stopRegAdvice(List<AdviceBatchOpParam> paramList) { public R<?> stopRegAdvice(List<AdviceBatchOpParam> paramList) {
// 获取停嘱时间:优先从前端传入的 stopTime否则用当前时间 // 当前时间
Date stopTime = paramList.stream() Date date = new Date();
.map(AdviceBatchOpParam::getStopTime)
.filter(Objects::nonNull)
.findFirst()
.orElse(new Date());
// 获取当前操作用户昵称作为停嘱医生
String stopUserName = SecurityUtils.getNickName();
// 药品 // 药品
List<AdviceBatchOpParam> medicineList = paramList.stream() List<AdviceBatchOpParam> medicineList = paramList.stream()
.filter(e -> ItemType.MEDICINE.getValue().equals(e.getAdviceType())).collect(Collectors.toList()); .filter(e -> ItemType.MEDICINE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
@@ -1066,112 +1059,15 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
= activityList.stream().map(AdviceBatchOpParam::getRequestId).collect(Collectors.toList()); = activityList.stream().map(AdviceBatchOpParam::getRequestId).collect(Collectors.toList());
if (!medicineRequestIds.isEmpty()) { if (!medicineRequestIds.isEmpty()) {
iMedicationRequestService.update(new LambdaUpdateWrapper<MedicationRequest>() iMedicationRequestService.update(new LambdaUpdateWrapper<MedicationRequest>()
.in(MedicationRequest::getId, medicineRequestIds) .in(MedicationRequest::getId, medicineRequestIds).set(MedicationRequest::getEffectiveDoseEnd, date)
.set(MedicationRequest::getEffectiveDoseEnd, stopTime) .set(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue()));
.set(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
.set(MedicationRequest::getUpdateBy, stopUserName));
} }
if (!activityRequestIds.isEmpty()) { if (!activityRequestIds.isEmpty()) {
iServiceRequestService.update(new LambdaUpdateWrapper<ServiceRequest>() iServiceRequestService.update(new LambdaUpdateWrapper<ServiceRequest>()
.in(ServiceRequest::getId, activityRequestIds) .in(ServiceRequest::getId, activityRequestIds).set(ServiceRequest::getOccurrenceEndTime, date)
.set(ServiceRequest::getOccurrenceEndTime, stopTime) .set(ServiceRequest::getStatusEnum, RequestStatus.STOPPED.getValue()));
.set(ServiceRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
.set(ServiceRequest::getUpdateBy, stopUserName));
} }
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"医嘱停止"})); return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"医嘱停止"}));
}
/**
* 住院医嘱取消停嘱(恢复)
*
* 核心业务逻辑:
* 1. 护士站校验:护士站尚未对该医嘱的停止进行"停止核对/确认"(即 dispense 状态未进入已发药/完成状态)
* 2. 药房端校验:药房尚未对该停嘱单进行退药接收/退费入库确认
* 3. 若校验通过,将医嘱状态复原为"已签发";清空停嘱时间与停嘱医生字段;
* 同时自动作废已生成的待发药退回/退药申请
*
* @param paramList 恢复参数
* @return 结果
*/
@Override
public R<?> cancelStopRegAdvice(List<AdviceBatchOpParam> paramList) {
// 药品
List<AdviceBatchOpParam> medicineList = paramList.stream()
.filter(e -> ItemType.MEDICINE.getValue().equals(e.getAdviceType())).collect(Collectors.toList());
List<Long> medicineRequestIds
= medicineList.stream().map(AdviceBatchOpParam::getRequestId).collect(Collectors.toList());
// 诊疗包含护理adviceType=26
List<AdviceBatchOpParam> activityList = paramList.stream()
.filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
|| (e.getAdviceType() != null && e.getAdviceType() == 26))
.collect(Collectors.toList());
List<Long> activityRequestIds
= activityList.stream().map(AdviceBatchOpParam::getRequestId).collect(Collectors.toList());
// ============ 前置校验 ============
// 1. 护士站校验:查询药品发放记录,确认护士站是否已执行停止核对(发药)
if (!medicineRequestIds.isEmpty()) {
List<MedicationDispense> dispenseList = iMedicationDispenseService.selectByRequestIdList(medicineRequestIds);
for (MedicationDispense dispense : dispenseList) {
// 如果发放状态 >= COMPLETED(4),说明护士站已发药/已确认停止
if (dispense.getStatusEnum() != null && dispense.getStatusEnum() >= DispenseStatus.COMPLETED.getValue()
&& !DispenseStatus.ON_HOLD.getValue().equals(dispense.getStatusEnum())
&& !DispenseStatus.STOPPED.getValue().equals(dispense.getStatusEnum())
&& !DispenseStatus.CANCELLED.getValue().equals(dispense.getStatusEnum())) {
throw new ServiceException("护士站已确认停止该医嘱,无法取消停嘱!");
}
// 2. 药房端校验:如果已有退药/退费记录,说明药房已处理
if (DispenseStatus.RETURNED.getValue().equals(dispense.getStatusEnum())
|| DispenseStatus.REFUNDED.getValue().equals(dispense.getStatusEnum())
|| DispenseStatus.PART_REFUND.getValue().equals(dispense.getStatusEnum())) {
throw new ServiceException("药房已完成退药处理,无法取消停嘱!");
}
}
}
// ============ 执行恢复 ============
if (!medicineRequestIds.isEmpty()) {
// 恢复药品请求状态为"已发送"(ACTIVE=2),清空停嘱时间和更新人
iMedicationRequestService.update(new LambdaUpdateWrapper<MedicationRequest>()
.in(MedicationRequest::getId, medicineRequestIds)
.set(MedicationRequest::getStatusEnum, RequestStatus.ACTIVE.getValue())
.set(MedicationRequest::getEffectiveDoseEnd, null)
.set(MedicationRequest::getUpdateBy, null));
// 作废/删除与这些药品请求相关的待退药发放记录
List<MedicationDispense> relatedDispenseList = iMedicationDispenseService.selectByRequestIdList(medicineRequestIds);
for (MedicationDispense dispense : relatedDispenseList) {
if (DispenseStatus.PENDING_REFUND.getValue().equals(dispense.getStatusEnum())
|| DispenseStatus.CANCELLED.getValue().equals(dispense.getStatusEnum())
|| DispenseStatus.ON_HOLD.getValue().equals(dispense.getStatusEnum())) {
// 将待退药/暂停/撤回的记录标记为草稿,或删除
iMedicationDispenseService.update(new LambdaUpdateWrapper<MedicationDispense>()
.eq(MedicationDispense::getId, dispense.getId())
.set(MedicationDispense::getStatusEnum, DispenseStatus.DRAFT.getValue())
.set(MedicationDispense::getStatusChangedTime, new Date()));
}
// 如果 dispense 已处于 STOPPED(6) 状态,也恢复为草稿以重新触发配药流程
if (DispenseStatus.STOPPED.getValue().equals(dispense.getStatusEnum())) {
iMedicationDispenseService.update(new LambdaUpdateWrapper<MedicationDispense>()
.eq(MedicationDispense::getId, dispense.getId())
.set(MedicationDispense::getStatusEnum, DispenseStatus.PREPARATION.getValue())
.set(MedicationDispense::getStatusChangedTime, new Date()));
}
}
}
if (!activityRequestIds.isEmpty()) {
// 恢复诊疗请求状态为"已发送"(ACTIVE=2),清空停嘱时间和更新人
iServiceRequestService.update(new LambdaUpdateWrapper<ServiceRequest>()
.in(ServiceRequest::getId, activityRequestIds)
.set(ServiceRequest::getStatusEnum, RequestStatus.ACTIVE.getValue())
.set(ServiceRequest::getOccurrenceEndTime, null)
.set(ServiceRequest::getUpdateBy, null));
}
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"医嘱恢复"}));
} }
} }

View File

@@ -5,7 +5,6 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R; import com.core.common.core.domain.R;
import com.core.common.enums.DelFlag;
import com.core.common.exception.ServiceException; import com.core.common.exception.ServiceException;
import com.core.common.utils.AssignSeqUtil; import com.core.common.utils.AssignSeqUtil;
import com.core.common.utils.MessageUtils; import com.core.common.utils.MessageUtils;
@@ -18,8 +17,6 @@ import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.*; import com.openhis.common.enums.*;
import com.openhis.document.domain.RequestForm; import com.openhis.document.domain.RequestForm;
import com.openhis.document.service.IRequestFormService; import com.openhis.document.service.IRequestFormService;
import com.openhis.lab.domain.Specimen;
import com.openhis.lab.service.ISpecimenService;
import com.openhis.web.doctorstation.dto.ActivityChildrenJsonParams; import com.openhis.web.doctorstation.dto.ActivityChildrenJsonParams;
import com.openhis.web.doctorstation.utils.AdviceUtils; import com.openhis.web.doctorstation.utils.AdviceUtils;
import com.openhis.web.regdoctorstation.appservice.IRequestFormManageAppService; import com.openhis.web.regdoctorstation.appservice.IRequestFormManageAppService;
@@ -70,39 +67,6 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
@Resource @Resource
IActivityDefinitionService iActivityDefinitionService; IActivityDefinitionService iActivityDefinitionService;
@Resource
ISpecimenService iSpecimenService;
/**
* 校验当前用户是否有权操作该申请单(申请者本人或管理员)
*/
private R<?> validateRequestFormPermission(RequestForm requestForm) {
if (SecurityUtils.isAdmin(SecurityUtils.getUserId())) {
return null;
}
Long currentPractitionerId = SecurityUtils.getLoginUser().getPractitionerId();
Long requesterId = requestForm.getRequesterId();
if (currentPractitionerId == null || requesterId == null
|| !currentPractitionerId.equals(requesterId)) {
return R.fail("无操作权限,仅申请开立者或管理员可操作");
}
return null;
}
/**
* 校验关联医嘱是否已采证(存在已采集/已接收标本则不可撤回)
*/
private boolean hasCollectedSpecimen(List<Long> serviceRequestIds) {
if (serviceRequestIds == null || serviceRequestIds.isEmpty()) {
return false;
}
long count = iSpecimenService.count(
new LambdaQueryWrapper<Specimen>()
.in(Specimen::getServiceId, serviceRequestIds)
.ge(Specimen::getCollectionStatusEnum, SpecCollectStatus.COLLECTED.getValue()));
return count > 0;
}
/** /**
* 保存申请单 * 保存申请单
* *
@@ -155,13 +119,10 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
return R.fail("无待签发的医嘱,该申请单不可编辑"); return R.fail("无待签发的医嘱,该申请单不可编辑");
} }
} else { } else {
// 根据申请单类型生成不同前缀的单 // 检查申请单JC检查+ Z住院标识+ yyMMdd日期+ 5位顺序
String dateStr = new java.text.SimpleDateFormat("yyMMdd").format(new Date()); String dateStr = new java.text.SimpleDateFormat("yyMMdd").format(new Date());
AssignSeqEnum seqEnum = ActivityDefCategory.PROCEDURE.getCode().equals(typeCode) int seq = assignSeqUtil.getSeqNoByDay(AssignSeqEnum.CHECK_APPLY_NO.getPrefix());
? AssignSeqEnum.SURGERY_APPLY_NO prescriptionNo = "JCZ" + dateStr + String.format("%05d", seq);
: AssignSeqEnum.CHECK_APPLY_NO;
int seq = assignSeqUtil.getSeqNoByDay(seqEnum.getPrefix());
prescriptionNo = seqEnum.getPrefix() + dateStr + String.format("%05d", seq);
} }
// 当前时间 // 当前时间
@@ -567,17 +528,12 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
if (requestForm == null) { if (requestForm == null) {
return R.fail("申请单不存在"); return R.fail("申请单不存在");
} }
R<?> permissionResult = validateRequestFormPermission(requestForm);
if (permissionResult != null) {
return permissionResult;
}
String prescriptionNo = requestForm.getPrescriptionNo(); String prescriptionNo = requestForm.getPrescriptionNo();
// 查询该申请单下所有 ServiceRequest含子项 // 查询该申请单下所有 ServiceRequest含子项
List<ServiceRequest> serviceRequests = iServiceRequestService.list( List<ServiceRequest> serviceRequests = iServiceRequestService.list(
new LambdaQueryWrapper<ServiceRequest>() new LambdaQueryWrapper<ServiceRequest>()
.eq(ServiceRequest::getPrescriptionNo, prescriptionNo) .eq(ServiceRequest::getPrescriptionNo, prescriptionNo));
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
if (serviceRequests == null || serviceRequests.isEmpty()) { if (serviceRequests == null || serviceRequests.isEmpty()) {
return R.fail("未找到关联的诊疗医嘱"); return R.fail("未找到关联的诊疗医嘱");
} }
@@ -607,7 +563,7 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
// 4. 删除申请单 // 4. 删除申请单
iRequestFormService.removeById(requestFormId); iRequestFormService.removeById(requestFormId);
log.info("申请单删除成功requestFormId={}, prescriptionNo={}", requestFormId, prescriptionNo); log.info("申请单删除成功requestFormId={}, prescriptionNo={}", requestFormId, prescriptionNo);
return R.ok("删除成功"); return R.ok("删除成功");
} }
@@ -620,47 +576,32 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
if (requestForm == null) { if (requestForm == null) {
return R.fail("申请单不存在"); return R.fail("申请单不存在");
} }
R<?> permissionResult = validateRequestFormPermission(requestForm);
if (permissionResult != null) {
return permissionResult;
}
String prescriptionNo = requestForm.getPrescriptionNo(); String prescriptionNo = requestForm.getPrescriptionNo();
// 查询该申请单下所有 ServiceRequest // 查询该申请单下所有 ServiceRequest
List<ServiceRequest> serviceRequests = iServiceRequestService.list( List<ServiceRequest> serviceRequests = iServiceRequestService.list(
new LambdaQueryWrapper<ServiceRequest>() new LambdaQueryWrapper<ServiceRequest>()
.eq(ServiceRequest::getPrescriptionNo, prescriptionNo) .eq(ServiceRequest::getPrescriptionNo, prescriptionNo));
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
if (serviceRequests == null || serviceRequests.isEmpty()) { if (serviceRequests == null || serviceRequests.isEmpty()) {
return R.fail("未找到关联的诊疗医嘱"); return R.fail("未找到关联的诊疗医嘱");
} }
// 校验:只有已签发(status=2)的申请单可撤回
boolean allActive = serviceRequests.stream()
.allMatch(sr -> RequestStatus.ACTIVE.getValue().equals(sr.getStatusEnum()));
if (!allActive) {
return R.fail("只有已签发状态的申请单可撤回");
}
// 将所有 ServiceRequest 状态改回待签发(DRAFT=0)
List<Long> serviceRequestIds = serviceRequests.stream() List<Long> serviceRequestIds = serviceRequests.stream()
.map(ServiceRequest::getId).collect(Collectors.toList()); .map(ServiceRequest::getId).collect(Collectors.toList());
iServiceRequestService.update(
// 校验:标本已采集则不可撤回
if (hasCollectedSpecimen(serviceRequestIds)) {
return R.fail("标本已采集,无法撤回");
}
// 校验任一ServiceRequest为ACTIVE(status=2)即可撤回与SQL的EXISTS逻辑一致
boolean hasActive = serviceRequests.stream()
.anyMatch(sr -> RequestStatus.ACTIVE.getValue().equals(sr.getStatusEnum()));
if (!hasActive) {
return R.fail("只有已签发且未采证的申请单可撤回");
}
// 将所有已签发的 ServiceRequest 状态改回待签发,与申请单展示状态同步
boolean updated = iServiceRequestService.update(
new ServiceRequest().setStatusEnum(RequestStatus.DRAFT.getValue()), new ServiceRequest().setStatusEnum(RequestStatus.DRAFT.getValue()),
new LambdaUpdateWrapper<ServiceRequest>() new LambdaUpdateWrapper<ServiceRequest>()
.in(ServiceRequest::getId, serviceRequestIds) .in(ServiceRequest::getId, serviceRequestIds));
.eq(ServiceRequest::getStatusEnum, RequestStatus.ACTIVE.getValue()));
if (!updated) {
return R.fail("撤回失败,医嘱状态已变更,请刷新后重试");
}
log.info("申请单撤回成功requestFormId={}, prescriptionNo={}", requestFormId, prescriptionNo); log.info("申请单撤回成功requestFormId={}, prescriptionNo={}", requestFormId, prescriptionNo);
return R.ok("撤回成功"); return R.ok("撤回成功");
} }

View File

@@ -28,7 +28,6 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.util.CollectionUtils;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -162,7 +161,7 @@ public class SpecialAdviceAppServiceImpl implements ISpecialAdviceAppService {
adviceBaseDto.setAdviceDefinitionId(definitionId); // 医嘱定义id adviceBaseDto.setAdviceDefinitionId(definitionId); // 医嘱定义id
// 对应的诊疗医嘱信息 // 对应的诊疗医嘱信息
activityAdviceBaseDto = iDoctorStationAdviceAppService.getAdviceBaseInfo(adviceBaseDto, null, null, activityAdviceBaseDto = iDoctorStationAdviceAppService.getAdviceBaseInfo(adviceBaseDto, null, null,
null, null, 1, 1, null, List.of(3), null, null).getRecords().get(0); null, null, 1, 1, Whether.NO.getValue(), List.of(3), null, null).getRecords().get(0);
// 逻辑1---------------------直接新增 // 逻辑1---------------------直接新增
longServiceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());// 请求状态 longServiceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());// 请求状态
longServiceRequest.setOccurrenceStartTime(startTime); // 医嘱开始时间 longServiceRequest.setOccurrenceStartTime(startTime); // 医嘱开始时间
@@ -209,7 +208,7 @@ public class SpecialAdviceAppServiceImpl implements ISpecialAdviceAppService {
adviceBaseDto.setAdviceDefinitionId(definitionId); // 医嘱定义id adviceBaseDto.setAdviceDefinitionId(definitionId); // 医嘱定义id
// 对应的诊疗医嘱信息 // 对应的诊疗医嘱信息
activityAdviceBaseDto = iDoctorStationAdviceAppService activityAdviceBaseDto = iDoctorStationAdviceAppService
.getAdviceBaseInfo(adviceBaseDto, null, null, null, null, 1, 1, null, List.of(3), null, null) .getAdviceBaseInfo(adviceBaseDto, null, null, null, null, 1, 1, Whether.NO.getValue(), List.of(3), null, null)
.getRecords().get(0); .getRecords().get(0);
longServiceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());// 请求状态 longServiceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());// 请求状态
@@ -349,7 +348,7 @@ public class SpecialAdviceAppServiceImpl implements ISpecialAdviceAppService {
adviceBaseDto.setAdviceDefinitionId(transferOrganizationDefinitionId); // 医嘱定义id adviceBaseDto.setAdviceDefinitionId(transferOrganizationDefinitionId); // 医嘱定义id
// 转科的医嘱信息 // 转科的医嘱信息
AdviceBaseDto activityAdviceBaseDto = iDoctorStationAdviceAppService AdviceBaseDto activityAdviceBaseDto = iDoctorStationAdviceAppService
.getAdviceBaseInfo(adviceBaseDto, null, null, null, null, 1, 1, null, List.of(3), null, null) .getAdviceBaseInfo(adviceBaseDto, null, null, null, null, 1, 1, Whether.NO.getValue(), List.of(3), null, null)
.getRecords().get(0); .getRecords().get(0);
// 保存转科医嘱请求 // 保存转科医嘱请求
ServiceRequest serviceRequest = new ServiceRequest(); ServiceRequest serviceRequest = new ServiceRequest();
@@ -401,7 +400,7 @@ public class SpecialAdviceAppServiceImpl implements ISpecialAdviceAppService {
// 计划出院时间 // 计划出院时间
Date endTime = leaveHospitalParam.getEndTime(); Date endTime = leaveHospitalParam.getEndTime();
if (endTime == null) { if (endTime == null) {
endTime = new Date(); endTime = endTime;
} }
// 就诊id // 就诊id
Long encounterId = leaveHospitalParam.getEncounterId(); Long encounterId = leaveHospitalParam.getEncounterId();
@@ -430,12 +429,9 @@ public class SpecialAdviceAppServiceImpl implements ISpecialAdviceAppService {
} }
// 出院的医嘱信息 // 出院的医嘱信息
List<AdviceBaseDto> adviceList = iDoctorStationAdviceAppService.getAdviceBaseInfo(null, null, null, AdviceBaseDto activityAdviceBaseDto = iDoctorStationAdviceAppService.getAdviceBaseInfo(null, null, null,
List.of(transferOrganizationDefinitionId), null, 1, 1, null, List.of(3), null, null).getRecords(); List.of(transferOrganizationDefinitionId), null, 1, 1, Whether.NO.getValue(), List.of(3), null, null).getRecords()
if (CollectionUtils.isEmpty(adviceList)) { .get(0);
return R.fail("未找到出院医嘱定义数据,请确认诊疗目录中已配置出院医嘱");
}
AdviceBaseDto activityAdviceBaseDto = adviceList.get(0);
// 保存出院医嘱请求 // 保存出院医嘱请求
ServiceRequest serviceRequest = new ServiceRequest(); ServiceRequest serviceRequest = new ServiceRequest();
serviceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());// 请求状态 serviceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());// 请求状态

View File

@@ -143,15 +143,4 @@ public class AdviceManageController {
return iAdviceManageAppService.stopRegAdvice(paramList); return iAdviceManageAppService.stopRegAdvice(paramList);
} }
/**
* 住院医嘱取消停嘱(恢复)
*
* @param paramList 恢复参数
* @return 结果
*/
@PostMapping(value = "/cancel-stop-reg-advice")
public R<?> cancelStopRegAdvice(@RequestBody List<AdviceBatchOpParam> paramList) {
return iAdviceManageAppService.cancelStopRegAdvice(paramList);
}
} }

View File

@@ -143,23 +143,14 @@ public class RequestFormManageController {
* 查询手术申请单 * 查询手术申请单
* *
* @param encounterId 就诊id * @param encounterId 就诊id
* @param startDate 开始日期可选格式yyyy-MM-dd
* @param endDate 结束日期可选格式yyyy-MM-dd
* @param status 单据状态(可选)
* @param keyword 关键字(可选,申请单号/手术项目名称模糊匹配)
* @return 手术申请单 * @return 手术申请单
*/ */
@GetMapping(value = "/get-surgery") @GetMapping(value = "/get-surgery")
public R<?> getSurgeryRequestForm( public R<?> getSurgeryRequestForm(@RequestParam(required = false) Long encounterId) {
@RequestParam(required = false) Long encounterId,
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate,
@RequestParam(required = false) String status,
@RequestParam(required = false) String keyword) {
if (encounterId == null) { if (encounterId == null) {
return R.fail("就诊ID不能为空"); return R.fail("就诊ID不能为空");
} }
return R.ok(iRequestFormManageAppService.getRequestForm(encounterId, ActivityDefCategory.PROCEDURE.getCode(), startDate, endDate, status, keyword)); return R.ok(iRequestFormManageAppService.getRequestForm(encounterId, ActivityDefCategory.PROCEDURE.getCode()));
} }
/** /**
* 分页查询手术申请单全局不需要encounterId用于门诊手术安排查找弹窗 * 分页查询手术申请单全局不需要encounterId用于门诊手术安排查找弹窗
@@ -203,8 +194,8 @@ public class RequestFormManageController {
* @return 结果 * @return 结果
*/ */
@PostMapping(value = "/delete") @PostMapping(value = "/delete")
public R<?> deleteRequestForm(@RequestBody Map<String, Object> data) { public R<?> deleteRequestForm(@RequestBody Map<String, Long> data) {
return iRequestFormManageAppService.deleteRequestForm(parseLong(data.get("requestFormId"))); return iRequestFormManageAppService.deleteRequestForm(data.get("requestFormId"));
} }
/** /**
@@ -214,24 +205,7 @@ public class RequestFormManageController {
* @return 结果 * @return 结果
*/ */
@PostMapping(value = "/withdraw") @PostMapping(value = "/withdraw")
public R<?> withdrawRequestForm(@RequestBody Map<String, Object> data) { public R<?> withdrawRequestForm(@RequestBody Map<String, Long> data) {
return iRequestFormManageAppService.withdrawRequestForm(parseLong(data.get("requestFormId"))); return iRequestFormManageAppService.withdrawRequestForm(data.get("requestFormId"));
}
private Long parseLong(Object value) {
if (value == null) {
return null;
}
if (value instanceof Long) {
return (Long) value;
}
if (value instanceof Number) {
return ((Number) value).longValue();
}
try {
return Long.parseLong(value.toString());
} catch (NumberFormatException e) {
return null;
}
} }
} }

View File

@@ -1,13 +1,10 @@
package com.openhis.web.regdoctorstation.dto; package com.openhis.web.regdoctorstation.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.util.Date;
/** /**
* 医嘱批量操作参数类 * 医嘱批量操作参数类
*/ */
@@ -24,10 +21,4 @@ public class AdviceBatchOpParam {
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long requestId; private Long requestId;
/**
* 停嘱时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private Date stopTime;
} }

View File

@@ -10,8 +10,4 @@ import lombok.experimental.Accessors;
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
public class RegAdviceSaveDto extends AdviceSaveDto { public class RegAdviceSaveDto extends AdviceSaveDto {
/** 请求类型 */
private Integer categoryEnum;
} }

View File

@@ -31,8 +31,8 @@ public class HomeController {
HomeStatisticsDto statisticsDto = homeStatisticsService.getHomeStatistics(); HomeStatisticsDto statisticsDto = homeStatisticsService.getHomeStatistics();
// 获取待写病历数量 // 获取待写病历数量
Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId(); Long userId = SecurityUtils.getLoginUser().getUserId();
R<?> pendingEmrCount = doctorStationEmrAppService.getPendingEmrCount(practitionerId, null); R<?> pendingEmrCount = doctorStationEmrAppService.getPendingEmrCount(userId);
// 将待写病历数量添加到统计数据中 // 将待写病历数量添加到统计数据中
statisticsDto.setPendingEmr((Integer) pendingEmrCount.getData()); statisticsDto.setPendingEmr((Integer) pendingEmrCount.getData());

View File

@@ -74,6 +74,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.eq(TriageQueueItem::getTenantId, tenantId) .eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getQueueDate, qd) .eq(TriageQueueItem::getQueueDate, qd)
.eq(TriageQueueItem::getDeleteFlag, "0") .eq(TriageQueueItem::getDeleteFlag, "0")
.ne(TriageQueueItem::getStatus, TriageQueueStatus.COMPLETED.getValue())
.orderByAsc(TriageQueueItem::getQueueOrder); .orderByAsc(TriageQueueItem::getQueueOrder);
// 如果指定了科室,按科室过滤;否则查询所有科室(全科模式) // 如果指定了科室,按科室过滤;否则查询所有科室(全科模式)
@@ -91,6 +92,14 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
} }
}); });
} }
// 双重保险:再次过滤掉 COMPLETED 状态的患者(防止数据库中有异常数据)
if (list != null && !list.isEmpty()) {
int beforeSize = list.size();
list = list.stream()
.filter(item -> !TriageQueueStatus.COMPLETED.getValue().equals(item.getStatus()))
.collect(java.util.stream.Collectors.toList());
}
return R.ok(list); return R.ok(list);
} }

View File

@@ -516,7 +516,6 @@
T1.patient_id AS patient_id, T1.patient_id AS patient_id,
'med_medication_definition' AS advice_table_name, 'med_medication_definition' AS advice_table_name,
T1.medication_id AS advice_definition_id T1.medication_id AS advice_definition_id
, T1.back_reason AS reason_text
FROM med_medication_request AS T1 FROM med_medication_request AS T1
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
AND T2.delete_flag = '0' AND T2.delete_flag = '0'
@@ -578,7 +577,6 @@
T1.patient_id AS patient_id, T1.patient_id AS patient_id,
'med_medication_definition' AS advice_table_name, 'med_medication_definition' AS advice_table_name,
T3.ID AS advice_definition_id T3.ID AS advice_definition_id
, T2.back_reason AS reason_text
FROM adm_charge_item AS T1 FROM adm_charge_item AS T1
INNER JOIN med_medication_request AS T2 ON T2.ID = T1.service_id AND T2.delete_flag = '0' 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' LEFT JOIN med_medication_definition AS T3 ON T3.ID = T2.medication_id AND T3.delete_flag = '0'
@@ -586,9 +584,6 @@
WHERE T1.delete_flag = '0' WHERE T1.delete_flag = '0'
AND T1.service_table = #{MED_MEDICATION_REQUEST} AND T1.service_table = #{MED_MEDICATION_REQUEST}
<if test="historyFlag == '0'.toString()"> <if test="historyFlag == '0'.toString()">
<if test="generateSourceEnum != null">
AND (T2.generate_source_enum IS NULL OR T2.generate_source_enum = #{generateSourceEnum})
</if>
AND T1.encounter_id = #{encounterId} AND T1.encounter_id = #{encounterId}
</if> </if>
<if test="historyFlag == '1'.toString()"> <if test="historyFlag == '1'.toString()">
@@ -642,7 +637,6 @@
CI.patient_id AS patient_id, CI.patient_id AS patient_id,
'adm_device_definition' AS advice_table_name, 'adm_device_definition' AS advice_table_name,
CI.product_id AS advice_definition_id CI.product_id AS advice_definition_id
, NULL AS reason_text
FROM adm_charge_item AS CI 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 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' LEFT JOIN wor_device_request DR ON DR.id = CI.service_id AND DR.delete_flag = '0'
@@ -697,7 +691,6 @@
T1.patient_id AS patient_id, T1.patient_id AS patient_id,
'adm_device_definition' AS advice_table_name, 'adm_device_definition' AS advice_table_name,
T1.device_def_id AS advice_definition_id T1.device_def_id AS advice_definition_id
, NULL AS reason_text
FROM wor_device_request AS T1 FROM wor_device_request AS T1
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
AND T2.delete_flag = '0' AND T2.delete_flag = '0'
@@ -754,7 +747,6 @@
T1.patient_id AS patient_id, T1.patient_id AS patient_id,
'wor_activity_definition' AS advice_table_name, 'wor_activity_definition' AS advice_table_name,
T1.activity_id AS advice_definition_id T1.activity_id AS advice_definition_id
, T1.reason_text AS reason_text
FROM wor_service_request AS T1 FROM wor_service_request AS T1
LEFT JOIN wor_activity_definition AS T2 LEFT JOIN wor_activity_definition AS T2
ON T2.ID = T1.activity_id ON T2.ID = T1.activity_id
@@ -902,6 +894,7 @@
AND (t1.name ILIKE '%' || #{searchKey} || '%' OR t1.py_str ILIKE '%' || #{searchKey} || '%') AND (t1.name ILIKE '%' || #{searchKey} || '%' OR t1.py_str ILIKE '%' || #{searchKey} || '%')
</if> </if>
ORDER BY t1.ID, t1.name ASC, t2.ID ASC ORDER BY t1.ID, t1.name ASC, t2.ID ASC
LIMIT #{limit} OFFSET #{offset}
</select> </select>
<!-- 检查/检验项目专用分页查询:仅查指定 category_code + 定价,无库存/草稿库存/取药科室等无关逻辑 --> <!-- 检查/检验项目专用分页查询:仅查指定 category_code + 定价,无库存/草稿库存/取药科室等无关逻辑 -->

View File

@@ -4,38 +4,4 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.openhis.web.doctorstation.mapper.DoctorStationEmrAppMapper"> <mapper namespace="com.openhis.web.doctorstation.mapper.DoctorStationEmrAppMapper">
<select id="getPendingEmrList" resultType="java.util.HashMap">
SELECT e.id AS "encounterId",
e.patient_id AS "patientId",
p.name AS "patientName",
p.gender_enum AS "gender",
p.birth_date AS "birthDate",
e.create_time AS "registerTime",
e.bus_no AS "busNo"
FROM adm_encounter e
INNER JOIN adm_encounter_participant ep ON e.id = ep.encounter_id AND ep.practitioner_id = #{doctorId}
LEFT JOIN adm_patient p ON e.patient_id = p.id
LEFT JOIN doc_emr emr ON e.id = emr.encounter_id
WHERE e.status_enum = 2
AND emr.id IS NULL
<if test="patientName != null and patientName != ''">
AND p.name LIKE CONCAT('%', #{patientName}, '%')
</if>
ORDER BY e.create_time DESC
LIMIT #{pageSize} OFFSET #{offset}
</select>
<select id="getPendingEmrCount" resultType="java.lang.Long">
SELECT COUNT(*)
FROM adm_encounter e
INNER JOIN adm_encounter_participant ep ON e.id = ep.encounter_id AND ep.practitioner_id = #{doctorId}
LEFT JOIN adm_patient p ON e.patient_id = p.id
LEFT JOIN doc_emr emr ON e.id = emr.encounter_id
WHERE e.status_enum = 2
AND emr.id IS NULL
<if test="patientName != null and patientName != ''">
AND p.name LIKE CONCAT('%', #{patientName}, '%')
</if>
</select>
</mapper> </mapper>

View File

@@ -11,10 +11,6 @@
p.birth_date, p.birth_date,
p.phone, p.phone,
p.address, p.address,
p.address_province,
p.address_city,
p.address_district,
p.address_street,
p.work_company, p.work_company,
p.nationality_code, p.nationality_code,
p.marital_status_enum, p.marital_status_enum,

View File

@@ -214,13 +214,10 @@
T1.dispense_per_duration AS dispense_per_duration, T1.dispense_per_duration AS dispense_per_duration,
T2.part_percent AS part_percent, T2.part_percent AS part_percent,
ccd.name AS condition_definition_name, ccd.name AS condition_definition_name,
T1.effective_dose_start AS start_time,
T1.therapy_enum AS therapyEnum, T1.therapy_enum AS therapyEnum,
T1.sort_number AS sort_number, T1.sort_number AS sort_number,
T1.based_on_id AS based_on_id, T1.based_on_id AS based_on_id,
T1.medication_id AS advice_definition_id T1.medication_id AS advice_definition_id
T1.effective_dose_end AS stop_time,
T1.update_by AS stop_user_name
FROM med_medication_request AS T1 FROM med_medication_request AS T1
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
AND T2.delete_flag = '0' AND T2.delete_flag = '0'
@@ -272,11 +269,8 @@
'' AS condition_definition_name, '' AS condition_definition_name,
2 AS therapyEnum, 2 AS therapyEnum,
99 AS sort_number, 99 AS sort_number,
T1.req_authored_time AS start_time,
T1.based_on_id AS based_on_id, T1.based_on_id AS based_on_id,
T1.device_def_id AS advice_definition_id T1.device_def_id AS advice_definition_id
NULL AS stop_time,
'' AS stop_user_name
FROM wor_device_request AS T1 FROM wor_device_request AS T1
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
AND T2.delete_flag = '0' AND T2.delete_flag = '0'
@@ -325,11 +319,8 @@
'' AS condition_definition_name, '' AS condition_definition_name,
COALESCE(T1.therapy_enum, 2) AS therapyEnum, COALESCE(T1.therapy_enum, 2) AS therapyEnum,
99 AS sort_number, 99 AS sort_number,
T1.occurrence_start_time AS start_time,
T1.based_on_id AS based_on_id, T1.based_on_id AS based_on_id,
T1.activity_id AS advice_definition_id T1.activity_id AS advice_definition_id
T1.occurrence_end_time AS stop_time,
T1.update_by AS stop_user_name
FROM wor_service_request AS T1 FROM wor_service_request AS T1
LEFT JOIN wor_activity_definition AS T2 LEFT JOIN wor_activity_definition AS T2
ON T2.ID = T1.activity_id ON T2.ID = T1.activity_id

View File

@@ -35,36 +35,21 @@
WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0' WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0'
AND ws.status_enum = 8 AND ws.status_enum = 8
) THEN 6 ) THEN 6
WHEN EXISTS (
SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0'
AND ws.status_enum = 5
) THEN 7
WHEN EXISTS ( WHEN EXISTS (
SELECT 1 FROM wor_service_request ws SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0' WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0'
AND ws.status_enum = 3 AND ws.status_enum = 3
) THEN 5 ) THEN 5
WHEN EXISTS (
SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0'
AND ws.status_enum = 12
) THEN 4
WHEN EXISTS (
SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0'
AND ws.status_enum = 11
) THEN 3
WHEN EXISTS (
SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0'
AND ws.status_enum = 10
) THEN 2
WHEN EXISTS ( WHEN EXISTS (
SELECT 1 FROM wor_service_request ws SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0' WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0'
AND ws.status_enum = 2 AND ws.status_enum = 2
) THEN 1 ) THEN 1
WHEN EXISTS (
SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no AND ws.delete_flag = '0'
AND ws.status_enum = 5
) THEN 7
ELSE 0 ELSE 0
END AS computed_status END AS computed_status
FROM doc_request_form AS drf FROM doc_request_form AS drf

View File

@@ -274,10 +274,6 @@ public enum AssignSeqEnum {
* 检查申请单号(住院) * 检查申请单号(住院)
*/ */
CHECK_APPLY_NO("72", "检查申请单号", "JCZ"), CHECK_APPLY_NO("72", "检查申请单号", "JCZ"),
/**
* 手术申请单号(住院)
*/
SURGERY_APPLY_NO("73", "手术申请单号", "SSZ"),
/** /**
* b 病历文书 * b 病历文书
*/ */

View File

@@ -57,22 +57,7 @@ public enum RequestStatus implements HisEnumInterface {
/** /**
* 未知 * 未知
*/ */
UNKNOWN(9, "unknown", "未知"), UNKNOWN(9, "unknown", "未知");
/**
* 已校对(检查申请:护士校对通过)
*/
CHECK_VERIFIED(10, "check_verified", "已校对"),
/**
* 待接收(检查申请:等待医技科室接单)
*/
PENDING_RECEIVE(11, "pending_receive", "待接收"),
/**
* 已接收(检查申请:医技科室已接单)
*/
CHECK_RECEIVED(12, "check_received", "已接收");
@EnumValue @EnumValue
private final Integer value; private final Integer value;

View File

@@ -1,6 +1,7 @@
package com.openhis.lab.domain; package com.openhis.lab.domain;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
@@ -106,10 +107,12 @@ public class InspectionPackage {
/** 创建时间 */ /** 创建时间 */
@TableField("create_time") @TableField("create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime; private LocalDateTime createTime;
/** 更新时间 */ /** 更新时间 */
@TableField("update_time") @TableField("update_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime; private LocalDateTime updateTime;
/** 删除标志false-正常true-删除) */ /** 删除标志false-正常true-删除) */

View File

@@ -1,6 +1,7 @@
package com.openhis.lab.domain; package com.openhis.lab.domain;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
@@ -75,10 +76,12 @@ public class InspectionPackageDetail {
/** 创建时间 */ /** 创建时间 */
@TableField("create_time") @TableField("create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime; private LocalDateTime createTime;
/** 更新时间 */ /** 更新时间 */
@TableField("update_time") @TableField("update_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime; private LocalDateTime updateTime;
/** 删除标志false-正常true-删除) */ /** 删除标志false-正常true-删除) */

View File

@@ -111,9 +111,6 @@ public class MedicationRequest extends HisBaseEntity {
/** 支持用药信息 */ /** 支持用药信息 */
private String supportInfo; private String supportInfo;
/** 退回原因 */
private String backReason;
/** 请求开始时间 */ /** 请求开始时间 */
private Date reqAuthoredTime; private Date reqAuthoredTime;

View File

@@ -30,7 +30,7 @@ public interface IMedicationRequestService extends IService<MedicationRequest> {
* @param practitionerId 校对人 * @param practitionerId 校对人
* @param checkDate 校对时间 * @param checkDate 校对时间
*/ */
void updateDraftStatusBatch(List<Long> requestIdList, Long practitionerId, Date checkDate, String backReason); void updateDraftStatusBatch(List<Long> requestIdList, Long practitionerId, Date checkDate);
/** /**
* 更新请求状态:取消 * 更新请求状态:取消

View File

@@ -44,7 +44,7 @@ public class MedicationRequestServiceImpl extends ServiceImpl<MedicationRequestM
* @param checkDate 校对时间 * @param checkDate 校对时间
*/ */
@Override @Override
public void updateDraftStatusBatch(List<Long> requestIdList, Long practitionerId, Date checkDate, String backReason) { public void updateDraftStatusBatch(List<Long> requestIdList, Long practitionerId, Date checkDate) {
LambdaUpdateWrapper<MedicationRequest> updateWrapper = LambdaUpdateWrapper<MedicationRequest> updateWrapper =
new LambdaUpdateWrapper<MedicationRequest>().in(MedicationRequest::getId, requestIdList) new LambdaUpdateWrapper<MedicationRequest>().in(MedicationRequest::getId, requestIdList)
.set(MedicationRequest::getStatusEnum, RequestStatus.DRAFT.getValue()); .set(MedicationRequest::getStatusEnum, RequestStatus.DRAFT.getValue());
@@ -54,9 +54,6 @@ public class MedicationRequestServiceImpl extends ServiceImpl<MedicationRequestM
if (checkDate != null) { if (checkDate != null) {
updateWrapper.set(MedicationRequest::getCheckTime, checkDate); updateWrapper.set(MedicationRequest::getCheckTime, checkDate);
} }
if (backReason != null) {
updateWrapper.set(MedicationRequest::getBackReason, backReason);
}
baseMapper.update(null, updateWrapper); baseMapper.update(null, updateWrapper);
} }
@@ -78,9 +75,6 @@ public class MedicationRequestServiceImpl extends ServiceImpl<MedicationRequestM
if (checkDate != null) { if (checkDate != null) {
updateWrapper.set(MedicationRequest::getCheckTime, checkDate); updateWrapper.set(MedicationRequest::getCheckTime, checkDate);
} }
if (backReason != null) {
updateWrapper.set(MedicationRequest::getBackReason, backReason);
}
baseMapper.update(null, updateWrapper); baseMapper.update(null, updateWrapper);
} }

View File

@@ -39,22 +39,6 @@ public interface IServiceRequestService extends IService<ServiceRequest> {
*/ */
void updateCompleteRequestStatus(List<Long> serReqIdList, Long practitionerId, Date checkDate); void updateCompleteRequestStatus(List<Long> serReqIdList, Long practitionerId, Date checkDate);
/**
* 更新检查申请状态已校对护士校对检查申请后状态为CHECK_VERIFIED而非COMPLETED
*
* @param serReqIdList 服务请求id列表
* @param practitionerId 校对人
* @param checkDate 校对时间
*/
void updateCheckVerifiedStatus(List<Long> serReqIdList, Long practitionerId, Date checkDate);
/**
* 更新检查申请状态待接收护士执行检查申请后状态为PENDING_RECEIVE
*
* @param serReqIdList 服务请求id列表
*/
void updatePendingReceiveStatus(List<Long> serReqIdList);
/** /**
* 获取执行过的诊疗数据 * 获取执行过的诊疗数据
* *
@@ -109,7 +93,7 @@ public interface IServiceRequestService extends IService<ServiceRequest> {
* @param practitionerId 校对人 * @param practitionerId 校对人
* @param checkDate 校对时间 * @param checkDate 校对时间
*/ */
void updateDraftStatus(List<Long> serviceRequestIdList, Long practitionerId, Date checkDate, String backReason); void updateDraftStatus(List<Long> serviceRequestIdList, Long practitionerId, Date checkDate);
/** /**
* 更新服务状态:待发送 * 更新服务状态:待发送

View File

@@ -66,31 +66,6 @@ public class ServiceRequestServiceImpl extends ServiceImpl<ServiceRequestMapper,
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode())); .eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
} }
/**
* 更新检查申请状态已校对护士校对检查申请后状态为CHECK_VERIFIED而非COMPLETED
*
* @param serReqIdList 服务请求id列表
*/
@Override
public void updateCheckVerifiedStatus(List<Long> serReqIdList, Long practitionerId, Date checkDate) {
baseMapper.update(new ServiceRequest().setStatusEnum(RequestStatus.CHECK_VERIFIED.getValue())
.setPerformerCheckId(SecurityUtils.getLoginUser().getPractitionerId()).setCheckTime(DateUtils.getNowDate()),
new LambdaUpdateWrapper<ServiceRequest>().in(ServiceRequest::getId, serReqIdList)
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
}
/**
* 更新检查申请状态待接收护士执行检查申请后状态为PENDING_RECEIVE
*
* @param serReqIdList 服务请求id列表
*/
@Override
public void updatePendingReceiveStatus(List<Long> serReqIdList) {
baseMapper.update(new ServiceRequest().setStatusEnum(RequestStatus.PENDING_RECEIVE.getValue()),
new LambdaUpdateWrapper<ServiceRequest>().in(ServiceRequest::getId, serReqIdList)
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
}
/** /**
* 获取执行过的诊疗数据 * 获取执行过的诊疗数据
* *
@@ -197,15 +172,9 @@ public class ServiceRequestServiceImpl extends ServiceImpl<ServiceRequestMapper,
* @param checkDate 校对时间 * @param checkDate 校对时间
*/ */
@Override @Override
public void updateDraftStatus(List<Long> serviceRequestIdList, Long practitionerId, Date checkDate, String backReason) { public void updateDraftStatus(List<Long> serviceRequestIdList, Long practitionerId, Date checkDate) {
ServiceRequest updateEntity = new ServiceRequest() baseMapper.update(new ServiceRequest().setStatusEnum(RequestStatus.DRAFT.getValue())
.setStatusEnum(RequestStatus.DRAFT.getValue()) .setPerformerCheckId(SecurityUtils.getLoginUser().getPractitionerId()).setCheckTime(DateUtils.getNowDate()),
.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) new LambdaUpdateWrapper<ServiceRequest>().in(ServiceRequest::getId, serviceRequestIdList)
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode())); .eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
} }

View File

@@ -65,7 +65,7 @@
"typescript": "^5.9.3", "typescript": "^5.9.3",
"unplugin-auto-import": "0.17.1", "unplugin-auto-import": "0.17.1",
"unplugin-vue-setup-extend-plus": "1.0.0", "unplugin-vue-setup-extend-plus": "1.0.0",
"vite": "^5.0.4", "vite": "5.0.4",
"vite-plugin-compression": "0.5.1", "vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1", "vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-mcp": "^0.3.2", "vite-plugin-vue-mcp": "^0.3.2",
@@ -3093,6 +3093,41 @@
"url": "https://opencollective.com/vitest" "url": "https://opencollective.com/vitest"
} }
}, },
"node_modules/@vitest/mocker": {
"version": "4.1.2",
"resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.1.2.tgz",
"integrity": "sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==",
"dev": true,
"dependencies": {
"@vitest/spy": "4.1.2",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.21"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"msw": "^2.4.9",
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"msw": {
"optional": true
},
"vite": {
"optional": true
}
}
},
"node_modules/@vitest/mocker/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/@vitest/pretty-format": { "node_modules/@vitest/pretty-format": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.1.2.tgz", "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.1.2.tgz",
@@ -12636,10 +12671,9 @@
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.0.4", "version": "5.0.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.0.4.tgz", "resolved": "https://registry.npmmirror.com/vite/-/vite-5.0.4.tgz",
"integrity": "sha512-RzAr8LSvM8lmhB4tQ5OPcBhpjOZRZjuxv9zO5UcxeoY2bd3kP3Ticd40Qma9/BqZ8JS96Ll/jeBX9u+LJZrhVg==", "integrity": "sha512-RzAr8LSvM8lmhB4tQ5OPcBhpjOZRZjuxv9zO5UcxeoY2bd3kP3Ticd40Qma9/BqZ8JS96Ll/jeBX9u+LJZrhVg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "^0.19.3", "esbuild": "^0.19.3",
"postcss": "^8.4.31", "postcss": "^8.4.31",
@@ -13302,33 +13336,6 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/vitest/node_modules/@vitest/mocker": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.2.tgz",
"integrity": "sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/spy": "4.1.2",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.21"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"msw": "^2.4.9",
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"msw": {
"optional": true
},
"vite": {
"optional": true
}
}
},
"node_modules/vitest/node_modules/chokidar": { "node_modules/vitest/node_modules/chokidar": {
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -13391,16 +13398,6 @@
"@esbuild/win32-x64": "0.27.7" "@esbuild/win32-x64": "0.27.7"
} }
}, },
"node_modules/vitest/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/vitest/node_modules/fsevents": { "node_modules/vitest/node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",

View File

@@ -83,7 +83,7 @@
"typescript": "^5.9.3", "typescript": "^5.9.3",
"unplugin-auto-import": "0.17.1", "unplugin-auto-import": "0.17.1",
"unplugin-vue-setup-extend-plus": "1.0.0", "unplugin-vue-setup-extend-plus": "1.0.0",
"vite": "^5.0.4", "vite": "5.0.4",
"vite-plugin-compression": "0.5.1", "vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1", "vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-mcp": "^0.3.2", "vite-plugin-vue-mcp": "^0.3.2",

View File

@@ -162,24 +162,6 @@ export function getG(svg, viewConfig) {
// 设置数据 // 设置数据
export function getData(allData) { export function getData(allData) {
const rowsData = allData.rows; // allData, '【全部数据】' const rowsData = allData.rows; // allData, '【全部数据】'
// 兼容旧数据:将旧 typeCode 映射到新 typeCode心率 004→014脉搏 005→002呼吸 006→001
const OLD_CODE_MAP = { '004': '014', '005': '002', '006': '001' };
rowsData.forEach(row => {
if (row.rowBOS) {
const prependItems = [];
row.rowBOS.forEach(item => {
const newCode = OLD_CODE_MAP[item.typeCode];
// 始终添加映射条目,用 unshift 插入数组头部
// 这样 getType 的 find() 优先匹配映射后的编码(如脉冲、呼吸)
// 即使存在同编码的旧条目(如血压舒张压用 002、收缩压用 001
// 映射后的脉搏(002)和呼吸(001)条目排在前面,确保图表正确渲染
if (newCode) {
prependItems.push({ ...item, typeCode: newCode });
}
});
row.rowBOS.unshift(...prependItems);
}
});
const infoData = allData.grParamBOS; const infoData = allData.grParamBOS;
const typesData = getTypeDatas(allData.types, allData.grParamBOS.beginDate); const typesData = getTypeDatas(allData.types, allData.grParamBOS.beginDate);
const selectOp = allData.selectOp; const selectOp = allData.selectOp;

View File

@@ -10,27 +10,15 @@
@click="clickAct" @click="clickAct"
> >
<div v-if="data.bedOperationalStatus==='U'"> <div v-if="data.bedOperationalStatus==='U'">
<img <img :src="emptyBed" class="pf_card_emptyBed_img">
:src="emptyBed" <div class="pf_card_emptyBed_text">{{ data.bedName }}</div>
class="pf_card_emptyBed_img"
>
<div class="pf_card_emptyBed_text">
{{ data.bedName }}
</div>
</div> </div>
<div v-else> <div v-else>
<div <div v-if="data.isDischarge" class="pf_card_discharge">
v-if="data.isDischarge"
class="pf_card_discharge"
>
<span style="margin-left: 6px"></span> <span style="margin-left: 6px"></span>
</div> </div>
<div class="pf_card_card"> <div class="pf_card_card">
<CardSign <CardSign :color="getBedBackColor(data.triageLevel)" :title="data.bedName" :tail="getDisplay(data.triageLevel)" />
:color="getBedBackColor(data.triageLevel)"
:title="data.bedName"
:tail="getDisplay(data.triageLevel)"
/>
</div> </div>
<div class="pf_card_nameSexAndAge"> <div class="pf_card_nameSexAndAge">
<span class="pf_card_name">{{ data.patientName }}</span> <span class="pf_card_name">{{ data.patientName }}</span>
@@ -40,48 +28,20 @@
<span style="margin-right: 16px">入室时间</span> <span style="margin-right: 16px">入室时间</span>
{{ moment(data.checkInWardTime).format('YYYY-MM-DD HH:mm') }} {{ moment(data.checkInWardTime).format('YYYY-MM-DD HH:mm') }}
</div> </div>
<div class="pf_card_noCode"> <div class="pf_card_noCode">{{ data.hisId }}</div>
{{ data.hisId }} <div class="pf_card_rescueTimeText">{{ rescueTimeText() }}</div>
</div> <div v-if="data.diag!==''" class="pf_card_diagnosis">
<div class="pf_card_rescueTimeText"> <div class="card-rectangle-text">{{ data.diag }}</div>
{{ rescueTimeText() }}
</div>
<div
v-if="data.diag!==''"
class="pf_card_diagnosis"
>
<div class="card-rectangle-text">
{{ data.diag }}
</div>
<span style="margin-left: 4px">(诊断)</span> <span style="margin-left: 4px">(诊断)</span>
</div> </div>
<div <div v-if="isNewSign()" class="card-rectangle"></div>
v-if="isNewSign()" <div v-if="is72HourSign()" class="card-rectangle2">超72H</div>
class="card-rectangle"
>
</div>
<div
v-if="is72HourSign()"
class="card-rectangle2"
>
超72H
</div>
<hr class="pf_card_line"> <hr class="pf_card_line">
<div class="pf_card_nursingMeasuresString"> <div class="pf_card_nursingMeasuresString">{{ getStringByCode(data.nursingMeasures, nursingMeasures) }}</div>
{{ getStringByCode(data.nursingMeasures, nursingMeasures) }} <div class="pf_card_specialArrangementString">{{ getStringByCode(data.specialArrangement, specialArrangementList) }}</div>
</div> <div v-if="false" class="pf_card_btn" @click="moreClick">更多</div>
<div class="pf_card_specialArrangementString">
{{ getStringByCode(data.specialArrangement, specialArrangementList) }}
</div>
<div
v-if="false"
class="pf_card_btn"
@click="moreClick"
>
更多
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>

View File

@@ -6,7 +6,7 @@
:data="item" :data="item"
:bed-config="bedConfig" :bed-config="bedConfig"
@click="clickAct" @click="clickAct"
@more-click="moreClickAct" @moreClick="moreClickAct"
/> />
</div> </div>
</template> </template>

View File

@@ -1,19 +1,9 @@
<template> <template>
<div class="printCard"> <div class="printCard">
<div <div ref="refQr" style="float: left; margin: 30px 15px">
ref="refQr" <img :src="emptyBed" style="height: 120px" class="pf_card_emptyBed_img">
style="float: left; margin: 30px 15px"
>
<img
:src="emptyBed"
style="height: 120px"
class="pf_card_emptyBed_img"
>
</div> </div>
<div <div class="printView_content" style=" margin: 30px 0">
class="printView_content"
style=" margin: 30px 0"
>
<div> <div>
<span>床号</span> <span>床号</span>
<span>{{ printData.bedName }}</span> <span>{{ printData.bedName }}</span>

View File

@@ -1,9 +1,6 @@
<template> <template>
<div class="recordBill"> <div class="recordBill">
<div <div id="div1" class="printView_header">
id="div1"
class="printView_header"
>
<div style="text-align: center; height: 40px"> <div style="text-align: center; height: 40px">
护理交接班 护理交接班
</div> </div>
@@ -21,83 +18,35 @@
/> />
</div> </div>
</div> </div>
<div <div id="div2" class="printView_content">
id="div2" <table border="1" cellSpacing="0" width="98%" cellPadding="1" style=" border-collapse:collapse; font-size: 14px" bordercolor="#333333">
class="printView_content"
>
<table
border="1"
cellSpacing="0"
width="98%"
cellPadding="1"
style=" border-collapse:collapse; font-size: 14px"
bordercolor="#333333"
>
<thead> <thead>
<TR> <TR>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 40px" align="center">类别</DIV>
style="width: 40px"
align="center"
>
类别
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 50px" align="center">床号</DIV>
style="width: 50px"
align="center"
>
床号
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 60px" align="center">姓名</DIV>
style="width: 60px"
align="center"
>
姓名
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 90px" align="center">主诉</DIV>
style="width: 90px"
align="center"
>
主诉
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 90px" align="center">既往史</DIV>
style="width: 90px"
align="center"
>
既往史
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 90px" align="center">诊断</DIV>
style="width: 90px"
align="center"
>
诊断
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 155px" align="center">交接信息</DIV>
style="width: 155px"
align="center"
>
交接信息
</DIV>
</TD> </TD>
</TR> </TR>
</thead> </thead>
<tbody> <tbody>
<tr <tr v-for="item in printData.shiftRecordItems" :key="item.id">
v-for="item in printData.shiftRecordItems"
:key="item.id"
>
<td v-html="item.typeDisplay" /> <td v-html="item.typeDisplay" />
<td v-html="item.bedName" /> <td v-html="item.bedName" />
<td v-html="item.patientName" /> <td v-html="item.patientName" />

View File

@@ -1,9 +1,6 @@
<template> <template>
<div class="recordBill"> <div class="recordBill">
<div <div :id="'exeSheetTitle' + printData.id" class="printView_header">
:id="'exeSheetTitle' + printData.id"
class="printView_header"
>
<div style="text-align: center; height: 60px"> <div style="text-align: center; height: 60px">
{{ userStore.hospitalName }}医嘱执行单 {{ userStore.hospitalName }}医嘱执行单
</div> </div>
@@ -19,119 +16,51 @@
<span style="display: inline-block; width: 140px">性别{{!printData.patientInfo.gender? '':printData.patientInfo.gender.display}}</span> <span style="display: inline-block; width: 140px">性别{{!printData.patientInfo.gender? '':printData.patientInfo.gender.display}}</span>
</div>--> </div>-->
</div> </div>
<div <div :id="'exeSheet' + printData.id" class="printView_content">
:id="'exeSheet' + printData.id" <table border="1" cellSpacing="0" width="97%" cellPadding="1" style=" border-collapse:collapse; font-size: 13px" bordercolor="#333333">
class="printView_content"
>
<table
border="1"
cellSpacing="0"
width="97%"
cellPadding="1"
style=" border-collapse:collapse; font-size: 13px"
bordercolor="#333333"
>
<thead> <thead>
<TR> <TR>
<TD rowspan="1"> <TD rowspan="1">
<DIV style="width: 65px;text-align: center"> <DIV style="width: 65px;text-align: center">医嘱日期</DIV>
医嘱日期
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 120px" align="center">医嘱</DIV>
style="width: 120px"
align="center"
>
医嘱
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 10px" align="center" />
style="width: 10px"
align="center"
/>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 70px" align="center">嘱托</DIV>
style="width: 70px"
align="center"
>
嘱托
</DIV>
</TD> </TD>
<TD rowspan="1"> <TD rowspan="1">
<DIV <DIV style="width: 60px" align="center">用量</DIV>
style="width: 60px"
align="center"
>
用量
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 40px" align="center">用法</DIV>
style="width: 40px"
align="center"
>
用法
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 40px" align="center">频次</DIV>
style="width: 40px"
align="center"
>
频次
</DIV>
</TD> </TD>
<TD rowspan="1"> <TD rowspan="1">
<DIV <DIV style="width: 65px" align="center">开立医生</DIV>
style="width: 65px"
align="center"
>
开立医生
</DIV>
</TD> </TD>
<TD rowspan="1"> <TD rowspan="1">
<DIV <DIV style="width: 65px" align="center">执行时间</DIV>
style="width: 65px"
align="center"
>
执行时间
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 65px" align="center">执行护士</DIV>
style="width: 65px"
align="center"
>
执行护士
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 55px" align="center">终止时间</DIV>
style="width: 55px"
align="center"
>
终止时间
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 55px" align="center">终止人</DIV>
style="width: 55px"
align="center"
>
终止人
</DIV>
</TD> </TD>
</TR> </TR>
</thead> </thead>
<tbody> <tbody>
<tr <tr v-for="item in printData.recordData" :key="item.id">
v-for="item in printData.recordData"
:key="item.id"
>
<td v-html="item.moTime" /> <td v-html="item.moTime" />
<td v-html="item.orderName" /> <td v-html="item.orderName" />
<td v-html="item.flag" /> <td v-html="item.flag" />
@@ -141,20 +70,12 @@
<td v-html="item.frequency" /> <td v-html="item.frequency" />
<td :id="item.id"> <td :id="item.id">
<span v-if="(item.docSignImage === ''||item.docSignImage === null)">{{ item.moDocName }}</span> <span v-if="(item.docSignImage === ''||item.docSignImage === null)">{{ item.moDocName }}</span>
<img <img v-if="(item.docSignImage !== ''&&item.docSignImage !== null)" :src="'data:image/png;base64,'+ item.docSignImage" style="height: 100%; width: 100%;object-fit: cover;">
v-if="(item.docSignImage !== ''&&item.docSignImage !== null)"
:src="'data:image/png;base64,'+ item.docSignImage"
style="height: 100%; width: 100%;object-fit: cover;"
>
</td> </td>
<td v-html="item.occurrence" /> <td v-html="item.occurrence" />
<td :id="item.id"> <td :id="item.id">
<span v-if="(item.perNurserSignImage === ''||item.perNurserSignImage === null)">{{ item.performName }}</span> <span v-if="(item.perNurserSignImage === ''||item.perNurserSignImage === null)">{{ item.performName }}</span>
<img <img v-if="(item.perNurserSignImage !== ''&&item.perNurserSignImage !== null)" :src="'data:image/png;base64,'+ item.perNurserSignImage" style="height: 100%; width: 100%;object-fit: cover;">
v-if="(item.perNurserSignImage !== ''&&item.perNurserSignImage !== null)"
:src="'data:image/png;base64,'+ item.perNurserSignImage"
style="height: 100%; width: 100%;object-fit: cover;"
>
</td> </td>
<td /> <td />
<td /> <td />
@@ -170,6 +91,10 @@ import { simplePrint, PRINT_TEMPLATE } from '@/utils/printUtils.js'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
export default { export default {
setup() {
const userStore = useUserStore();
return { userStore };
},
props: { props: {
printData: { printData: {
type: Object, type: Object,
@@ -178,10 +103,6 @@ export default {
} }
} }
}, },
setup() {
const userStore = useUserStore();
return { userStore };
},
data() { data() {
return {} return {}
}, },

View File

@@ -12,51 +12,23 @@
</div> </div>
</div> </div>
<div style="display: block; width: 120px; height: 60px; float:left; "> <div style="display: block; width: 120px; height: 60px; float:left; ">
<div <div :id="getId(printData.id)" style="float: left; margin: 5px;" />
:id="getId(printData.id)"
style="float: left; margin: 5px;"
/>
<span style="float: left; margin: 5px">{{ printData.priority }}</span> <span style="float: left; margin: 5px">{{ printData.priority }}</span>
</div> </div>
</div> </div>
<div :id="printData.id + 'div2'"> <div :id="printData.id + 'div2'">
<table <table border="1" cellSpacing="0" width="390px" cellPadding="1" style="margin-left: 8px; border-collapse:collapse; table-layout: fixed; font-size: 14px" bordercolor="#333333">
border="1"
cellSpacing="0"
width="390px"
cellPadding="1"
style="margin-left: 8px; border-collapse:collapse; table-layout: fixed; font-size: 14px"
bordercolor="#333333"
>
<thead> <thead>
<TR> <TR>
<Th <Th style="width: 160px" v-html="'药品名称'" />
style="width: 160px" <Th style="width: 75px" v-html="'用量'" />
v-html="'药品名称'" <Th style="width: 10px" v-html="''" />
/> <Th style="width: 50px" v-html="'频次'" />
<Th <Th style="width: 75px" v-html="'用法'" />
style="width: 75px"
v-html="'用量'"
/>
<Th
style="width: 10px"
v-html="''"
/>
<Th
style="width: 50px"
v-html="'频次'"
/>
<Th
style="width: 75px"
v-html="'用法'"
/>
</TR> </TR>
</thead> </thead>
<tbody> <tbody>
<tr <tr v-for="item in printData.orderDetail" :key="item.id">
v-for="item in printData.orderDetail"
:key="item.id"
>
<td v-html="item.orderName" /> <td v-html="item.orderName" />
<td v-html="item.doseOnce + item.doseUnit" /> <td v-html="item.doseOnce + item.doseUnit" />
<td v-html="item.flag" /> <td v-html="item.flag" />

View File

@@ -1,9 +1,6 @@
<template> <template>
<div class="recordBill"> <div class="recordBill">
<div <div id="div1" class="printView_header">
id="div1"
class="printView_header"
>
<div style="text-align: center; font-size: 20px; height: 40px"> <div style="text-align: center; font-size: 20px; height: 40px">
{{ userStore.hospitalName }}输液执行单 {{ userStore.hospitalName }}输液执行单
</div> </div>
@@ -16,88 +13,38 @@
<span style="margin-left: 18px">科室{{ printData.patientInfo.deptName }}</span> <span style="margin-left: 18px">科室{{ printData.patientInfo.deptName }}</span>
</div> </div>
</div> </div>
<div <div id="div2" class="printView_content">
id="div2" <table border="1" cellSpacing="0" cellPadding="1" style=" border-collapse:collapse; font-size: 14px" bordercolor="#333333">
class="printView_content"
>
<table
border="1"
cellSpacing="0"
cellPadding="1"
style=" border-collapse:collapse; font-size: 14px"
bordercolor="#333333"
>
<thead> <thead>
<TR style="height: 30px"> <TR style="height: 30px">
<TD rowspan="1"> <TD rowspan="1">
<DIV <DIV style="width: 35px" align="center">时间</DIV>
style="width: 35px"
align="center"
>
时间
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 280px" align="center">药品名称</DIV>
style="width: 280px"
align="center"
>
药品名称
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 10px" align="center" />
style="width: 10px"
align="center"
/>
</TD> </TD>
<TD rowspan="1"> <TD rowspan="1">
<DIV <DIV style="width: 55px" align="center">剂量</DIV>
style="width: 55px"
align="center"
>
剂量
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 30px" align="center">频次</DIV>
style="width: 30px"
align="center"
>
频次
</DIV>
</TD> </TD>
<TD colspan="1"> <TD colspan="1">
<DIV <DIV style="width: 55px" align="center">用法</DIV>
style="width: 55px"
align="center"
>
用法
</DIV>
</TD> </TD>
<TD rowspan="1"> <TD rowspan="1">
<DIV <DIV style="width: 70px" align="center">执行时间</DIV>
style="width: 70px"
align="center"
>
执行时间
</DIV>
</TD> </TD>
<TD rowspan="1"> <TD rowspan="1">
<DIV <DIV style="width: 55px" align="center">执行人</DIV>
style="width: 55px"
align="center"
>
执行人
</DIV>
</TD> </TD>
</TR> </TR>
</thead> </thead>
<tbody style=" border-collapse:collapse;"> <tbody style=" border-collapse:collapse;">
<tr <tr v-for="item in printData.recordData" :key="item.id">
v-for="item in printData.recordData"
:key="item.id"
>
<td v-html="item.moTime.substring(0,16)" /> <td v-html="item.moTime.substring(0,16)" />
<td v-html="item.orderName" /> <td v-html="item.orderName" />
<td v-html="item.flag" /> <td v-html="item.flag" />

View File

@@ -1,15 +1,9 @@
<template> <template>
<div> <div>
<div ref="print"> <div ref="print">
<div <div v-for="item in printData" :key="item.id">
v-for="item in printData"
:key="item.id"
>
<div class="myccs2"> <div class="myccs2">
<injectLabel <injectLabel :ref="item.id" :print-data="item" />
:ref="item.id"
:print-data="item"
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,21 +1,10 @@
<template> <template>
<div> <div>
<div ref="print"> <div ref="print">
<div <div v-for="item in printData" :key="item.id">
v-for="item in printData"
:key="item.id"
>
<div class="myccs2"> <div class="myccs2">
<orderSheet <orderSheet v-if="!item.type" :ref="item.id" :print-data="item" />
v-if="!item.type" <exeOrderSheet v-if="item.type" :ref="item.id" :print-data="item" />
:ref="item.id"
:print-data="item"
/>
<exeOrderSheet
v-if="item.type"
:ref="item.id"
:print-data="item"
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,10 +1,5 @@
<template> <template>
<Graphics <Graphics v-if="graphicsDataDone" :value="resInfo" print @done="printPage" />
v-if="graphicsDataDone"
:value="resInfo"
print
@done="printPage"
/>
</template> </template>
<script setup> <script setup>

View File

@@ -21,10 +21,7 @@
<span>分诊时间</span> <span>分诊时间</span>
<span>{{ printData.triageTime }}</span> <span>{{ printData.triageTime }}</span>
</div> </div>
<img <img ref="refQr" style="position: absolute; top: 10px; left: 100px" />
ref="refQr"
style="position: absolute; top: 10px; left: 100px"
>
</div> </div>
</template> </template>
<script> <script>
@@ -33,6 +30,10 @@ import useUserStore from '@/store/modules/user';
export default { export default {
name: 'TriageTicket', name: 'TriageTicket',
setup() {
const userStore = useUserStore();
return { userStore };
},
props: { props: {
printData: { printData: {
type: Object, type: Object,
@@ -47,10 +48,6 @@ export default {
}, },
}, },
}, },
setup() {
const userStore = useUserStore();
return { userStore };
},
data() { data() {
return {}; return {};
}, },

View File

@@ -2,10 +2,7 @@
<div> <div>
<div ref="print"> <div ref="print">
<div class="myccs2"> <div class="myccs2">
<triageTicketNew <triageTicketNew ref="printTriage" :print-data="printData" />
ref="printTriage"
:print-data="printData"
/>
</div> </div>
<!-- <div v-for="item in printData" :key="item.id">--> <!-- <div v-for="item in printData" :key="item.id">-->
<!-- <div class="myccs2">--> <!-- <div class="myccs2">-->

View File

@@ -6,9 +6,7 @@
<span style="font-weight: bolder; font-size: 18px; line-height: 36px">{{ printData.greenText }}</span> <span style="font-weight: bolder; font-size: 18px; line-height: 36px">{{ printData.greenText }}</span>
<span style="font-weight: bolder; font-size: 18px; line-height: 36px">分诊单</span> <span style="font-weight: bolder; font-size: 18px; line-height: 36px">分诊单</span>
</div> </div>
<div style="position: absolute; top: 135px; text-align: center; width: 300px"> <div style="position: absolute; top: 135px; text-align: center; width: 300px">{{ printData.hisId }}</div>
{{ printData.hisId }}
</div>
<div style="position: absolute; top: 155px; text-align: center; width: 300px"> <div style="position: absolute; top: 155px; text-align: center; width: 300px">
{{ printData.triageLevel }}{{ printData.dept }} {{ printData.triageLevel }}{{ printData.dept }}
</div> </div>
@@ -109,18 +107,10 @@
" "
/> />
<div style="margin-left: 15px"> <div style="margin-left: 15px">
<div style="font-size: 14px; margin-top: 15px; font-weight: bolder"> <div style="font-size: 14px; margin-top: 15px; font-weight: bolder">请仔细核对个人信息后进行挂号</div>
请仔细核对个人信息后进行挂号 <div style="margin-top: 5px; font-size: 14px">为了您家人和其他患者的健康</div>
</div> <div style="font-size: 14px">请您保持就诊秩序保持诊区安静</div>
<div style="margin-top: 5px; font-size: 14px"> <div style="font-size: 14px">祝您早日康复</div>
为了您家人和其他患者的健康
</div>
<div style="font-size: 14px">
请您保持就诊秩序保持诊区安静
</div>
<div style="font-size: 14px">
祝您早日康复
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,9 +1,6 @@
<template> <template>
<div class="printWrist"> <div class="printWrist">
<div <div id="div1" class="printView_content">
id="div1"
class="printView_content"
>
<div style="margin: 1px;font-size: 12px"> <div style="margin: 1px;font-size: 12px">
<span>姓名: </span> <span>姓名: </span>
<span>{{ printData.patientName }}</span> <span>{{ printData.patientName }}</span>
@@ -25,11 +22,7 @@
<span style="position: absolute; left: 140px">{{ printData.triageLevel }}</span> <span style="position: absolute; left: 140px">{{ printData.triageLevel }}</span>
</div> </div>
</div> </div>
<div <div id="qrcode" ref="refQr" style="padding-top: 1px" />
id="qrcode"
ref="refQr"
style="padding-top: 1px"
/>
</div> </div>
</template> </template>
<script> <script>

View File

@@ -1,21 +1,9 @@
<template> <template>
<el-breadcrumb <el-breadcrumb class="app-breadcrumb" separator="/">
class="app-breadcrumb"
separator="/"
>
<transition-group name="breadcrumb"> <transition-group name="breadcrumb">
<el-breadcrumb-item <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
v-for="(item,index) in levelList" <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
:key="item.path" <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
>
<span
v-if="item.redirect === 'noRedirect' || index == levelList.length - 1"
class="no-redirect"
>{{ item.meta.title }}</span>
<a
v-else
@click.prevent="handleLink(item)"
>{{ item.meta.title }}</a>
</el-breadcrumb-item> </el-breadcrumb-item>
</transition-group> </transition-group>
</el-breadcrumb> </el-breadcrumb>

View File

@@ -1,103 +1,51 @@
<template> <template>
<el-form> <el-form>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="1">
v-model="radioValue"
:label="1"
>
允许的通配符[, - * ? / L W] 允许的通配符[, - * ? / L W]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="2">
v-model="radioValue"
:label="2"
>
不指定 不指定
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="3">
v-model="radioValue"
:label="3"
>
周期从 周期从
<el-input-number <el-input-number v-model='cycle01' :min="1" :max="30" /> -
v-model="cycle01" <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="31" />
:min="1"
:max="30"
/> -
<el-input-number
v-model="cycle02"
:min="cycle01 + 1"
:max="31"
/>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="4">
v-model="radioValue"
:label="4"
>
<el-input-number <el-input-number v-model='average01' :min="1" :max="30" /> 号开始
v-model="average01" <el-input-number v-model='average02' :min="1" :max="31 - average01" /> 日执行一次
:min="1"
:max="30"
/> 号开始
<el-input-number
v-model="average02"
:min="1"
:max="31 - average01"
/> 日执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="5">
v-model="radioValue"
:label="5"
>
每月 每月
<el-input-number <el-input-number v-model='workday' :min="1" :max="31" /> 号最近的那个工作日
v-model="workday"
:min="1"
:max="31"
/> 号最近的那个工作日
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="6">
v-model="radioValue"
:label="6"
>
本月最后一天 本月最后一天
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="7">
v-model="radioValue"
:label="7"
>
指定 指定
<el-select <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
v-model="checkboxList" <el-option v-for="item in 31" :key="item" :label="item" :value="item" />
clearable
placeholder="可多选"
multiple
:multiple-limit="10"
>
<el-option
v-for="item in 31"
:key="item"
:label="item"
:value="item"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>

View File

@@ -1,71 +1,32 @@
<template> <template>
<el-form> <el-form>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="1">
v-model="radioValue"
:label="1"
>
小时允许的通配符[, - * /] 小时允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="2">
v-model="radioValue"
:label="2"
>
周期从 周期从
<el-input-number <el-input-number v-model='cycle01' :min="0" :max="22" /> -
v-model="cycle01" <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="23" />
:min="0"
:max="22"
/> -
<el-input-number
v-model="cycle02"
:min="cycle01 + 1"
:max="23"
/>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="3">
v-model="radioValue"
:label="3"
>
<el-input-number <el-input-number v-model='average01' :min="0" :max="22" /> 时开始
v-model="average01" <el-input-number v-model='average02' :min="1" :max="23 - average01" /> 小时执行一次
:min="0"
:max="22"
/> 时开始
<el-input-number
v-model="average02"
:min="1"
:max="23 - average01"
/> 小时执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="4">
v-model="radioValue"
:label="4"
>
指定 指定
<el-select <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
v-model="checkboxList" <el-option v-for="item in 24" :key="item" :label="item - 1" :value="item - 1" />
clearable
placeholder="可多选"
multiple
:multiple-limit="10"
>
<el-option
v-for="item in 24"
:key="item"
:label="item - 1"
:value="item - 1"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>

View File

@@ -1,208 +1,120 @@
<template> <template>
<div> <div>
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane <el-tab-pane label="秒" v-if="shouldHide('second')">
v-if="shouldHide('second')"
label="秒"
>
<CrontabSecond <CrontabSecond
@update="updateCrontabValue"
:check="checkNumber"
:cron="crontabValueObj"
ref="cronsecond" ref="cronsecond"
:check="checkNumber"
:cron="crontabValueObj"
@update="updateCrontabValue"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="分钟" v-if="shouldHide('min')">
v-if="shouldHide('min')"
label="分钟"
>
<CrontabMin <CrontabMin
@update="updateCrontabValue"
:check="checkNumber"
:cron="crontabValueObj"
ref="cronmin" ref="cronmin"
:check="checkNumber"
:cron="crontabValueObj"
@update="updateCrontabValue"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="小时" v-if="shouldHide('hour')">
v-if="shouldHide('hour')"
label="小时"
>
<CrontabHour <CrontabHour
@update="updateCrontabValue"
:check="checkNumber"
:cron="crontabValueObj"
ref="cronhour" ref="cronhour"
:check="checkNumber"
:cron="crontabValueObj"
@update="updateCrontabValue"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="日" v-if="shouldHide('day')">
v-if="shouldHide('day')"
label="日"
>
<CrontabDay <CrontabDay
@update="updateCrontabValue"
:check="checkNumber"
:cron="crontabValueObj"
ref="cronday" ref="cronday"
:check="checkNumber"
:cron="crontabValueObj"
@update="updateCrontabValue"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="月" v-if="shouldHide('month')">
v-if="shouldHide('month')"
label="月"
>
<CrontabMonth <CrontabMonth
@update="updateCrontabValue"
:check="checkNumber"
:cron="crontabValueObj"
ref="cronmonth" ref="cronmonth"
:check="checkNumber"
:cron="crontabValueObj"
@update="updateCrontabValue"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="周" v-if="shouldHide('week')">
v-if="shouldHide('week')"
label="周"
>
<CrontabWeek <CrontabWeek
ref="cronweek" @update="updateCrontabValue"
:check="checkNumber" :check="checkNumber"
:cron="crontabValueObj" :cron="crontabValueObj"
@update="updateCrontabValue" ref="cronweek"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="年" v-if="shouldHide('year')">
v-if="shouldHide('year')"
label="年"
>
<CrontabYear <CrontabYear
ref="cronyear" @update="updateCrontabValue"
:check="checkNumber" :check="checkNumber"
:cron="crontabValueObj" :cron="crontabValueObj"
@update="updateCrontabValue" ref="cronyear"
/> />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<div class="popup-main"> <div class="popup-main">
<div class="popup-result"> <div class="popup-result">
<p class="title"> <p class="title">时间表达式</p>
时间表达式
</p>
<table> <table>
<thead> <thead>
<th <th v-for="item of tabTitles" :key="item">{{item}}</th>
v-for="item of tabTitles"
:key="item"
>
{{ item }}
</th>
<th>Cron 表达式</th> <th>Cron 表达式</th>
</thead> </thead>
<tbody> <tbody>
<td> <td>
<span v-if="crontabValueObj.second.length < 10">{{ crontabValueObj.second }}</span> <span v-if="crontabValueObj.second.length < 10">{{crontabValueObj.second}}</span>
<el-tooltip <el-tooltip v-else :content="crontabValueObj.second" placement="top"><span>{{crontabValueObj.second}}</span></el-tooltip>
v-else
:content="crontabValueObj.second"
placement="top"
>
<span>{{ crontabValueObj.second }}</span>
</el-tooltip>
</td> </td>
<td> <td>
<span v-if="crontabValueObj.min.length < 10">{{ crontabValueObj.min }}</span> <span v-if="crontabValueObj.min.length < 10">{{crontabValueObj.min}}</span>
<el-tooltip <el-tooltip v-else :content="crontabValueObj.min" placement="top"><span>{{crontabValueObj.min}}</span></el-tooltip>
v-else
:content="crontabValueObj.min"
placement="top"
>
<span>{{ crontabValueObj.min }}</span>
</el-tooltip>
</td> </td>
<td> <td>
<span v-if="crontabValueObj.hour.length < 10">{{ crontabValueObj.hour }}</span> <span v-if="crontabValueObj.hour.length < 10">{{crontabValueObj.hour}}</span>
<el-tooltip <el-tooltip v-else :content="crontabValueObj.hour" placement="top"><span>{{crontabValueObj.hour}}</span></el-tooltip>
v-else
:content="crontabValueObj.hour"
placement="top"
>
<span>{{ crontabValueObj.hour }}</span>
</el-tooltip>
</td> </td>
<td> <td>
<span v-if="crontabValueObj.day.length < 10">{{ crontabValueObj.day }}</span> <span v-if="crontabValueObj.day.length < 10">{{crontabValueObj.day}}</span>
<el-tooltip <el-tooltip v-else :content="crontabValueObj.day" placement="top"><span>{{crontabValueObj.day}}</span></el-tooltip>
v-else
:content="crontabValueObj.day"
placement="top"
>
<span>{{ crontabValueObj.day }}</span>
</el-tooltip>
</td> </td>
<td> <td>
<span v-if="crontabValueObj.month.length < 10">{{ crontabValueObj.month }}</span> <span v-if="crontabValueObj.month.length < 10">{{crontabValueObj.month}}</span>
<el-tooltip <el-tooltip v-else :content="crontabValueObj.month" placement="top"><span>{{crontabValueObj.month}}</span></el-tooltip>
v-else
:content="crontabValueObj.month"
placement="top"
>
<span>{{ crontabValueObj.month }}</span>
</el-tooltip>
</td> </td>
<td> <td>
<span v-if="crontabValueObj.week.length < 10">{{ crontabValueObj.week }}</span> <span v-if="crontabValueObj.week.length < 10">{{crontabValueObj.week}}</span>
<el-tooltip <el-tooltip v-else :content="crontabValueObj.week" placement="top"><span>{{crontabValueObj.week}}</span></el-tooltip>
v-else
:content="crontabValueObj.week"
placement="top"
>
<span>{{ crontabValueObj.week }}</span>
</el-tooltip>
</td> </td>
<td> <td>
<span v-if="crontabValueObj.year.length < 10">{{ crontabValueObj.year }}</span> <span v-if="crontabValueObj.year.length < 10">{{crontabValueObj.year}}</span>
<el-tooltip <el-tooltip v-else :content="crontabValueObj.year" placement="top"><span>{{crontabValueObj.year}}</span></el-tooltip>
v-else
:content="crontabValueObj.year"
placement="top"
>
<span>{{ crontabValueObj.year }}</span>
</el-tooltip>
</td> </td>
<td class="result"> <td class="result">
<span v-if="crontabValueString.length < 90">{{ crontabValueString }}</span> <span v-if="crontabValueString.length < 90">{{crontabValueString}}</span>
<el-tooltip <el-tooltip v-else :content="crontabValueString" placement="top"><span>{{crontabValueString}}</span></el-tooltip>
v-else
:content="crontabValueString"
placement="top"
>
<span>{{ crontabValueString }}</span>
</el-tooltip>
</td> </td>
</tbody> </tbody>
</table> </table>
</div> </div>
<CrontabResult :ex="crontabValueString" /> <CrontabResult :ex="crontabValueString"></CrontabResult>
<div class="pop_btn"> <div class="pop_btn">
<el-button <el-button type="primary" @click="submitFill">确定</el-button>
type="primary" <el-button type="warning" @click="clearCron">重置</el-button>
@click="submitFill" <el-button @click="hidePopup">取消</el-button>
>
确定
</el-button>
<el-button
type="warning"
@click="clearCron"
>
重置
</el-button>
<el-button @click="hidePopup">
取消
</el-button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,71 +1,32 @@
<template> <template>
<el-form> <el-form>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="1">
v-model="radioValue"
:label="1"
>
分钟允许的通配符[, - * /] 分钟允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="2">
v-model="radioValue"
:label="2"
>
周期从 周期从
<el-input-number <el-input-number v-model='cycle01' :min="0" :max="58" /> -
v-model="cycle01" <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="59" /> 分钟
:min="0"
:max="58"
/> -
<el-input-number
v-model="cycle02"
:min="cycle01 + 1"
:max="59"
/> 分钟
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="3">
v-model="radioValue"
:label="3"
>
<el-input-number <el-input-number v-model='average01' :min="0" :max="58" /> 分钟开始
v-model="average01" <el-input-number v-model='average02' :min="1" :max="59 - average01" /> 分钟执行一次
:min="0"
:max="58"
/> 分钟开始
<el-input-number
v-model="average02"
:min="1"
:max="59 - average01"
/> 分钟执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="4">
v-model="radioValue"
:label="4"
>
指定 指定
<el-select <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
v-model="checkboxList" <el-option v-for="item in 60" :key="item" :label="item - 1" :value="item - 1" />
clearable
placeholder="可多选"
multiple
:multiple-limit="10"
>
<el-option
v-for="item in 60"
:key="item"
:label="item - 1"
:value="item - 1"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>

View File

@@ -1,71 +1,32 @@
<template> <template>
<el-form> <el-form>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="1">
v-model="radioValue"
:label="1"
>
允许的通配符[, - * /] 允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="2">
v-model="radioValue"
:label="2"
>
周期从 周期从
<el-input-number <el-input-number v-model='cycle01' :min="1" :max="11" /> -
v-model="cycle01" <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="12" />
:min="1"
:max="11"
/> -
<el-input-number
v-model="cycle02"
:min="cycle01 + 1"
:max="12"
/>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="3">
v-model="radioValue"
:label="3"
>
<el-input-number <el-input-number v-model='average01' :min="1" :max="11" /> 月开始
v-model="average01" <el-input-number v-model='average02' :min="1" :max="12 - average01" /> 月月执行一次
:min="1"
:max="11"
/> 月开始
<el-input-number
v-model="average02"
:min="1"
:max="12 - average01"
/> 月月执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="4">
v-model="radioValue"
:label="4"
>
指定 指定
<el-select <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="8">
v-model="checkboxList" <el-option v-for="item in monthList" :key="item.key" :label="item.value" :value="item.key" />
clearable
placeholder="可多选"
multiple
:multiple-limit="8"
>
<el-option
v-for="item in monthList"
:key="item.key"
:label="item.value"
:value="item.key"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>

View File

@@ -1,20 +1,11 @@
<template> <template>
<div class="popup-result"> <div class="popup-result">
<p class="title"> <p class="title">最近5次运行时间</p>
最近5次运行时间
</p>
<ul class="popup-result-scroll"> <ul class="popup-result-scroll">
<template v-if="isShow"> <template v-if='isShow'>
<li <li v-for='item in resultList' :key="item">{{item}}</li>
v-for="item in resultList"
:key="item"
>
{{ item }}
</li>
</template> </template>
<li v-else> <li v-else>计算结果中...</li>
计算结果中...
</li>
</ul> </ul>
</div> </div>
</template> </template>

View File

@@ -1,71 +1,32 @@
<template> <template>
<el-form> <el-form>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="1">
v-model="radioValue"
:label="1"
>
允许的通配符[, - * /] 允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="2">
v-model="radioValue"
:label="2"
>
周期从 周期从
<el-input-number <el-input-number v-model='cycle01' :min="0" :max="58" /> -
v-model="cycle01" <el-input-number v-model='cycle02' :min="cycle01 + 1" :max="59" />
:min="0"
:max="58"
/> -
<el-input-number
v-model="cycle02"
:min="cycle01 + 1"
:max="59"
/>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="3">
v-model="radioValue"
:label="3"
>
<el-input-number <el-input-number v-model='average01' :min="0" :max="58" /> 秒开始
v-model="average01" <el-input-number v-model='average02' :min="1" :max="59 - average01" /> 秒执行一次
:min="0"
:max="58"
/> 秒开始
<el-input-number
v-model="average02"
:min="1"
:max="59 - average01"
/> 秒执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="4">
v-model="radioValue"
:label="4"
>
指定 指定
<el-select <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="10">
v-model="checkboxList" <el-option v-for="item in 60" :key="item" :label="item - 1" :value="item - 1" />
clearable
placeholder="可多选"
multiple
:multiple-limit="10"
>
<el-option
v-for="item in 60"
:key="item"
:label="item - 1"
:value="item - 1"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>

View File

@@ -1,129 +1,70 @@
<template> <template>
<el-form> <el-form>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="1">
v-model="radioValue"
:label="1"
>
允许的通配符[, - * ? / L #] 允许的通配符[, - * ? / L #]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="2">
v-model="radioValue"
:label="2"
>
不指定 不指定
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="3">
v-model="radioValue"
:label="3"
>
周期从 周期从
<el-select <el-select clearable v-model="cycle01">
v-model="cycle01"
clearable
>
<el-option <el-option
v-for="(item,index) of weekList" v-for="(item,index) of weekList"
:key="index" :key="index"
:label="item.value" :label="item.value"
:value="item.key" :value="item.key"
:disabled="item.key === 7" :disabled="item.key === 7"
> >{{item.value}}</el-option>
{{ item.value }}
</el-option>
</el-select> </el-select>
- -
<el-select <el-select clearable v-model="cycle02">
v-model="cycle02"
clearable
>
<el-option <el-option
v-for="(item,index) of weekList" v-for="(item,index) of weekList"
:key="index" :key="index"
:label="item.value" :label="item.value"
:value="item.key" :value="item.key"
:disabled="item.key <= cycle01" :disabled="item.key <= cycle01"
> >{{item.value}}</el-option>
{{ item.value }}
</el-option>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="4">
v-model="radioValue"
:label="4"
>
<el-input-number <el-input-number v-model='average01' :min="1" :max="4" /> 周的
v-model="average01" <el-select clearable v-model="average02">
:min="1" <el-option v-for="item in weekList" :key="item.key" :label="item.value" :value="item.key" />
:max="4"
/> 周的
<el-select
v-model="average02"
clearable
>
<el-option
v-for="item in weekList"
:key="item.key"
:label="item.value"
:value="item.key"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="5">
v-model="radioValue"
:label="5"
>
本月最后一个 本月最后一个
<el-select <el-select clearable v-model="weekday">
v-model="weekday" <el-option v-for="item in weekList" :key="item.key" :label="item.value" :value="item.key" />
clearable
>
<el-option
v-for="item in weekList"
:key="item.key"
:label="item.value"
:value="item.key"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio v-model='radioValue' :label="6">
v-model="radioValue"
:label="6"
>
指定 指定
<el-select <el-select class="multiselect" clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="6">
v-model="checkboxList" <el-option v-for="item in weekList" :key="item.key" :label="item.value" :value="item.key" />
class="multiselect"
clearable
placeholder="可多选"
multiple
:multiple-limit="6"
>
<el-option
v-for="item in weekList"
:key="item.key"
:label="item.value"
:value="item.key"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>

View File

@@ -1,80 +1,39 @@
<template> <template>
<el-form> <el-form>
<el-form-item> <el-form-item>
<el-radio <el-radio :label="1" v-model='radioValue'>
v-model="radioValue"
:label="1"
>
不填允许的通配符[, - * /] 不填允许的通配符[, - * /]
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio :label="2" v-model='radioValue'>
v-model="radioValue"
:label="2"
>
每年 每年
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio :label="3" v-model='radioValue'>
v-model="radioValue"
:label="3"
>
周期从 周期从
<el-input-number <el-input-number v-model='cycle01' :min='fullYear' :max="2098"/> -
v-model="cycle01" <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : fullYear + 1" :max="2099"/>
:min="fullYear"
:max="2098"
/> -
<el-input-number
v-model="cycle02"
:min="cycle01 ? cycle01 + 1 : fullYear + 1"
:max="2099"
/>
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio :label="4" v-model='radioValue'>
v-model="radioValue"
:label="4"
>
<el-input-number <el-input-number v-model='average01' :min='fullYear' :max="2098"/> 年开始
v-model="average01" <el-input-number v-model='average02' :min="1" :max="2099 - average01 || fullYear"/> 年执行一次
:min="fullYear"
:max="2098"
/> 年开始
<el-input-number
v-model="average02"
:min="1"
:max="2099 - average01 || fullYear"
/> 年执行一次
</el-radio> </el-radio>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-radio <el-radio :label="5" v-model='radioValue'>
v-model="radioValue"
:label="5"
>
指定 指定
<el-select <el-select clearable v-model="checkboxList" placeholder="可多选" multiple :multiple-limit="8">
v-model="checkboxList" <el-option v-for="item in 9" :key="item" :value="item - 1 + fullYear" :label="item -1 + fullYear" />
clearable
placeholder="可多选"
multiple
:multiple-limit="8"
>
<el-option
v-for="item in 9"
:key="item"
:value="item - 1 + fullYear"
:label="item -1 + fullYear"
/>
</el-select> </el-select>
</el-radio> </el-radio>
</el-form-item> </el-form-item>

View File

@@ -10,14 +10,12 @@
>{{ item.label + " " }}</span> >{{ item.label + " " }}</span>
<el-tag <el-tag
v-else v-else
:key="item.value + ''"
:disable-transitions="true" :disable-transitions="true"
:key="item.value + ''"
:index="index" :index="index"
:type="getValidTagType(item.elTagType)" :type="getValidTagType(item.elTagType)"
:class="item.elTagClass" :class="item.elTagClass"
> >{{ item.label + " " }}</el-tag>
{{ item.label + " " }}
</el-tag>
</template> </template>
</template> </template>
<template v-if="unmatch && showValue"> <template v-if="unmatch && showValue">

View File

@@ -1,33 +1,15 @@
<template> <template>
<div class="editor-container"> <div class="editor-container">
<div> <div>
<el-upload <el-upload :action="uploadUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess"
v-if="type == 'url'" :on-error="handleUploadError" name="file" :show-file-list="false" :headers="headers" class="editor-img-uploader"
:action="uploadUrl" v-if="type == 'url'">
:before-upload="handleBeforeUpload" <i ref="uploadRef" class="editor-img-uploader"></i>
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
name="file"
:show-file-list="false"
:headers="headers"
class="editor-img-uploader"
>
<i
ref="uploadRef"
class="editor-img-uploader"
/>
</el-upload> </el-upload>
</div> </div>
<div class="editor"> <div class="editor">
<quill-editor <quill-editor ref="quillEditorRef" :content="content" @update:content="content = $event" contentType="html"
ref="quillEditorRef" @textChange="(e) => $emit('update:modelValue', content)" :options="options" :style="styles" />
:content="content"
content-type="html"
:options="options"
:style="styles"
@update:content="content = $event"
@text-change="(e) => $emit('update:modelValue', content)"
/>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -2,7 +2,6 @@
<div class="upload-file"> <div class="upload-file">
<el-upload <el-upload
multiple multiple
ref="fileUpload"
:action="uploadFileUrl" :action="uploadFileUrl"
:before-upload="handleBeforeUpload" :before-upload="handleBeforeUpload"
:file-list="fileList" :file-list="fileList"
@@ -13,52 +12,26 @@
:show-file-list="false" :show-file-list="false"
:headers="headers" :headers="headers"
class="upload-file-uploader" class="upload-file-uploader"
ref="fileUpload"
> >
<!-- 上传按钮 --> <!-- 上传按钮 -->
<el-button type="primary"> <el-button type="primary">选取文件</el-button>
选取文件
</el-button>
</el-upload> </el-upload>
<!-- 上传提示 --> <!-- 上传提示 -->
<div <div class="el-upload__tip" v-if="showTip">
v-if="showTip"
class="el-upload__tip"
>
请上传 请上传
<template v-if="fileSize"> <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
</template>
的文件 的文件
</div> </div>
<!-- 文件列表 --> <!-- 文件列表 -->
<transition-group <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
class="upload-file-list el-upload-list el-upload-list--text" <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
name="el-fade-in-linear" <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
tag="ul"
>
<li
v-for="(file, index) in fileList"
:key="file.uid"
class="el-upload-list__item ele-upload-list__item-content"
>
<el-link
:href="`${baseUrl}${file.url}`"
:underline="false"
target="_blank"
>
<span class="el-icon-document"> {{ getFileName(file.name) }} </span> <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link> </el-link>
<div class="ele-upload-list__item-content-action"> <div class="ele-upload-list__item-content-action">
<el-link <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
:underline="false"
type="danger"
@click="handleDelete(index)"
>
删除
</el-link>
</div> </div>
</li> </li>
</transition-group> </transition-group>

View File

@@ -1,8 +1,5 @@
<template> <template>
<div <div style="padding: 0 15px;" @click="toggleClick">
style="padding: 0 15px;"
@click="toggleClick"
>
<svg <svg
:class="{'is-active':isActive}" :class="{'is-active':isActive}"
class="hamburger" class="hamburger"

View File

@@ -1,14 +1,6 @@
<template> <template>
<div <div :class="{ show: show }" class="header-search">
:class="{ show: show }" <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" v-if="!show" />
class="header-search"
>
<svg-icon
v-if="!show"
class-name="search-icon"
icon-class="search"
@click.stop="click"
/>
<el-select <el-select
v-else v-else
ref="headerSearchSelectRef" ref="headerSearchSelectRef"

View File

@@ -8,24 +8,13 @@
@clear="filterIcons" @clear="filterIcons"
@input="filterIcons" @input="filterIcons"
> >
<template #suffix> <template #suffix><i class="el-icon-search el-input__icon" /></template>
<i class="el-icon-search el-input__icon" />
</template>
</el-input> </el-input>
<div class="icon-list"> <div class="icon-list">
<div class="list-container"> <div class="list-container">
<div <div v-for="(item, index) in iconList" class="icon-item-wrapper" :key="index" @click="selectedIcon(item)">
v-for="(item, index) in iconList"
:key="index"
class="icon-item-wrapper"
@click="selectedIcon(item)"
>
<div :class="['icon-item', { active: activeIcon === item }]"> <div :class="['icon-item', { active: activeIcon === item }]">
<svg-icon <svg-icon :icon-class="item" class-name="icon" style="height: 25px;width: 16px;"/>
:icon-class="item"
class-name="icon"
style="height: 25px;width: 16px;"
/>
<span>{{ item }}</span> <span>{{ item }}</span>
</div> </div>
</div> </div>

View File

@@ -1,7 +1,6 @@
<template> <template>
<div class="component-upload-image"> <div class="component-upload-image">
<el-upload <el-upload
ref="imageUpload"
multiple multiple
:action="uploadImgUrl" :action="uploadImgUrl"
list-type="picture-card" list-type="picture-card"
@@ -10,6 +9,7 @@
:limit="limit" :limit="limit"
:on-error="handleUploadError" :on-error="handleUploadError"
:on-exceed="handleExceed" :on-exceed="handleExceed"
ref="imageUpload"
:before-remove="handleDelete" :before-remove="handleDelete"
:show-file-list="true" :show-file-list="true"
:headers="headers" :headers="headers"
@@ -17,15 +17,10 @@
:on-preview="handlePictureCardPreview" :on-preview="handlePictureCardPreview"
:class="{ hide: fileList.length >= limit }" :class="{ hide: fileList.length >= limit }"
> >
<el-icon class="avatar-uploader-icon"> <el-icon class="avatar-uploader-icon"><plus /></el-icon>
<plus />
</el-icon>
</el-upload> </el-upload>
<!-- 上传提示 --> <!-- 上传提示 -->
<div <div class="el-upload__tip" v-if="showTip">
v-if="showTip"
class="el-upload__tip"
>
请上传 请上传
<template v-if="fileSize"> <template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
@@ -45,7 +40,7 @@
<img <img
:src="dialogImageUrl" :src="dialogImageUrl"
style="display: block; max-width: 100%; margin: 0 auto" style="display: block; max-width: 100%; margin: 0 auto"
> />
</el-dialog> </el-dialog>
</div> </div>
</template> </template>

View File

@@ -1,18 +1,12 @@
<template> <template>
<div class="page-container"> <div class="page-container">
<div <div v-if="$slots.header" class="page-header">
v-if="$slots.header"
class="page-header"
>
<slot name="header" /> <slot name="header" />
</div> </div>
<div class="page-content"> <div class="page-content">
<slot /> <slot />
</div> </div>
<div <div v-if="$slots.footer" class="page-footer">
v-if="$slots.footer"
class="page-footer"
>
<slot name="footer" /> <slot name="footer" />
</div> </div>
</div> </div>

View File

@@ -1,51 +1,20 @@
<template> <template>
<el-drawer <el-drawer v-model="noticeVisible" title="公告/通知" direction="rtl" size="400px" destroy-on-close>
v-model="noticeVisible" <el-empty v-if="noticeList.length === 0" description="暂无公告/通知" />
title="公告/通知" <div v-else class="notice-list">
direction="rtl" <div v-for="item in noticeList" :key="item.noticeId" class="notice-item" :class="{ 'is-read': isRead(item.noticeId), 'unread': !isRead(item.noticeId) }" @click="viewDetail(item)">
size="400px"
destroy-on-close
>
<el-empty
v-if="noticeList.length === 0"
description="暂无公告/通知"
/>
<div
v-else
class="notice-list"
>
<div
v-for="item in noticeList"
:key="item.noticeId"
class="notice-item"
:class="{ 'is-read': isRead(item.noticeId), 'unread': !isRead(item.noticeId) }"
@click="viewDetail(item)"
>
<div class="notice-title"> <div class="notice-title">
<span <span v-if="!isRead(item.noticeId)" class="unread-dot"></span>
v-if="!isRead(item.noticeId)"
class="unread-dot"
/>
{{ item.noticeTitle }} {{ item.noticeTitle }}
</div> </div>
<div class="notice-info"> <div class="notice-info">
<span class="notice-type"> <span class="notice-type">
<el-tag <el-tag :type="getNoticeTypeTagType(item.noticeType)" size="small">
:type="getNoticeTypeTagType(item.noticeType)"
size="small"
>
{{ getNoticeTypeText(item.noticeType) }} {{ getNoticeTypeText(item.noticeType) }}
</el-tag> </el-tag>
</span> </span>
<span <span class="notice-priority" v-if="item.priority">
v-if="item.priority" <el-tag :type="getPriorityTagType(item.priority)" size="small" effect="plain">
class="notice-priority"
>
<el-tag
:type="getPriorityTagType(item.priority)"
size="small"
effect="plain"
>
{{ getPriorityText(item.priority) }} {{ getPriorityText(item.priority) }}
</el-tag> </el-tag>
</span> </span>
@@ -55,41 +24,23 @@
</div> </div>
<!-- 公告/通知详情对话框 --> <!-- 公告/通知详情对话框 -->
<el-dialog <el-dialog v-model="detailVisible" :title="currentNotice.noticeTitle" width="800px" append-to-body>
v-model="detailVisible"
:title="currentNotice.noticeTitle"
width="800px"
append-to-body
>
<div class="notice-detail"> <div class="notice-detail">
<div class="detail-header"> <div class="detail-header">
<div class="detail-type"> <div class="detail-type">
<el-tag <el-tag :type="getNoticeTypeTagType(currentNotice.noticeType)" size="small">
:type="getNoticeTypeTagType(currentNotice.noticeType)"
size="small"
>
{{ getNoticeTypeText(currentNotice.noticeType) }} {{ getNoticeTypeText(currentNotice.noticeType) }}
</el-tag> </el-tag>
<el-tag <el-tag :type="getPriorityTagType(currentNotice.priority)" size="small" effect="plain" style="margin-left: 8px;">
:type="getPriorityTagType(currentNotice.priority)"
size="small"
effect="plain"
style="margin-left: 8px;"
>
{{ getPriorityText(currentNotice.priority) }} {{ getPriorityText(currentNotice.priority) }}
</el-tag> </el-tag>
</div> </div>
<span class="detail-time">{{ parseTime(currentNotice.createTime, '{y}-{m}-{d} {h}:{i}') }}</span> <span class="detail-time">{{ parseTime(currentNotice.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</div> </div>
<div <div class="detail-content" v-html="currentNotice.noticeContent"></div>
class="detail-content"
v-html="currentNotice.noticeContent"
/>
</div> </div>
<template #footer> <template #footer>
<el-button @click="detailVisible = false"> <el-button @click="detailVisible = false">关闭</el-button>
关闭
</el-button>
</template> </template>
</el-dialog> </el-dialog>
</el-drawer> </el-drawer>

View File

@@ -13,12 +13,7 @@
<div class="notice-list"> <div class="notice-list">
<div class="notice-list-header"> <div class="notice-list-header">
<span class="notice-list-title">公告列表</span> <span class="notice-list-title">公告列表</span>
<el-button <el-button text type="primary" @click="markAllAsRead" v-if="unreadCount > 0">
v-if="unreadCount > 0"
text
type="primary"
@click="markAllAsRead"
>
全部标记为已读 全部标记为已读
</el-button> </el-button>
</div> </div>
@@ -31,10 +26,7 @@
@click="handleSelectNotice(notice)" @click="handleSelectNotice(notice)"
> >
<div class="notice-item-left"> <div class="notice-item-left">
<el-icon <el-icon class="notice-type-icon" :class="getNoticeTypeClass(notice.noticeType)">
class="notice-type-icon"
:class="getNoticeTypeClass(notice.noticeType)"
>
<component :is="getNoticeTypeIcon(notice.noticeType)" /> <component :is="getNoticeTypeIcon(notice.noticeType)" />
</el-icon> </el-icon>
<div class="notice-item-content"> <div class="notice-item-content">
@@ -47,14 +39,7 @@
{{ getPriorityText(notice.priority) }} {{ getPriorityText(notice.priority) }}
</el-tag> </el-tag>
<span class="notice-title-text">{{ notice.noticeTitle }}</span> <span class="notice-title-text">{{ notice.noticeTitle }}</span>
<el-tag <el-tag v-if="!notice.isRead" type="danger" size="small" effect="dark">未读</el-tag>
v-if="!notice.isRead"
type="danger"
size="small"
effect="dark"
>
未读
</el-tag>
</div> </div>
<div class="notice-meta"> <div class="notice-meta">
<span class="notice-date">{{ formatDate(notice.createTime) }}</span> <span class="notice-date">{{ formatDate(notice.createTime) }}</span>
@@ -62,77 +47,45 @@
</div> </div>
</div> </div>
</div> </div>
<el-icon <el-icon class="arrow-icon" v-if="activeNoticeId === notice.noticeId">
v-if="activeNoticeId === notice.noticeId"
class="arrow-icon"
>
<ArrowRight /> <ArrowRight />
</el-icon> </el-icon>
</div> </div>
<!-- 空状态 --> <!-- 空状态 -->
<div <div v-if="noticeList.length === 0" class="empty-state">
v-if="noticeList.length === 0" <el-empty description="暂无公告" :image-size="100" />
class="empty-state"
>
<el-empty
description="暂无公告"
:image-size="100"
/>
</div> </div>
</el-scrollbar> </el-scrollbar>
</div> </div>
<!-- 公告详情 --> <!-- 公告详情 -->
<div <div class="notice-detail" v-if="activeNotice">
v-if="activeNotice"
class="notice-detail"
>
<div class="notice-detail-header"> <div class="notice-detail-header">
<h3 class="notice-detail-title"> <h3 class="notice-detail-title">{{ activeNotice.noticeTitle }}</h3>
{{ activeNotice.noticeTitle }}
</h3>
<div class="notice-detail-meta"> <div class="notice-detail-meta">
<el-tag <el-tag :type="getPriorityTagType(activeNotice.priority)" size="small" effect="dark">
:type="getPriorityTagType(activeNotice.priority)"
size="small"
effect="dark"
>
{{ getPriorityText(activeNotice.priority) }} {{ getPriorityText(activeNotice.priority) }}
</el-tag> </el-tag>
<el-tag <el-tag :type="getNoticeTypeTagType(activeNotice.noticeType)" size="small">
:type="getNoticeTypeTagType(activeNotice.noticeType)"
size="small"
>
{{ getNoticeTypeText(activeNotice.noticeType) }} {{ getNoticeTypeText(activeNotice.noticeType) }}
</el-tag> </el-tag>
<span class="notice-detail-date">{{ formatFullDate(activeNotice.createTime) }}</span> <span class="notice-detail-date">{{ formatFullDate(activeNotice.createTime) }}</span>
</div> </div>
</div> </div>
<el-divider /> <el-divider />
<div <div class="notice-detail-body" v-html="activeNotice.noticeContent"></div>
class="notice-detail-body"
v-html="activeNotice.noticeContent"
/>
</div> </div>
<!-- 未选择状态 --> <!-- 未选择状态 -->
<div <div v-else class="no-selection">
v-else <el-empty description="请选择公告查看详情" :image-size="120" />
class="no-selection"
>
<el-empty
description="请选择公告查看详情"
:image-size="120"
/>
</div> </div>
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button @click="handleClose"> <el-button @click="handleClose">关闭</el-button>
关闭
</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>

View File

@@ -21,10 +21,7 @@
@click="handleSelectNotice(notice)" @click="handleSelectNotice(notice)"
> >
<div class="notice-item-left"> <div class="notice-item-left">
<el-icon <el-icon class="notice-type-icon" :class="getNoticeTypeClass(notice.noticeType)">
class="notice-type-icon"
:class="getNoticeTypeClass(notice.noticeType)"
>
<component :is="getNoticeTypeIcon(notice.noticeType)" /> <component :is="getNoticeTypeIcon(notice.noticeType)" />
</el-icon> </el-icon>
<div class="notice-item-content"> <div class="notice-item-content">
@@ -37,14 +34,7 @@
{{ getPriorityText(notice.priority) }} {{ getPriorityText(notice.priority) }}
</el-tag> </el-tag>
<span class="notice-title-text">{{ notice.noticeTitle }}</span> <span class="notice-title-text">{{ notice.noticeTitle }}</span>
<el-tag <el-tag v-if="!notice.isRead" type="danger" size="small" effect="dark">未读</el-tag>
v-if="!notice.isRead"
type="danger"
size="small"
effect="dark"
>
未读
</el-tag>
</div> </div>
<div class="notice-meta"> <div class="notice-meta">
<span class="notice-date">{{ formatDate(notice.createTime) }}</span> <span class="notice-date">{{ formatDate(notice.createTime) }}</span>
@@ -52,10 +42,7 @@
</div> </div>
</div> </div>
</div> </div>
<el-icon <el-icon class="arrow-icon" v-if="activeNoticeId === notice.noticeId">
v-if="activeNoticeId === notice.noticeId"
class="arrow-icon"
>
<ArrowRight /> <ArrowRight />
</el-icon> </el-icon>
</div> </div>
@@ -63,63 +50,35 @@
</div> </div>
<!-- 公告详情 --> <!-- 公告详情 -->
<div <div class="notice-detail" v-if="activeNotice">
v-if="activeNotice"
class="notice-detail"
>
<div class="notice-detail-header"> <div class="notice-detail-header">
<h3 class="notice-detail-title"> <h3 class="notice-detail-title">{{ activeNotice.noticeTitle }}</h3>
{{ activeNotice.noticeTitle }}
</h3>
<div class="notice-detail-meta"> <div class="notice-detail-meta">
<el-tag <el-tag :type="getPriorityTagType(activeNotice.priority)" size="small" effect="dark">
:type="getPriorityTagType(activeNotice.priority)"
size="small"
effect="dark"
>
{{ getPriorityText(activeNotice.priority) }} {{ getPriorityText(activeNotice.priority) }}
</el-tag> </el-tag>
<el-tag <el-tag :type="getNoticeTypeTagType(activeNotice.noticeType)" size="small">
:type="getNoticeTypeTagType(activeNotice.noticeType)"
size="small"
>
{{ getNoticeTypeText(activeNotice.noticeType) }} {{ getNoticeTypeText(activeNotice.noticeType) }}
</el-tag> </el-tag>
<span class="notice-detail-date">{{ formatDate(activeNotice.createTime) }}</span> <span class="notice-detail-date">{{ formatDate(activeNotice.createTime) }}</span>
</div> </div>
</div> </div>
<el-divider /> <el-divider />
<div <div class="notice-detail-body" v-html="activeNotice.noticeContent"></div>
class="notice-detail-body"
v-html="activeNotice.noticeContent"
/>
</div> </div>
<!-- 空状态 --> <!-- 空状态 -->
<div <div v-else class="empty-state">
v-else <el-empty description="暂无公告" :image-size="120" />
class="empty-state"
>
<el-empty
description="暂无公告"
:image-size="120"
/>
</div> </div>
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button <el-button @click="markAllAsRead" v-if="unreadCount > 0" type="info">
v-if="unreadCount > 0"
type="info"
@click="markAllAsRead"
>
全部标记为已读 全部标记为已读
</el-button> </el-button>
<el-button <el-button type="primary" @click="handleClose">
type="primary"
@click="handleClose"
>
{{ hasUnread ? '稍后再看' : '知道了' }} {{ hasUnread ? '稍后再看' : '知道了' }}
</el-button> </el-button>
</div> </div>

View File

@@ -1,9 +1,6 @@
<template> <template>
<div> <div>
<svg-icon <svg-icon icon-class="question" @click="goto" />
icon-class="question"
@click="goto"
/>
</div> </div>
</template> </template>

View File

@@ -1,7 +1,7 @@
<template> <template>
<el-dialog <el-dialog
v-model="props.openDialog"
title="药品追溯码" title="药品追溯码"
v-model="props.openDialog"
width="842" width="842"
append-to-body append-to-body
destroy-on-close destroy-on-close
@@ -15,15 +15,13 @@
> >
<div> <div>
<div style="font-size: 16px"> <div style="font-size: 16px">
<div style="margin-bottom: 15px"> <div style="margin-bottom: 15px">药品名称 {{ props.ypName }}</div>
药品名称 {{ props.ypName }}
</div>
扫描追溯码 扫描追溯码
<el-input <el-input
ref="traceNoTempRef" ref="traceNoTempRef"
v-model="traceNoTemp"
type="textarea" type="textarea"
:rows="1" :rows="1"
v-model="traceNoTemp"
style="width: 180px; margin-right: 20px" style="width: 180px; margin-right: 20px"
@input="throttledGetList(traceNoTemp)" @input="throttledGetList(traceNoTemp)"
/> />
@@ -33,22 +31,8 @@
style="width: 180px; margin-right: 20px" style="width: 180px; margin-right: 20px"
@keyup.enter="handelTraceNo(traceNoInput)" @keyup.enter="handelTraceNo(traceNoInput)"
/> />
<el-button <el-button type="primary" plain icon="CircleClose" @click="handleReturn"> 撤回 </el-button>
type="primary" <el-button type="danger" plain icon="CircleClose" @click="handleClear"> 清除 </el-button>
plain
icon="CircleClose"
@click="handleReturn"
>
撤回
</el-button>
<el-button
type="danger"
plain
icon="CircleClose"
@click="handleClear"
>
清除
</el-button>
</div> </div>
<!-- <el-input <!-- <el-input
ref="inputRef" ref="inputRef"
@@ -85,10 +69,11 @@
<span style="margin-right: 6px"> <span style="margin-right: 6px">
[{{ index + 1 }}] [{{ index + 1 }}]
<template v-if="index < 9">&nbsp;</template> <template v-if="index < 9">&nbsp;</template>
<template v-else /> <template v-else></template>
{{ item }} {{ item }}
</span> </span>
<div <div
@click="removeTraceNo(index)"
style=" style="
display: flex; display: flex;
align-items: center; align-items: center;
@@ -99,12 +84,8 @@
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
" "
@click="removeTraceNo(index)"
>
<el-icon
size="10"
color="white"
> >
<el-icon size="10" color="white">
<Close /> <Close />
</el-icon> </el-icon>
</div> </div>
@@ -117,15 +98,8 @@
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button <el-button type="primary" @click="submit"> </el-button>
type="primary" <el-button @click="cancel"> </el-button>
@click="submit"
>
</el-button>
<el-button @click="cancel">
</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>

View File

@@ -6,11 +6,7 @@
trigger="manual" trigger="manual"
:width="width" :width="width"
> >
<slot <slot name="popover-content" :row="row" :index="index">
name="popover-content"
:row="row"
:index="index"
>
<div>列表内容</div> <div>列表内容</div>
</slot> </slot>
<template #reference> <template #reference>

View File

@@ -1,12 +1,9 @@
<template> <template>
<div <div :class="{ 'hidden': hidden }" class="pagination-container">
:class="{ 'hidden': hidden }"
class="pagination-container"
>
<el-pagination <el-pagination
:background="background"
v-model:current-page="currentPage" v-model:current-page="currentPage"
v-model:page-size="pageSize" v-model:page-size="pageSize"
:background="background"
:layout="layout" :layout="layout"
:page-sizes="pageSizes" :page-sizes="pageSizes"
:pager-count="pagerCount" :pager-count="pagerCount"

View File

@@ -1,3 +1,3 @@
<template> <template >
<router-view /> <router-view />
</template> </template>

View File

@@ -1,69 +1,21 @@
<template> <template>
<div <div class="top-right-btn" :style="style">
class="top-right-btn"
:style="style"
>
<el-row> <el-row>
<el-tooltip <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
v-if="search" <el-button circle icon="Search" @click="toggleSearch()" />
class="item"
effect="dark"
:content="showSearch ? '隐藏搜索' : '显示搜索'"
placement="top"
>
<el-button
circle
icon="Search"
@click="toggleSearch()"
/>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip class="item" effect="dark" content="刷新" placement="top">
class="item" <el-button circle icon="Refresh" @click="refresh()" />
effect="dark"
content="刷新"
placement="top"
>
<el-button
circle
icon="Refresh"
@click="refresh()"
/>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
v-if="columns" <el-button circle icon="Menu" @click="showColumn()" v-if="showColumnsType == 'transfer'"/>
class="item" <el-dropdown trigger="click" :hide-on-click="false" style="padding-left: 12px" v-if="showColumnsType == 'checkbox'">
effect="dark" <el-button circle icon="Menu" />
content="显隐列"
placement="top"
>
<el-button
v-if="showColumnsType == 'transfer'"
circle
icon="Menu"
@click="showColumn()"
/>
<el-dropdown
v-if="showColumnsType == 'checkbox'"
trigger="click"
:hide-on-click="false"
style="padding-left: 12px"
>
<el-button
circle
icon="Menu"
/>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<template <template v-for="item in columns" :key="item.key">
v-for="item in columns"
:key="item.key"
>
<el-dropdown-item> <el-dropdown-item>
<el-checkbox <el-checkbox :checked="item.visible" @change="checkboxChange($event, item.label)" :label="item.label" />
:checked="item.visible"
:label="item.label"
@change="checkboxChange($event, item.label)"
/>
</el-dropdown-item> </el-dropdown-item>
</template> </template>
</el-dropdown-menu> </el-dropdown-menu>
@@ -71,17 +23,13 @@
</el-dropdown> </el-dropdown>
</el-tooltip> </el-tooltip>
</el-row> </el-row>
<el-dialog <el-dialog :title="title" v-model="open" append-to-body>
v-model="open"
:title="title"
append-to-body
>
<el-transfer <el-transfer
v-model="value"
:titles="['显示', '隐藏']" :titles="['显示', '隐藏']"
v-model="value"
:data="columns" :data="columns"
@change="dataChange" @change="dataChange"
/> ></el-transfer>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>

View File

@@ -1,9 +1,6 @@
<template> <template>
<div> <div>
<svg-icon <svg-icon :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'" @click="toggle" />
:icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
@click="toggle"
/>
</div> </div>
</template> </template>

View File

@@ -1,23 +1,12 @@
<template> <template>
<div> <div>
<el-dropdown <el-dropdown trigger="click" @command="handleSetSize">
trigger="click"
@command="handleSetSize"
>
<div class="size-icon--style"> <div class="size-icon--style">
<svg-icon <svg-icon class-name="size-icon" icon-class="size" />
class-name="size-icon"
icon-class="size"
/>
</div> </div>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size === item.value" :command="item.value">
v-for="item of sizeOptions"
:key="item.value"
:disabled="size === item.value"
:command="item.value"
>
{{ item.label }} {{ item.label }}
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>

View File

@@ -1,12 +1,6 @@
<template> <template>
<svg <svg :class="svgClass" aria-hidden="true">
:class="svgClass" <use :xlink:href="iconName" :fill="color" />
aria-hidden="true"
>
<use
:xlink:href="iconName"
:fill="color"
/>
</svg> </svg>
</template> </template>

View File

@@ -1,22 +1,8 @@
<template> <template>
<div <div class="table-section" v-loading="loading">
v-loading="loading" <EditableTable ref="editableTableRef" v-bind="$attrs" class="editable-table">
class="table-section" <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
> <slot :name="slotName" v-bind="slotProps" />
<EditableTable
ref="editableTableRef"
v-bind="$attrs"
class="editable-table"
>
<template
v-for="(_, slotName) in $slots"
:key="slotName"
#[slotName]="slotProps"
>
<slot
:name="slotName"
v-bind="slotProps"
/>
</template> </template>
</EditableTable> </EditableTable>
</div> </div>

View File

@@ -1,18 +1,8 @@
<template> <template>
<div class="form-section"> <div class="form-section">
<FormLayout <FormLayout ref="formLayoutRef" v-bind="$attrs">
ref="formLayoutRef" <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
v-bind="$attrs" <slot :name="slotName" v-bind="slotProps" />
>
<template
v-for="(_, slotName) in $slots"
:key="slotName"
#[slotName]="slotProps"
>
<slot
:name="slotName"
v-bind="slotProps"
/>
</template> </template>
</FormLayout> </FormLayout>
</div> </div>

View File

@@ -8,12 +8,7 @@
@blur="handleBlur" @blur="handleBlur"
@change="handleChange" @change="handleChange"
> >
<template <template v-if="suffix" #suffix>{{ suffix }}</template>
v-if="suffix"
#suffix
>
{{ suffix }}
</template>
</el-input> </el-input>
</template> </template>

View File

@@ -5,10 +5,7 @@
<slot /> <slot />
</div> </div>
</template> </template>
<template <template v-if="$slots.footer" #footer>
v-if="$slots.footer"
#footer
>
<slot name="footer" /> <slot name="footer" />
</template> </template>
</Layout> </Layout>

View File

@@ -2,28 +2,20 @@
<el-menu <el-menu
:default-active="activeMenu" :default-active="activeMenu"
mode="horizontal" mode="horizontal"
:ellipsis="false"
@select="handleSelect" @select="handleSelect"
:ellipsis="false"
> >
<template v-for="(item, index) in topMenus"> <template v-for="(item, index) in topMenus">
<!-- 处理有子菜单的情况 --> <!-- 处理有子菜单的情况 -->
<template v-if="item.children && item.children.length > 0 && index < visibleNumber"> <template v-if="item.children && item.children.length > 0 && index < visibleNumber">
<el-sub-menu <el-sub-menu :style="{'--theme': theme}" :index="item.path" :key="index">
:key="index"
:style="{'--theme': theme}"
:index="item.path"
>
<template #title> <template #title>
<svg-icon <svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta.icon" :icon-class="item.meta.icon"/>
/>
{{ item.meta.title }} {{ item.meta.title }}
</template> </template>
<template <template v-for="(child, childIndex) in item.children" :key="childIndex">
v-for="(child, childIndex) in item.children"
:key="childIndex"
>
<el-menu-item :index="item.path + '/' + (child.path || '')"> <el-menu-item :index="item.path + '/' + (child.path || '')">
{{ child.meta.title }} {{ child.meta.title }}
</el-menu-item> </el-menu-item>
@@ -32,47 +24,29 @@
</template> </template>
<!-- 处理无子菜单的情况 --> <!-- 处理无子菜单的情况 -->
<template v-else-if="index < visibleNumber"> <template v-else-if="index < visibleNumber">
<el-menu-item <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index">
:key="index"
:style="{'--theme': theme}"
:index="item.path"
>
<svg-icon <svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta.icon" :icon-class="item.meta.icon"/>
/>
{{ item.meta.title }} {{ item.meta.title }}
</el-menu-item> </el-menu-item>
</template> </template>
</template> </template>
<!-- 顶部菜单超出数量折叠 --> <!-- 顶部菜单超出数量折叠 -->
<el-sub-menu <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
v-if="topMenus.length > visibleNumber" <template #title>更多菜单</template>
:style="{'--theme': theme}" <template v-for="(item, index) in topMenus" :key="index">
index="more"
>
<template #title>
更多菜单
</template>
<template
v-for="(item, index) in topMenus"
:key="index"
>
<!-- 处理有子菜单的情况 --> <!-- 处理有子菜单的情况 -->
<template v-if="item.children && item.children.length > 0 && index >= visibleNumber"> <template v-if="item.children && item.children.length > 0 && index >= visibleNumber">
<el-sub-menu :index="item.path"> <el-sub-menu :index="item.path">
<template #title> <template #title>
<svg-icon <svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta.icon" :icon-class="item.meta.icon"/>
/>
{{ item.meta.title }} {{ item.meta.title }}
</template> </template>
<template <template v-for="(child, childIndex) in item.children" :key="childIndex">
v-for="(child, childIndex) in item.children"
:key="childIndex"
>
<el-menu-item :index="item.path + '/' + (child.path || '')"> <el-menu-item :index="item.path + '/' + (child.path || '')">
{{ child.meta.title }} {{ child.meta.title }}
</el-menu-item> </el-menu-item>
@@ -84,8 +58,7 @@
<el-menu-item :index="item.path"> <el-menu-item :index="item.path">
<svg-icon <svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta.icon" :icon-class="item.meta.icon"/>
/>
{{ item.meta.title }} {{ item.meta.title }}
</el-menu-item> </el-menu-item>
</template> </template>

View File

@@ -1,19 +1,16 @@
<template> <template>
<div class="el-tree-select"> <div class="el-tree-select">
<el-select <el-select
ref="treeSelect"
v-model="valueId"
style="width: 100%" style="width: 100%"
v-model="valueId"
ref="treeSelect"
:filterable="true" :filterable="true"
:clearable="true" :clearable="true"
@clear="clearHandle"
:filter-method="selectFilterData" :filter-method="selectFilterData"
:placeholder="placeholder" :placeholder="placeholder"
@clear="clearHandle"
>
<el-option
:value="valueId"
:label="valueTitle"
> >
<el-option :value="valueId" :label="valueTitle">
<el-tree <el-tree
id="tree-option" id="tree-option"
ref="selectTree" ref="selectTree"
@@ -25,7 +22,7 @@
:default-expanded-keys="defaultExpandedKey" :default-expanded-keys="defaultExpandedKey"
:filter-node-method="filterNode" :filter-node-method="filterNode"
@node-click="handleNodeClick" @node-click="handleNodeClick"
/> ></el-tree>
</el-option> </el-option>
</el-select> </el-select>
</div> </div>

View File

@@ -1,14 +1,10 @@
<template> <template>
<div <div v-loading="loading" :style="'height:' + height">
v-loading="loading"
:style="'height:' + height"
>
<iframe <iframe
:src="url" :src="url"
frameborder="no" frameborder="no"
style="width: 100%; height: 100%" style="width: 100%; height: 100%"
scrolling="auto" scrolling="auto" />
/>
</div> </div>
</template> </template>

Some files were not shown because too many files have changed in this diff Show More