From 2a0303d0e67476ef52a7877d3513d0671a717304 Mon Sep 17 00:00:00 2001 From: chenqi Date: Wed, 17 Jun 2026 09:32:19 +0800 Subject: [PATCH 01/14] =?UTF-8?q?fix(regdoctorstation):=20RegPrescriptionU?= =?UTF-8?q?tils=20groupingBy=20null=20key=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug #674: 住院签发长期医嘱时 conditionDefinitionId/pharmacologyCategoryCode/therapyEnum 为 null 导致 Collectors.groupingBy 抛出 NPE 'element cannot be mapped to a null key' 修复:对齐门诊版 PrescriptionUtils 的 null 处理逻辑 - getConditionDefinitionId null -> 默认 0L - getPharmacologyCategoryCode null -> 默认 '0' - getTherapyEnum null -> 默认 0 - generatePrescriptionNo null/空 -> 走普通处方号 --- .../utils/RegPrescriptionUtils.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/regdoctorstation/utils/RegPrescriptionUtils.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/regdoctorstation/utils/RegPrescriptionUtils.java index 1a5dcae06..83a499a85 100755 --- a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/regdoctorstation/utils/RegPrescriptionUtils.java +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/regdoctorstation/utils/RegPrescriptionUtils.java @@ -26,9 +26,11 @@ public class RegPrescriptionUtils { if (medicineList == null || medicineList.isEmpty()) { return; } - // 1. 按诊断ID分组(不同诊断必须分开) + // 1. 按诊断ID分组(不同诊断必须分开,null值归为一组) Map> diagnosisGroups = - medicineList.stream().collect(Collectors.groupingBy(RegAdviceSaveDto::getConditionDefinitionId)); + medicineList.stream().collect(Collectors.groupingBy(dto -> + dto.getConditionDefinitionId() != null ? dto.getConditionDefinitionId() : 0L + )); // 2. 处理每个诊断组 diagnosisGroups.values().forEach(this::processDiagnosisGroup); } @@ -40,14 +42,18 @@ public class RegPrescriptionUtils { if (diagnosisGroup.isEmpty()) { return; } - // 1. 按药品性质分组 + // 1. 按药品性质分组(null值归为普通药品) Map> pharmacologyGroups = - diagnosisGroup.stream().collect(Collectors.groupingBy(RegAdviceSaveDto::getPharmacologyCategoryCode)); + diagnosisGroup.stream().collect(Collectors.groupingBy(dto -> + dto.getPharmacologyCategoryCode() != null ? dto.getPharmacologyCategoryCode() : "0" + )); // 2. 处理每个药品性质组 pharmacologyGroups.values().forEach(pharmaGroup -> { // 2.1 按治疗类型分组 Map> therapyGroups = - pharmaGroup.stream().collect(Collectors.groupingBy(RegAdviceSaveDto::getTherapyEnum)); + pharmaGroup.stream().collect(Collectors.groupingBy(dto -> + dto.getTherapyEnum() != null ? dto.getTherapyEnum() : 0 + )); // 2.2 为每组治疗类型生成唯一处方号 therapyGroups.forEach((therapyEnum, group) -> { String prescriptionNo = generatePrescriptionNo(pharmaGroup.get(0).getPharmacologyCategoryCode()); @@ -60,6 +66,9 @@ public class RegPrescriptionUtils { * 根据药品性质生成处方号(前缀规则与原工具类一致) */ private String generatePrescriptionNo(String pharmacologyCategoryCode) { + if (pharmacologyCategoryCode == null || pharmacologyCategoryCode.isEmpty()) { + return assignSeqUtil.getSeq(AssignSeqEnum.PRESCRIPTION_COMMON_NO.getPrefix(), 8); + } switch (pharmacologyCategoryCode) { case "2": // 麻醉药品 return assignSeqUtil.getSeq(AssignSeqEnum.PRESCRIPTION_NARCOTIC_NO.getPrefix(), 8); @@ -74,4 +83,4 @@ public class RegPrescriptionUtils { } } -} +} \ No newline at end of file From 1c68860541ebfceed97095ba946482b173e1e9be Mon Sep 17 00:00:00 2001 From: chenqi Date: Wed, 17 Jun 2026 10:40:34 +0800 Subject: [PATCH 02/14] =?UTF-8?q?```=20feat(patient):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E9=97=A8=E8=AF=8A=E8=AE=B0=E5=BD=95=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除了 OutpatientRecord.vue 组件文件 - 移除了门诊记录表格显示功能 - 清理了相关的数据获取和状态管理逻辑 - 移除了查看门诊详情的路由跳转功能 ``` --- scripts/repair_bug_318.py | 351 ------------------ .../PatientManagement/OutpatientRecord.vue | 69 ---- 2 files changed, 420 deletions(-) delete mode 100755 scripts/repair_bug_318.py delete mode 100644 src/components/PatientManagement/OutpatientRecord.vue diff --git a/scripts/repair_bug_318.py b/scripts/repair_bug_318.py deleted file mode 100755 index f97afed14..000000000 --- a/scripts/repair_bug_318.py +++ /dev/null @@ -1,351 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Bug #318 历史数据修复脚本 -为已存在但未生成手术医嘱的手术申请单补齐数据 -""" - -import psycopg2 -import json -import random -import string -from datetime import datetime - -# 数据库连接配置 -DB_CONFIG = { - "host": "47.116.196.11", - "port": 15432, - "database": "postgresql", - "user": "postgresql", - "password": "postgresql", # 请根据实际情况修改 -} - - -def generate_bus_no(): - """生成4位随机bus_no""" - return "".join(random.choices(string.digits, k=4)) - - -def check_repair_needed(conn): - """检查需要修复的记录数""" - cursor = conn.cursor() - sql = """ - SELECT COUNT(*) - FROM doc_request_form rf - LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no - AND sr.delete_flag = '0' - WHERE rf.type_code = 'PROCEDURE' - AND rf.delete_flag = '0' - AND sr.id IS NULL - """ - cursor.execute(sql) - count = cursor.fetchone()[0] - cursor.close() - return count - - -def get_repair_list(conn): - """获取需要修复的手术申请单列表""" - cursor = conn.cursor() - sql = """ - SELECT - rf.id, - rf.prescription_no, - rf.encounter_id, - rf.patient_id, - rf.requester_id, - rf.create_time, - rf.org_id, - rf.desc_json - FROM doc_request_form rf - LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no - AND sr.delete_flag = '0' - WHERE rf.type_code = 'PROCEDURE' - AND rf.delete_flag = '0' - AND sr.id IS NULL - ORDER BY rf.create_time DESC - """ - cursor.execute(sql) - results = cursor.fetchall() - cursor.close() - return results - - -def parse_surgery_info(desc_json): - """解析手术信息""" - if not desc_json: - return {} - try: - if isinstance(desc_json, str): - return json.loads(desc_json) - return desc_json - except: - return {} - - -def repair_service_request(conn, repair_list): - """修复手术医嘱(ServiceRequest)""" - cursor = conn.cursor() - - insert_sql = """ - INSERT INTO wor_service_request ( - bus_no, prescription_no, status_enum, generate_source_enum, - therapy_enum, quantity, unit_code, category_enum, - patient_id, requester_id, encounter_id, authored_time, - org_id, content_json, delete_flag, create_time, create_by, tenant_id - ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) - RETURNING id - """ - - new_requests = [] - for record in repair_list: - ( - rf_id, - prescription_no, - encounter_id, - patient_id, - requester_id, - create_time, - org_id, - desc_json, - ) = record - - # 解析手术信息 - surgery_info = parse_surgery_info(desc_json) - content_json = ( - json.dumps(surgery_info, ensure_ascii=False) if surgery_info else None - ) - - # 生成bus_no - bus_no = generate_bus_no() - - # 插入ServiceRequest - cursor.execute( - insert_sql, - ( - bus_no, # bus_no - prescription_no, # prescription_no - 1, # status_enum: 1-待签发 - 1, # generate_source_enum: 1-医生处方 - 2, # therapy_enum: 2-临时医嘱 - 1, # quantity - "次", # unit_code - 4, # category_enum: 4-手术 - patient_id, # patient_id - requester_id, # requester_id - encounter_id, # encounter_id - create_time, # authored_time - org_id, # org_id - content_json, # content_json - "0", # delete_flag - create_time, # create_time - requester_id, # create_by - 1, # tenant_id - ), - ) - - service_request_id = cursor.fetchone()[0] - new_requests.append( - { - "service_request_id": service_request_id, - "bus_no": bus_no, - "prescription_no": prescription_no, - "patient_id": patient_id, - "encounter_id": encounter_id, - "requester_id": requester_id, - "create_time": create_time, - "org_id": org_id, - "surgery_info": surgery_info, - } - ) - - conn.commit() - cursor.close() - return new_requests - - -def repair_charge_items(conn, new_requests): - """修复收费项目(ChargeItem)""" - cursor = conn.cursor() - - insert_sql = """ - INSERT INTO adm_charge_item ( - bus_no, status_enum, generate_source_enum, patient_id, - context_enum, encounter_id, enterer_id, entered_date, - service_table, service_id, product_table, requesting_org_id, - quantity_value, quantity_unit, unit_price, total_price, - delete_flag, create_time, create_by, tenant_id - ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) - """ - - for req in new_requests: - surgery_info = req["surgery_info"] - - # 手术费用 - surgery_fee = 0 - if surgery_info and "surgeryFee" in surgery_info: - try: - surgery_fee = float(surgery_info["surgeryFee"]) - except: - surgery_fee = 0 - - # 插入手术费用收费项目 - cursor.execute( - insert_sql, - ( - "CI" + req["bus_no"], # bus_no - 1, # status_enum: 1-草稿 - 1, # generate_source_enum: 1-医生处方 - req["patient_id"], # patient_id - 3, # context_enum: 3-诊疗 - req["encounter_id"], # encounter_id - req["requester_id"], # enterer_id - req["create_time"], # entered_date - "wor_service_request", # service_table - req["service_request_id"], # service_id - "wor_activity_definition", # product_table - req["org_id"], # requesting_org_id - 1, # quantity_value - "次", # quantity_unit - surgery_fee, # unit_price - surgery_fee, # total_price - "0", # delete_flag - req["create_time"], # create_time - req["requester_id"], # create_by - 1, # tenant_id - ), - ) - - # 麻醉费用(如果存在且大于0) - anesthesia_fee = 0 - if surgery_info and "anesthesiaFee" in surgery_info: - try: - anesthesia_fee = float(surgery_info["anesthesiaFee"]) - except: - anesthesia_fee = 0 - - if anesthesia_fee > 0: - cursor.execute( - insert_sql, - ( - "CI" + req["bus_no"] + "_A", # bus_no - 1, # status_enum - 1, # generate_source_enum - req["patient_id"], # patient_id - 3, # context_enum - req["encounter_id"], # encounter_id - req["requester_id"], # enterer_id - req["create_time"], # entered_date - "wor_service_request", # service_table - req["service_request_id"], # service_id - "wor_activity_definition", # product_table - req["org_id"], # requesting_org_id - 1, # quantity_value - "次", # quantity_unit - anesthesia_fee, # unit_price - anesthesia_fee, # total_price - "0", # delete_flag - req["create_time"], # create_time - req["requester_id"], # create_by - 1, # tenant_id - ), - ) - - conn.commit() - cursor.close() - - -def verify_repair(conn): - """验证修复结果""" - cursor = conn.cursor() - - # 统计手术医嘱数量 - cursor.execute(""" - SELECT COUNT(*) - FROM wor_service_request - WHERE category_enum = 4 AND delete_flag = '0' - """) - service_request_count = cursor.fetchone()[0] - - # 统计收费项目数量 - cursor.execute(""" - SELECT COUNT(*) - FROM adm_charge_item ci - WHERE ci.service_table = 'wor_service_request' - AND EXISTS ( - SELECT 1 FROM wor_service_request sr - WHERE sr.id = ci.service_id AND sr.category_enum = 4 - ) - """) - charge_item_count = cursor.fetchone()[0] - - cursor.close() - return service_request_count, charge_item_count - - -def main(): - """主函数""" - print("=" * 60) - print("Bug #318 历史数据修复脚本") - print("=" * 60) - print() - - try: - # 连接数据库 - print("正在连接数据库...") - conn = psycopg2.connect(**DB_CONFIG) - print("✓ 数据库连接成功") - print() - - # 步骤1:检查需要修复的记录数 - print("步骤1: 检查需要修复的记录...") - need_repair_count = check_repair_needed(conn) - print(f"✓ 发现 {need_repair_count} 条需要修复的手术申请单") - print() - - if need_repair_count == 0: - print("没有需要修复的数据,退出") - return - - # 步骤2:获取修复列表 - print("步骤2: 获取修复列表...") - repair_list = get_repair_list(conn) - print(f"✓ 获取到 {len(repair_list)} 条记录") - print() - - # 步骤3:修复ServiceRequest - print("步骤3: 生成手术医嘱(ServiceRequest)...") - new_requests = repair_service_request(conn, repair_list) - print(f"✓ 成功生成 {len(new_requests)} 条手术医嘱") - print() - - # 步骤4:修复ChargeItem - print("步骤4: 生成收费项目(ChargeItem)...") - repair_charge_items(conn, new_requests) - print(f"✓ 成功生成收费项目") - print() - - # 步骤5:验证修复结果 - print("步骤5: 验证修复结果...") - service_count, charge_count = verify_repair(conn) - print(f"✓ 当前手术医嘱总数: {service_count}") - print(f"✓ 当前手术收费项目总数: {charge_count}") - print() - - print("=" * 60) - print("✓ 修复完成!") - print("=" * 60) - - except Exception as e: - print(f"✗ 错误: {e}") - import traceback - - traceback.print_exc() - finally: - if "conn" in locals(): - conn.close() - print("\n数据库连接已关闭") - - -if __name__ == "__main__": - main() diff --git a/src/components/PatientManagement/OutpatientRecord.vue b/src/components/PatientManagement/OutpatientRecord.vue deleted file mode 100644 index 30f2c0535..000000000 --- a/src/components/PatientManagement/OutpatientRecord.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - - - From 5a227014fea0415d0771b68cb41340ae67762926 Mon Sep 17 00:00:00 2001 From: chenqi Date: Wed, 17 Jun 2026 11:02:18 +0800 Subject: [PATCH 03/14] =?UTF-8?q?fix(surgery):=20#684=20=E6=89=8B=E6=9C=AF?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E4=B8=8B=E6=8B=89=E6=A1=86=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=20-=20=E6=B8=85=E7=90=86=E5=AD=97=E5=85=B8=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ..._bug684_fix_surgery_status_dict_duplicates.sql | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V2026_0617__bug684_fix_surgery_status_dict_duplicates.sql diff --git a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V2026_0617__bug684_fix_surgery_status_dict_duplicates.sql b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V2026_0617__bug684_fix_surgery_status_dict_duplicates.sql new file mode 100644 index 000000000..b8c0cff64 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V2026_0617__bug684_fix_surgery_status_dict_duplicates.sql @@ -0,0 +1,15 @@ +-- Bug #684: 手术状态下拉框有重复 +-- 原因:sys_dict_data 中 surgery_status 类型存在重复记录(每个 dict_value 有3条) +-- 修复:删除重复记录,每个 dict_value 只保留 dict_code 最小的一条 + +DELETE FROM sys_dict_data +WHERE dict_code IN ( + SELECT dict_code + FROM ( + SELECT dict_code, + ROW_NUMBER() OVER (PARTITION BY dict_type, dict_value ORDER BY dict_code ASC) as rn + FROM sys_dict_data + WHERE dict_type = 'surgery_status' + ) t + WHERE rn > 1 +); From bdb7d978fb5b6dae2e9694cc2a9aa1a92296bc4c Mon Sep 17 00:00:00 2001 From: wangjian963 <15215920+aprilry@user.noreply.gitee.com> Date: Wed, 17 Jun 2026 11:06:45 +0800 Subject: [PATCH 04/14] =?UTF-8?q?fix(ui):=20=E4=BF=AE=E5=A4=8D=E4=BD=8F?= =?UTF-8?q?=E9=99=A2=E5=8C=BB=E7=94=9F=E7=AB=99=E4=B8=8E=E6=8A=A4=E5=A3=AB?= =?UTF-8?q?=E7=AB=99=E4=B8=B4=E5=BA=8A=E5=8C=BB=E5=98=B1=E8=8B=A5=E5=B9=B2?= =?UTF-8?q?=E7=A8=B3=E5=AE=9A=E6=80=A7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 医生站: - 修复类型切换后编辑表单残留、blur/click竞态致选中无效、批量保存缺patientId - 修复filterPrescriptionList.find过滤下展开失败、popover溢出、表格塌陷 - 提取resolveCategoryCode/getAdviceTableRef消除重复, 优化adviceTableRef类型 - 修复adviceBaseList keyField、选中残留、TS类型声明 护士站: - 校对: 新增已执行状态判定+退回拦截, 修复状态标签颜色不一致 - 执行: 修复长期医嘱dayTimes为空被静默丢弃 - 双模块: 新增keep-alive重激活刷新+患者列表自动加载 配置: - eslint.config.js 新增 @typescript-eslint/parser 支持Vue TS解析 --- healthlink-his-ui/eslint.config.js | 6 +- healthlink-his-ui/package.json | 1 + .../home/components/adviceBaseList.vue | 28 ++- .../home/components/order/index.vue | 169 +++++++++++------- .../components/prescriptionList.vue | 11 ++ .../medicalOrderExecution/index.vue | 28 ++- .../components/prescriptionList.vue | 24 ++- .../medicalOrderProofread/index.vue | 25 +++ 8 files changed, 211 insertions(+), 81 deletions(-) diff --git a/healthlink-his-ui/eslint.config.js b/healthlink-his-ui/eslint.config.js index 1361781dd..760c086f4 100755 --- a/healthlink-his-ui/eslint.config.js +++ b/healthlink-his-ui/eslint.config.js @@ -4,6 +4,7 @@ import { fileURLToPath } from "node:url"; import globals from "globals"; import pluginVue from "eslint-plugin-vue"; import parserVue from "vue-eslint-parser"; +import parserTs from "@typescript-eslint/parser"; import importPlugin, { createNodeResolver } from "eslint-plugin-import-x"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -20,7 +21,7 @@ export default [ }, ...pluginVue.configs["flat/recommended"], - + { languageOptions: { globals: { @@ -30,6 +31,9 @@ export default [ parser: parserVue, ecmaVersion: "latest", sourceType: "module", + parserOptions: { + parser: parserTs, + }, }, plugins: { diff --git a/healthlink-his-ui/package.json b/healthlink-his-ui/package.json index 555adb5a4..9917217c1 100755 --- a/healthlink-his-ui/package.json +++ b/healthlink-his-ui/package.json @@ -72,6 +72,7 @@ "devDependencies": { "@playwright/test": "^1.60.0", "@types/node": "^25.0.1", + "@typescript-eslint/parser": "^8.61.1", "@vitejs/plugin-vue": "^5.2.4", "@vue/test-utils": "^2.4.6", "eslint": "^10.4.1", diff --git a/healthlink-his-ui/src/views/inpatientDoctor/home/components/adviceBaseList.vue b/healthlink-his-ui/src/views/inpatientDoctor/home/components/adviceBaseList.vue index f9a84666f..700cdd2ca 100755 --- a/healthlink-his-ui/src/views/inpatientDoctor/home/components/adviceBaseList.vue +++ b/healthlink-his-ui/src/views/inpatientDoctor/home/components/adviceBaseList.vue @@ -8,7 +8,7 @@ :table-height="400" :max-height="400" :loading="loading" - :row-config="{ keyField: 'patientId' }" + :row-config="{ keyField: 'adviceDefinitionId' }" @cell-click="handleRowClick" > From d792f03bbd262f1bb05ded2d7271ca202f3339c1 Mon Sep 17 00:00:00 2001 From: wangjian963 <15215920+aprilry@user.noreply.gitee.com> Date: Wed, 17 Jun 2026 11:37:14 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=20=20fix(ui):=20=E5=B7=B2=E7=99=BB?= =?UTF-8?q?=E8=AE=B0=E5=85=A5=E9=99=A2=E8=A1=A8=E6=A0=BC=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8E=E5=B8=83=E5=B1=80=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - handleRadioChange({newValue}→{row}): 修复 vxe-table radio-change 事件参数错误,selectedRow 始终为 undefined,打印住院证功能失效 - queryParams 初始定义与 resetQuery 对齐,补全缺失字段 - 表格布局重构: · 移除 height="100%"(解除横向滚动条位置漂移) · table min-width="1600px" + 容器 overflow-x:auto · 固定列 width / 信息列 min-width 差异化约束 --- .../register/components/accomplishList.vue | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/healthlink-his-ui/src/views/inHospitalManagement/charge/register/components/accomplishList.vue b/healthlink-his-ui/src/views/inHospitalManagement/charge/register/components/accomplishList.vue index 47c04fab7..11f05a823 100755 --- a/healthlink-his-ui/src/views/inHospitalManagement/charge/register/components/accomplishList.vue +++ b/healthlink-his-ui/src/views/inHospitalManagement/charge/register/components/accomplishList.vue @@ -54,8 +54,7 @@ @@ -68,6 +67,7 @@ /> @@ -85,6 +85,7 @@ /> @@ -94,6 +95,7 @@ @@ -105,7 +107,7 @@ field="idCard" align="center" title="身份证号码" - width="180" + width="200" >