From e31337b58a22bc6bc5e04fa7d929a0e555ea783e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=8E=E4=BD=97?= Date: Sun, 7 Jun 2026 21:54:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(test):=20=E4=B8=9A=E5=8A=A1=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E7=BA=A7=E6=B5=8B=E8=AF=95=E8=84=9A=E6=9C=AC+?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 04_test_business_logic.py: 业务逻辑测试v1(111用例) - 04_test_business_logic_v2.py: 修正API路径后v2(107用例,通过率31.8%) - 测试报告: 揭示大量API路径不匹配和参数问题 - 测试数据: SQL脚本覆盖31个业务模块 - 测试流程: 30个业务流程图+API映射 测试发现的问题: 1. 多个Controller缺少/page端点 2. 部分接口需要必填参数(patientId, startTime等) 3. 部分接口响应格式非标准(rows嵌套为dict) 4. DB列名不匹配(create_by不存在等) --- MD/test/01_test_data.sql | 476 ++++++++ MD/test/04_test_business_logic.py | 1020 +++++++++++++++++ MD/test/04_test_business_logic_v2.py | 631 ++++++++++ MD/test/HEALTHLINK_HIS_TEST_PLAN.md | 485 ++++++++ MD/test/reports/biz_test_20260607_215348.md | 128 +++ .../business_logic_report_20260607_215100.md | 148 +++ MD/test/test_api.sh | 162 +++ 7 files changed, 3050 insertions(+) create mode 100644 MD/test/01_test_data.sql create mode 100755 MD/test/04_test_business_logic.py create mode 100755 MD/test/04_test_business_logic_v2.py create mode 100644 MD/test/HEALTHLINK_HIS_TEST_PLAN.md create mode 100644 MD/test/reports/biz_test_20260607_215348.md create mode 100644 MD/test/reports/business_logic_report_20260607_215100.md create mode 100755 MD/test/test_api.sh diff --git a/MD/test/01_test_data.sql b/MD/test/01_test_data.sql new file mode 100644 index 000000000..58f1ac1a6 --- /dev/null +++ b/MD/test/01_test_data.sql @@ -0,0 +1,476 @@ +-- ============================================================ +-- HealthLink-HIS 三甲医院全流程测试数据 +-- 版本: v2.0 (JDK 25 + Spring Boot 4.0.6 + Vue 3) +-- 日期: 2026-06-07 +-- 说明: 覆盖门诊/住院/药房/检验/影像/手术/麻醉/护理/院感/质控/中医/会诊全流程 +-- 注意: 仅插入测试数据,不删除现有数据 +-- ============================================================ + +SET search_path TO healthlink_his; + +-- ============================ +-- 一、基础数据(科室/人员/组织) +-- ============================ + +-- 1.1 测试科室(使用现有科室,补充缺失科室) +INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader, phone, email, status, del_flag, create_by, create_time) +VALUES + (1001, 0, '0', '门诊内科', 10, '张主任', '13800000001', 'mnk@hospital.com', '0', '0', 'admin', NOW()), + (1002, 0, '0', '门诊外科', 11, '李主任', '13800000002', 'mwk@hospital.com', '0', '0', 'admin', NOW()), + (1003, 0, '0', '儿科门诊', 12, '王主任', '13800000003', 'ek@hospital.com', '0', '0', 'admin', NOW()), + (1004, 0, '0', '妇产科', 13, '赵主任', '13800000004', 'fck@hospital.com', '0', '0', 'admin', NOW()), + (1005, 0, '0', 'ICU', 14, '刘主任', '13800000005', 'icu@hospital.com', '0', '0', 'admin', NOW()), + (1006, 0, '0', '急诊科', 15, '陈主任', '13800000006', 'jzk@hospital.com', '0', '0', 'admin', NOW()), + (1007, 0, '0', '手术室', 16, '孙主任', '13800000007', 'ss@hospital.com', '0', '0', 'admin', NOW()), + (1008, 0, '0', '药房', 17, '周主任', '13800000008', 'yf@hospital.com', '0', '0', 'admin', NOW()), + (1009, 0, '0', '检验科', 18, '吴主任', '13800000009', 'jyk@hospital.com', '0', '0', 'admin', NOW()), + (1010, 0, '0', '影像科', 19, '郑主任', '13800000010', 'yxk@hospital.com', '0', '0', 'admin', NOW()), + (1011, 0, '0', '门诊部', 20, '黄院长', '13800000011', 'mzb@hospital.com', '0', '0', 'admin', NOW()), + (1012, 0, '0', '住院部', 21, '杨院长', '13800000012', 'zyb@hospital.com', '0', '0', 'admin', NOW()) +ON CONFLICT (dept_id) DO NOTHING; + +-- 1.2 测试医生 +INSERT INTO sys_user (user_id, user_name, nick_name, dept_id, email, phonenumber, sex, status, del_flag, create_by, create_time) +VALUES + (2001, 'doctor_zhang', '张三医生', 1001, 'zhangsan@hospital.com', '13900000001', '1', '0', '0', 'admin', NOW()), + (2002, 'doctor_li', '李四医生', 1002, 'lisi@hospital.com', '13900000002', '1', '0', '0', 'admin', NOW()), + (2003, 'doctor_wang', '王五医生', 1003, 'wangwu@hospital.com', '13900000003', '1', '0', '0', 'admin', NOW()), + (2004, 'doctor_zhao', '赵六医生', 1004, 'zhaoliu@hospital.com', '13900000004', '1', '0', '0', 'admin', NOW()), + (2005, 'doctor_liu', '刘七医生', 1005, 'liuqi@hospital.com', '13900000005', '1', '0', '0', 'admin', NOW()), + (2006, 'doctor_chen', '陈八医生', 1006, 'chenba@hospital.com', '13900000006', '1', '0', '0', 'admin', NOW()), + (2007, 'doctor_sun', '孙九医生', 1007, 'sunjiu@hospital.com', '13900000007', '1', '0', '0', 'admin', NOW()), + (2008, 'doctor_zhou', '周十医生', 1008, 'zhoushi@hospital.com', '13900000008', '1', '0', '0', 'admin', NOW()), + (2009, 'doctor_wu', '吴十一医生', 1009, 'wushiyi@hospital.com', '13900000009', '1', '0', '0', 'admin', NOW()), + (2010, 'doctor_zheng', '郑十二医生', 1010, 'zhengershi@hospital.com', '13900000010', '1', '0', '0', 'admin', NOW()) +ON CONFLICT (user_id) DO NOTHING; + +-- 1.3 测试护士 +INSERT INTO sys_user (user_id, user_name, nick_name, dept_id, email, phonenumber, sex, status, del_flag, create_by, create_time) +VALUES + (3001, 'nurse_a', '护士A', 1001, 'nursea@hospital.com', '13700000001', '2', '0', '0', 'admin', NOW()), + (3002, 'nurse_b', '护士B', 1005, 'nurseb@hospital.com', '13700000002', '2', '0', '0', 'admin', NOW()), + (3003, 'nurse_c', '护士C', 1006, 'nursec@hospital.com', '13700000003', '2', '0', '0', 'admin', NOW()), + (3004, 'nurse_d', '护士D', 1007, 'nursed@hospital.com', '13700000004', '2', '0', '0', 'admin', NOW()) +ON CONFLICT (user_id) DO NOTHING; + +-- ============================ +-- 二、测试患者数据 +-- ============================ + +-- 2.1 门诊患者 +INSERT INTO adm_patient (id, name, gender_enum, birth_date, phone, id_card, address, organization_id, tenant_id, delete_flag, create_by, create_time) +VALUES + (5001, '测试患者甲', 1, '1990-01-15 00:00:00+08', '13800138001', '450102199001011234', '广西南宁市青秀区民族大道100号', 1, 1, '0', 'admin', NOW()), + (5002, '测试患者乙', 2, '1985-05-20 00:00:00+08', '13800138002', '450102198505052345', '广西南宁市兴宁区朝阳路200号', 1, 1, '0', 'admin', NOW()), + (5003, '测试患者丙', 1, '2000-10-08 00:00:00+08', '13800138003', '450102200010103456', '广西南宁市西乡塘区大学路300号', 1, 1, '0', 'admin', NOW()), + (5004, '测试患者丁', 2, '1975-12-25 00:00:00+08', '13800138004', '450102197512124567', '广西南宁市良庆区银海大道400号', 1, 1, '0', 'admin', NOW()), + (5005, '测试患者戊', 1, '1965-03-10 00:00:00+08', '13800138005', '450102196503101234', '广西南宁市邕宁区蒲庙镇500号', 1, 1, '0', 'admin', NOW()), + (5006, '测试患者己', 2, '2015-08-18 00:00:00+08', '13800138006', '450102201508186789', '广西南宁市江南区星光大道600号', 1, 1, '0', 'admin', NOW()), + (5007, '急诊患者庚', 1, '1988-07-07 00:00:00+08', '13800138007', '450102198807071111', '广西南宁市青秀区东葛路700号', 1, 1, '0', 'admin', NOW()), + (5008, '急诊患者辛', 2, '1992-11-11 00:00:00+08', '13800138008', '450102199211112222', '广西南宁市青秀区凤岭北路800号', 1, 1, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 三、就诊记录(门诊+住院) +-- ============================ + +-- 3.1 门诊就诊记录 (class_enum=1门诊, class_enum=2住院) +INSERT INTO adm_encounter (id, patient_id, status_enum, class_enum, type_enum, start_time, organization_id, tenant_id, delete_flag, create_by, create_time) +VALUES + -- 门诊就诊 + (6001, 5001, 2, 1, 1, '2026-06-07 09:00:00+08', 1, 1, '0', 'admin', NOW()), + (6002, 5002, 2, 1, 1, '2026-06-07 09:30:00+08', 1, 1, '0', 'admin', NOW()), + (6003, 5003, 2, 1, 1, '2026-06-07 10:00:00+08', 1, 1, '0', 'admin', NOW()), + (6004, 5004, 2, 1, 1, '2026-06-07 10:30:00+08', 1, 1, '0', 'admin', NOW()), + (6005, 5005, 2, 1, 1, '2026-06-07 11:00:00+08', 1, 1, '0', 'admin', NOW()), + -- 住院就诊 + (6006, 5001, 2, 2, 1, '2026-06-01 14:00:00+08', 1, 1, '0', 'admin', NOW()), + (6007, 5002, 2, 2, 1, '2026-06-02 08:00:00+08', 1, 1, '0', 'admin', NOW()), + (6008, 5004, 2, 2, 1, '2026-06-03 10:00:00+08', 1, 1, '0', 'admin', NOW()), + (6009, 5005, 4, 2, 1, '2026-06-04 09:00:00+08', 1, 1, '0', 'admin', NOW()), + (6010, 5006, 2, 1, 1, '2026-06-07 14:00:00+08', 1, 1, '0', 'admin', NOW()), + -- 急诊就诊 + (6011, 5007, 2, 1, 1, '2026-06-07 02:30:00+08', 1, 1, '0', 'admin', NOW()), + (6012, 5008, 2, 1, 1, '2026-06-07 03:15:00+08', 1, 1, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 四、诊断数据 +-- ============================ + +INSERT INTO adm_encounter_diagnosis (id, encounter_id, patient_id, diagnosis_type_enum, delete_flag, create_by, create_time) +VALUES + (7001, 6001, 5001, 1, '0', 'admin', NOW()), + (7002, 6002, 5002, 1, '0', 'admin', NOW()), + (7003, 6006, 5001, 1, '0', 'admin', NOW()), + (7004, 6007, 5002, 1, '0', 'admin', NOW()), + (7005, 6008, 5004, 1, '0', 'admin', NOW()), + (7006, 6009, 5005, 1, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 五、检查检验数据 +-- ============================ + +-- 5.1 检查申请 +INSERT INTO check_apply (id, apply_no, encounter_id, patient_id, patient_name, id_card, fee_type, apply_date, apply_dept_id, apply_doctor_id, diagnosis_desc, check_purpose, status, total_amount, create_time) +VALUES + (8001, 'CK20260607001', 6001, 5001, '测试患者甲', '450102199001011234', '1', '2026-06-07 09:15:00+08', 1010, 2001, '咳嗽咳痰3天', '排除肺炎', 1, 280.00, NOW()), + (8002, 'CK20260607002', 6002, 5002, '测试患者乙', '450102198505052345', '1', '2026-06-07 09:45:00+08', 1010, 2002, '头痛头晕1周', '排除颅内病变', 1, 560.00, NOW()), + (8003, 'CK20260607003', 6011, 5007, '急诊患者庚', '450102198807071111', '1', '2026-06-07 02:45:00+08', 1010, 2006, '外伤后腹痛2小时', '排除脏器损伤', 1, 420.00, NOW()) +ON CONFLICT (id) DO NOTHING; + +-- 5.2 检查项目明细 +INSERT INTO check_apply_detail (id, apply_id, check_item_name, check_part, check_method, create_time) +VALUES + (9001, 8001, '胸部CT平扫', '胸部', 'CT', NOW()), + (9002, 8001, '血常规', '静脉血', '检验', NOW()), + (9003, 8002, '头颅MRI', '头部', 'MRI', NOW()), + (9004, 8002, '经颅多普勒', '头部', '超声', NOW()), + (9005, 8003, '腹部CT增强', '腹部', 'CT', NOW()), + (9006, 8003, '全血细胞计数', '静脉血', '检验', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- 5.3 检验申请 +INSERT INTO lab_apply (id, apply_no, patient_id, patient_name, apply_dept_code, apply_doc_code, apply_doc_name, apply_time, apply_status, delete_flag, create_by, create_time) +VALUES + (10001, 'LAB20260607001', 5001, '测试患者甲', '1009', '2009', '吴十一医生', '2026-06-07 09:20:00+08', '1', '0', 'admin', NOW()), + (10002, 'LAB20260607002', 5002, '测试患者乙', '1009', '2009', '吴十一医生', '2026-06-07 09:50:00+08', '1', '0', 'admin', NOW()), + (10003, 'LAB20260607003', 5006, '测试患者己', '1009', '2009', '吴十一医生', '2026-06-07 14:10:00+08', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 六、影像数据 +-- ============================ + +INSERT INTO radiology_image_report (id, apply_no, patient_id, patient_name, report_status, create_time) +VALUES + (11001, 'CK20260607001', 5001, '测试患者甲', '1', NOW()), + (11002, 'CK20260607002', 5002, '测试患者乙', '1', NOW()), + (11003, 'CK20260607003', 5007, '急诊患者庚', '1', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 七、手术数据 +-- ============================ + +INSERT INTO cli_surgery (id, patient_id, encounter_id, delete_flag, create_by, create_time) +VALUES + (12001, 5001, 6006, '0', 'admin', NOW()), + (12002, 5004, 6008, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 八、麻醉数据 +-- ============================ + +INSERT INTO anes_record (id, patient_id, encounter_id, delete_flag, create_by, create_time) +VALUES + (13001, 5001, 6006, '0', 'admin', NOW()), + (13002, 5004, 6008, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 九、护理数据 +-- ============================ + +-- 9.1 护理评估 +INSERT INTO nursing_assessment (id, patient_id, encounter_id, assessment_type, assessment_score, risk_level, delete_flag, create_by, create_time) +VALUES + (14001, 5001, 6006, 'braden', 12, 'high', '0', 'admin', NOW()), + (14002, 5002, 6007, 'morse', 45, 'high', '0', 'admin', NOW()), + (14003, 5004, 6008, 'nrs2002', 4, 'at_risk', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- 9.2 护理记录 +INSERT INTO nursing_vital_signs_chart (id, patient_id, encounter_id, temperature, pulse, respiration, blood_pressure_systolic, blood_pressure_diastolic, oxygen_saturation, delete_flag, create_by, create_time) +VALUES + (15001, 5001, 6006, 37.2, 78, 18, 125, 82, 98.5, '0', 'admin', NOW()), + (15002, 5002, 6007, 36.8, 72, 16, 130, 85, 99.0, '0', 'admin', NOW()), + (15003, 5004, 6008, 37.5, 85, 20, 140, 90, 97.5, '0', 'admin', NOW()), + (15004, 5005, 6009, 38.2, 92, 22, 150, 95, 96.0, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十、院感数据 +-- ============================ + +INSERT INTO hir_infection_case (id, patient_id, encounter_id, infection_type, pathogen, report_date, delete_flag, create_by, create_time) +VALUES + (16001, 5001, 6006, '医院获得性肺炎', '铜绿假单胞菌', '2026-06-03 10:00:00+08', '0', 'admin', NOW()), + (16002, 5002, 6007, '导管相关血流感染', '金黄色葡萄球菌', '2026-06-05 14:00:00+08', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO hir_hand_hygiene (id, dept_id, dept_name, month, total_opportunities, compliant_count, compliance_rate, delete_flag, create_by, create_time) +VALUES + (17001, 1005, 'ICU', '2026-06', 1200, 1140, 95.0, '0', 'admin', NOW()), + (17002, 1001, '门诊内科', '2026-06', 800, 720, 90.0, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十一、质控数据 +-- ============================ + +INSERT INTO emr_quality_score (id, encounter_id, patient_id, quality_type, score, delete_flag, create_by, create_time) +VALUES + (18001, 6006, 5001, '运行质控', 92.5, '0', 'admin', NOW()), + (18002, 6007, 5002, '终末质控', 88.0, '0', 'admin', NOW()), + (18003, 6008, 5004, '运行质控', 95.0, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十二、中医数据 +-- ============================ + +INSERT INTO tcm_constitution_assessment (id, patient_id, encounter_id, constitution_type, assessment_score, delete_flag, create_by, create_time) +VALUES + (19001, 5001, 6006, '气虚质', 65, '0', 'admin', NOW()), + (19002, 5002, 6007, '阳虚质', 70, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO tcm_prescription (id, prescription_name, prescription_type, composition, usage_method, delete_flag, create_by, create_time) +VALUES + (20001, '四君子汤', '补益剂', '人参、白术、茯苓、甘草', '水煎服,日一剂', '0', 'admin', NOW()), + (20002, '六味地黄丸', '补益剂', '熟地黄、山药、泽泻、牡丹皮、茯苓、山茱萸', '口服,一次8丸,一日3次', '0', 'admin', NOW()), + (20003, '小柴胡汤', '和解剂', '柴胡、黄芩、人参、半夏、甘草、生姜、大枣', '水煎服,日一剂', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十三、会诊数据 +-- ============================ + +INSERT INTO consultation_record (id, patient_id, encounter_id, consultation_type, requesting_dept, requested_dept, status, delete_flag, create_by, create_time) +VALUES + (21001, 5001, 6006, '科间会诊', 'ICU', '呼吸内科', '1', '0', 'admin', NOW()), + (21002, 5002, 6007, '全院会诊', 'ICU', '心内科', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十四、临床路径数据 +-- ============================ + +INSERT INTO clinical_pathway (id, pathway_name, disease_name, pathway_type, status, delete_flag, create_by, create_time) +VALUES + (22001, '社区获得性肺炎', '社区获得性肺炎', '内科', '1', '0', 'admin', NOW()), + (22002, '急性阑尾炎', '急性阑尾炎', '外科', '1', '0', 'admin', NOW()), + (22003, '2型糖尿病', '2型糖尿病', '内科', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十五、危急值数据 +-- ============================ + +INSERT INTO critical_value (id, patient_id, encounter_id, critical_item, critical_value, report_time, status, delete_flag, create_by, create_time) +VALUES + (23001, 5001, 6006, '血钾', '6.8mmol/L', '2026-06-03 15:30:00+08', '1', '0', 'admin', NOW()), + (23002, 5002, 6007, '血红蛋白', '52g/L', '2026-06-05 08:00:00+08', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十六、电子病历数据 +-- ============================ + +INSERT INTO doc_emr (id, encounter_id, patient_id, emr_type, emr_status, delete_flag, create_by, create_time) +VALUES + (24001, 6006, 5001, '入院记录', '1', '0', 'admin', NOW()), + (24002, 6007, 5002, '入院记录', '1', '0', 'admin', NOW()), + (24003, 6008, 5004, '入院记录', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十七、处方数据 +-- ============================ + +INSERT INTO med_medication_request (id, patient_id, encounter_id, request_type, status, delete_flag, create_by, create_time) +VALUES + (25001, 5001, 6006, '1', '1', '0', 'admin', NOW()), + (25002, 5002, 6007, '1', '1', '0', 'admin', NOW()), + (25003, 5004, 6008, '1', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十八、药品库存数据 +-- ============================ + +INSERT INTO pharmacy_stock_alert (id, medication_id, current_stock, minimum_stock, alert_level, delete_flag, create_by, create_time) +VALUES + (26001, 2037002083193978881, 50, 100, 'warning', '0', 'admin', NOW()), + (26002, 1983813501487038465, 10, 50, 'critical', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 十九、抗生素管理数据 +-- ============================ + +INSERT INTO antibiotic_approval (id, patient_id, encounter_id, antibiotic_name, approval_status, delete_flag, create_by, create_time) +VALUES + (27001, 5001, 6006, '头孢曲松', '1', '0', 'admin', NOW()), + (27002, 5002, 6007, '万古霉素', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十、药品追溯数据 +-- ============================ + +INSERT INTO drug_trace_code (id, drug_code, drug_name, batch_no, production_date, expiry_date, delete_flag, create_by, create_time) +VALUES + (28001, 'DRG001', '阿莫西林胶囊', 'B20260101', '2026-01-01', '2028-01-01', '0', 'admin', NOW()), + (28002, 'DRG002', '布洛芬缓释胶囊', 'B20260201', '2026-02-01', '2028-02-01', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十一、处方点评数据 +-- ============================ + +INSERT INTO review_plan (id, plan_name, plan_type, review_period, status, delete_flag, create_by, create_time) +VALUES + (29001, '2026年6月处方点评', '月度', '2026-06', '1', '0', 'admin', NOW()), + (29002, '2026年第二季度处方点评', '季度', '2026-Q2', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十二、DRG分析数据 +-- ============================ + +INSERT INTO drg_analysis_stats (id, encounter_id, drg_group, cost_weight, los_weight, delete_flag, create_by, create_time) +VALUES + (30001, 6006, 'ER1', 1.2, 1.0, '0', 'admin', NOW()), + (30002, 6007, 'FR1', 0.8, 0.9, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十三、随访数据 +-- ============================ + +INSERT INTO followup_plan (id, patient_id, encounter_id, followup_type, followup_date, status, delete_flag, create_by, create_time) +VALUES + (31001, 5001, 6006, '电话随访', '2026-06-14', '1', '0', 'admin', NOW()), + (31002, 5002, 6007, '门诊复查', '2026-06-20', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十四、知情同意数据 +-- ============================ + +INSERT INTO sys_informed_consent (id, patient_id, encounter_id, consent_type, status, delete_flag, create_by, create_time) +VALUES + (32001, 5001, 6006, '手术知情同意书', '1', '0', 'admin', NOW()), + (32002, 5002, 6007, '麻醉知情同意书', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十五、消毒供应中心数据 +-- ============================ + +INSERT INTO cssd_sterilize_batch (id, batch_no, sterilize_type, status, delete_flag, create_by, create_time) +VALUES + (33001, 'CSSD20260607001', '高压蒸汽', '1', '0', 'admin', NOW()), + (33002, 'CSSD20260607002', '低温等离子', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十六、EMPI主索引数据 +-- ============================ + +INSERT INTO empi_person (id, name, gender_enum, birth_date, id_card, phone, delete_flag, create_by, create_time) +VALUES + (34001, '测试患者甲', 1, '1990-01-15', '450102199001011234', '13800138001', '0', 'admin', NOW()), + (34002, '测试患者乙', 2, '1985-05-20', '450102198505052345', '13800138002', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十七、ESB数据集成数据 +-- ============================ + +INSERT INTO sys_esb_service_registry (id, service_name, service_code, service_type, status, delete_flag, create_by, create_time) +VALUES + (35001, '患者信息查询', 'PATIENT_QUERY', 'FHIR', '1', '0', 'admin', NOW()), + (35002, '检验结果查询', 'LAB_RESULT_QUERY', 'HL7', '1', '0', 'admin', NOW()), + (35003, '医嘱查询', 'ORDER_QUERY', 'FHIR', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十八、急诊绿色通道数据 +-- ============================ + +INSERT INTO emergency_green_channel (id, patient_id, encounter_id, channel_type, status, delete_flag, create_by, create_time) +VALUES + (36001, 5007, 6011, '胸痛中心', '1', '0', 'admin', NOW()), + (36002, 5008, 6012, '卒中中心', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 二十九、病案首页数据 +-- ============================ + +INSERT INTO mr_homepage (id, encounter_id, patient_id, homepage_status, delete_flag, create_by, create_time) +VALUES + (37001, 6009, 5005, '1', '0', 'admin', NOW()), + (37002, 6008, 5004, '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 三十、医嘱闭环数据 +-- ============================ + +INSERT INTO order_main (id, encounter_id, patient_id, order_type, order_status, delete_flag, create_by, create_time) +VALUES + (38001, 6006, 5001, '1', '1', '0', 'admin', NOW()), + (38002, 6007, 5002, '1', '1', '0', 'admin', NOW()), + (38003, 6008, 5004, '2', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 三十一、护理质量指标数据 +-- ============================ + +INSERT INTO nursing_quality_indicator (id, indicator_name, indicator_code, target_value, actual_value, indicator_period, delete_flag, create_by, create_time) +VALUES + (39001, '压疮发生率', 'NQ001', '0.5', '0.3', '2026-06', '0', 'admin', NOW()), + (39002, '跌倒发生率', 'NQ002', '1.0', '0.8', '2026-06', '0', 'admin', NOW()), + (39003, '导管滑脱率', 'NQ003', '0.5', '0.2', '2026-06', '0', 'admin', NOW()), + (39004, '给药差错率', 'NQ004', '0.1', '0.05', '2026-06', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 三十二、抗菌药物使用数据 +-- ============================ + +INSERT INTO hir_antibiotic_usage (id, patient_id, encounter_id, antibiotic_name, usage_days, ddd_value, delete_flag, create_by, create_time) +VALUES + (40001, 5001, 6006, '头孢曲松', 7, 2.0, '0', 'admin', NOW()), + (40002, 5002, 6007, '万古霉素', 10, 1.5, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 三十三、病案编码(DRG)数据 +-- ============================ + +INSERT INTO mr_drg_grouping (id, encounter_id, drg_code, drg_name, cost_weight, delete_flag, create_by, create_time) +VALUES + (41001, 6009, 'ER1', '呼吸系统感染', 1.2, '0', 'admin', NOW()), + (41002, 6008, 'FR1', '急性阑尾炎', 0.8, '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 三十四、满意度调查数据 +-- ============================ + +INSERT INTO satisfaction_survey (id, patient_id, encounter_id, survey_score, survey_type, delete_flag, create_by, create_time) +VALUES + (42001, 5005, 6009, 92, '出院患者', '0', 'admin', NOW()), + (42002, 5001, 6006, 88, '住院患者', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 三十五、交接班数据 +-- ============================ + +INSERT INTO nursing_handoff (id, from_nurse_id, to_nurse_id, handoff_time, handoff_type, status, delete_flag, create_by, create_time) +VALUES + (43001, 3001, 3002, '2026-06-07 08:00:00+08', '白班转夜班', '1', '0', 'admin', NOW()) +ON CONFLICT (id) DO NOTHING; + +-- ============================ +-- 完成! +-- ============================ diff --git a/MD/test/04_test_business_logic.py b/MD/test/04_test_business_logic.py new file mode 100755 index 000000000..8c67060af --- /dev/null +++ b/MD/test/04_test_business_logic.py @@ -0,0 +1,1020 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +HealthLink-HIS 三甲医院全流程业务逻辑测试 +版本: v2.0 +日期: 2026-06-07 + +测试理念: +- 不再只判断HTTP 200/500 +- 验证业务数据正确性(字段存在、值正确、关联关系正确) +- 验证业务流程链路(A→B→C步骤的因果关系) +- 验证异常场景(参数缺失、权限不足、数据不存在) +- 验证数据一致性(创建后查询能查到、更新后值改变、删除后查不到) +""" + +import requests +import json +import sys +import time +from datetime import datetime +from typing import Dict, Any, List, Tuple, Optional + +# ============================ +# 配置 +# ============================ +BASE_URL = "http://localhost:18082/healthlink-his" +ADMIN_USER = "admin" +ADMIN_PASS = "admin123" +TENANT_ID = "1" + +# 测试结果统计 +class TestStats: + def __init__(self): + self.total = 0 + self.passed = 0 + self.failed = 0 + self.skipped = 0 + self.results = [] + + def record(self, module: str, case_id: str, name: str, passed: bool, detail: str = ""): + self.total += 1 + if passed: + self.passed += 1 + status = "✅ PASS" + else: + self.failed += 1 + status = "❌ FAIL" + self.results.append({ + "module": module, + "case_id": case_id, + "name": name, + "status": status, + "detail": detail + }) + print(f" {status} [{module}] {case_id}: {name}") + if detail and not passed: + print(f" → {detail}") + + def summary(self): + print("\n" + "=" * 70) + print(f"测试汇总: 总数={self.total}, 通过={self.passed}, 失败={self.failed}") + if self.total > 0: + rate = self.passed * 100 / self.total + print(f"通过率: {rate:.1f}%") + print("=" * 70) + return self.failed == 0 + +stats = TestStats() +TOKEN = "" + +# ============================ +# 工具函数 +# ============================ +def login() -> str: + """登录获取Token""" + resp = requests.post(f"{BASE_URL}/login", json={ + "username": ADMIN_USER, + "password": ADMIN_PASS, + "tenantId": TENANT_ID + }) + data = resp.json() + return data.get("token", "") + +def headers() -> Dict: + return {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} + +def api_get(path: str, params: Dict = None) -> Dict: + resp = requests.get(f"{BASE_URL}{path}", headers=headers(), params=params) + return resp.json() + +def api_post(path: str, data: Dict = None) -> Dict: + resp = requests.post(f"{BASE_URL}{path}", headers=headers(), json=data) + return resp.json() + +def api_put(path: str, data: Dict = None) -> Dict: + resp = requests.put(f"{BASE_URL}{path}", headers=headers(), json=data) + return resp.json() + +def api_delete(path: str) -> Dict: + resp = requests.delete(f"{BASE_URL}{path}", headers=headers()) + return resp.json() + +def assert_response(resp: Dict, module: str, case_id: str, name: str, + expected_code: int = 200, + check_fields: List[str] = None, + check_values: Dict[str, Any] = None, + check_not_empty: List[str] = None): + """通用断言:检查响应码、字段存在、字段值""" + passed = True + detail = "" + + # 1. 检查HTTP响应码(业务码) + actual_code = resp.get("code") + if actual_code != expected_code: + passed = False + detail = f"预期code={expected_code}, 实际code={actual_code}, msg={resp.get('msg','')}" + stats.record(module, case_id, name, passed, detail) + return resp + + # 2. 检查字段存在 + if check_fields: + for field in check_fields: + if field not in resp: + passed = False + detail = f"响应缺少字段: {field}" + break + + # 3. 检查字段值 + if check_values and passed: + for field, expected_val in check_values.items(): + actual_val = resp.get(field) + if actual_val != expected_val: + passed = False + detail = f"字段{field}: 预期={expected_val}, 实际={actual_val}" + break + + # 4. 检查列表非空 + if check_not_empty and passed: + for field in check_not_empty: + val = resp.get(field) + if val is None or (isinstance(val, (list, dict)) and len(val) == 0): + passed = False + detail = f"字段{field}为空" + break + + stats.record(module, case_id, name, passed, detail) + return resp + +def assert_page_response(resp: Dict, module: str, case_id: str, name: str, + min_rows: int = 0, max_rows: int = 10000): + """断言分页查询响应""" + passed = True + detail = "" + + if resp.get("code") != 200: + passed = False + detail = f"code={resp.get('code')}, msg={resp.get('msg','')}" + else: + rows = resp.get("rows", resp.get("data", [])) + total = resp.get("total", 0) + if not isinstance(rows, list): + passed = False + detail = f"rows不是数组类型: {type(rows)}" + elif len(rows) < min_rows: + passed = False + detail = f"rows数量={len(rows)}, 最少需要{min_rows}" + elif total < min_rows: + passed = False + detail = f"total={total}, 最少需要{min_rows}" + + stats.record(module, case_id, name, passed, detail) + return resp + +# ============================ +# 测试模块1: 系统登录认证 +# ============================ +def test_auth(): + print("\n" + "=" * 50) + print("模块1: 系统登录认证") + print("=" * 50) + + # 1.1 登录成功 + resp = api_post("/login", {"username": "admin", "password": "admin123", "tenantId": "1"}) + assert_response(resp, "认证", "1.1", "登录成功验证", + expected_code=200, + check_fields=["token", "permissions", "roles"], + check_not_empty=["token"]) + + # 1.2 登录失败 - 错误密码 + resp = api_post("/login", {"username": "admin", "password": "wrongpass", "tenantId": "1"}) + assert_response(resp, "认证", "1.2", "错误密码应返回失败", + expected_code=500) # 若依框架返回500表示业务失败 + + # 1.3 获取用户信息 + resp = api_get("/getInfo") + assert_response(resp, "认证", "1.3", "获取用户信息", + expected_code=200, + check_fields=["user", "roles", "permissions"], + check_not_empty=["user"]) + + # 1.4 获取路由菜单 + resp = api_get("/getRouters") + assert_response(resp, "认证", "1.4", "获取路由菜单", + expected_code=200, + check_not_empty=["data"]) + + # 1.5 获取验证码 + resp = requests.get(f"{BASE_URL}/captchaImage") + captcha_data = resp.json() + assert_response(captcha_data, "认证", "1.5", "获取验证码", + expected_code=200, + check_fields=["img", "uuid"], + check_not_empty=["img", "uuid"]) + +# ============================ +# 测试模块2: 门诊挂号流程 +# ============================ +def test_registration(): + print("\n" + "=" * 50) + print("模块2: 门诊挂号流程") + print("=" * 50) + + # 2.1 挂号初始化 - 应返回优先级选项 + resp = api_get("/charge-manage/register/init") + assert_response(resp, "挂号", "2.1", "挂号初始化-返回优先级选项", + expected_code=200, + check_fields=["priorityLevelOptionOptions"]) + + # 2.2 挂号列表查询 - 应返回分页数据 + resp = api_get("/charge-manage/register/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "挂号", "2.2", "挂号列表分页查询", min_rows=0) + + # 2.3 查询患者信息 - 应返回患者列表 + resp = api_get("/charge-manage/register/patient", {"searchKey": "测试"}) + assert_response(resp, "挂号", "2.3", "查询患者-搜索'测试'", + expected_code=200) + + # 2.4 查询患者 - 空搜索应返回提示 + resp = api_get("/charge-manage/register/patient", {"searchKey": "不存在的患者XYZ"}) + assert_response(resp, "挂号", "2.4", "查询不存在的患者", + expected_code=200) # 应正常返回空列表 + +# ============================ +# 测试模块3: 门诊医生站 +# ============================ +def test_doctor_station(): + print("\n" + "=" * 50) + print("模块3: 门诊医生站") + print("=" * 50) + + # 3.1 待诊患者列表 + resp = api_get("/doctor-station/main/patient-list") + assert_response(resp, "医生站", "3.1", "待诊患者列表", + expected_code=200) + + # 3.2 医嘱列表查询 + resp = api_get("/doctor-station/advice/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "医生站", "3.2", "医嘱列表分页查询") + + # 3.3 诊断列表查询 + resp = api_get("/doctor-station/diagnosis/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "医生站", "3.3", "诊断列表分页查询") + + # 3.4 检查申请列表 + resp = api_get("/doctor-station/inspection/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "医生站", "3.4", "检查申请列表") + +# ============================ +# 测试模块4: 收费管理 +# ============================ +def test_charge(): + print("\n" + "=" * 50) + print("模块4: 收费管理") + print("=" * 50) + + # 4.1 收费初始化 + resp = api_get("/charge-manage/charge/init") + assert_response(resp, "收费", "4.1", "收费初始化", + expected_code=200) + + # 4.2 收费记录查询 + resp = api_get("/charge-manage/charge/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "收费", "4.2", "收费记录分页查询") + + # 4.3 退费记录查询 + resp = api_get("/charge-manage/refund/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "收费", "4.3", "退费记录分页查询") + + # 4.4 收费定价查询 + resp = api_get("/charge-manage/pricing/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "收费", "4.4", "收费定价列表") + +# ============================ +# 测试模块5: 住院管理 +# ============================ +def test_inpatient(): + print("\n" + "=" * 50) + print("模块5: 住院管理") + print("=" * 50) + + # 5.1 入院登记列表 + resp = api_get("/inhospitalmanage/register/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "住院", "5.1", "入院登记列表") + + # 5.2 患者主页初始化 + resp = api_get("/patient-home-manage/init") + assert_response(resp, "住院", "5.2", "患者主页初始化", + expected_code=200) + + # 5.3 空床查询 + resp = api_get("/patient-home-manage/empty-bed") + assert_response(resp, "住院", "5.3", "空床查询", + expected_code=200) + + # 5.4 押金管理初始化 + resp = api_get("/deposit-manage/init") + assert_response(resp, "住院", "5.4", "押金管理初始化", + expected_code=200) + + # 5.5 押金记录查询 + resp = api_get("/deposit-manage/deposit-page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "住院", "5.5", "押金记录分页查询") + + # 5.6 住院收费记录 + resp = api_get("/charge-manage/inpatient-charge/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "住院", "5.6", "住院收费记录") + +# ============================ +# 测试模块6: 护理管理 +# ============================ +def test_nursing(): + print("\n" + "=" * 50) + print("模块6: 护理管理") + print("=" * 50) + + # 6.1 护理评估列表 + resp = api_get("/nursing-assessment-enhanced/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "护理", "6.1", "护理评估列表") + + # 6.2 护理评估统计 + resp = api_get("/nursing-assessment-enhanced/stats") + assert_response(resp, "护理", "6.2", "护理评估统计", + expected_code=200) + + # 6.3 Braden压疮评估 - 业务逻辑验证 + braden_data = { + "patientName": "测试患者甲", + "encounterId": "6006", + "itemScores": json.dumps({"sensation": 2, "moisture": 2, "activity": 1, "mobility": 2, "nutrition": 3, "friction": 2}), + "detail": "压疮高危患者,需每2小时翻身" + } + resp = api_post("/nursing-assessment-enhanced/braden/assess", braden_data) + # 验证:评估应成功,且返回的评估分数应为12 (2+2+1+2+3+2) + assert_response(resp, "护理", "6.3", "Braden压疮评估-分数计算正确", + expected_code=200) + + # 6.4 Morse跌倒评估 + morse_data = { + "patientName": "测试患者乙", + "encounterId": "6007", + "itemScores": json.dumps({"history": 15, "diagnosis": 0, "ambulation": 15, "iv": 20, "gait": 0, "mental": 15}), + "detail": "跌倒高危患者,需加强防护" + } + resp = api_post("/nursing-assessment-enhanced/morse/assess", morse_data) + # 验证:Morse评分应为65 (15+0+15+20+0+15),属于高危 + assert_response(resp, "护理", "6.4", "Morse跌倒评估-分数计算正确", + expected_code=200) + + # 6.5 护理记录患者列表 + resp = api_get("/nursing-record/patient-page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "护理", "6.5", "护理记录患者列表") + + # 6.6 体征记录查询 + resp = api_get("/vital-signs/record-search") + assert_response(resp, "护理", "6.6", "体征记录查询", + expected_code=200) + + # 6.7 体征图表查询 + resp = api_get("/vital-signs-chart/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "护理", "6.7", "体征图表分页查询") + + # 6.8 护理执行列表 + resp = api_get("/nurse-station/advice-process/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "护理", "6.8", "护理执行列表") + + # 6.9 交接班记录 + resp = api_get("/nursing-handoff/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "护理", "6.9", "交接班记录查询") + + # 6.10 护理质量指标 + resp = api_get("/nursing-quality/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "护理", "6.10", "护理质量指标查询") + +# ============================ +# 测试模块7: 检验检查 +# ============================ +def test_inspection(): + print("\n" + "=" * 50) + print("模块7: 检验检查") + print("=" * 50) + + # 7.1 标本采集列表 + resp = api_get("/inspection/collection/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "检验", "7.1", "标本采集列表") + + # 7.2 检验观察定义 + resp = api_get("/inspection/observation/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "检验", "7.2", "检验观察定义列表") + + # 7.3 标本定义 + resp = api_get("/inspection/specimen/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "检验", "7.3", "标本定义列表") + + # 7.4 LIS配置 + resp = api_get("/inspection/lisConfig/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "检验", "7.4", "LIS配置列表") + + # 7.5 仪器管理 + resp = api_get("/inspection/instrument/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "检验", "7.5", "仪器管理列表") + + # 7.6 检验结果 + resp = api_get("/inspection/laboratory/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "检验", "7.6", "检验结果列表") + + # 7.7 参考范围 + resp = api_get("/lab-ref-range/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "检验", "7.7", "参考范围列表") + + # 7.8 检查申请 + resp = api_get("/check/examApply/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "检验", "7.8", "检查申请列表") + +# ============================ +# 测试模块8: 影像检查 +# ============================ +def test_radiology(): + print("\n" + "=" * 50) + print("模块8: 影像检查") + print("=" * 50) + + # 8.1 影像列表 + resp = api_get("/check/radiologyImage/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "影像", "8.1", "影像列表查询") + + # 8.2 影像增强 + resp = api_get("/check/radiologyEnhanced/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "影像", "8.2", "影像增强列表") + + # 8.3 影像对比 + resp = api_get("/check/radiologyComparison/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "影像", "8.3", "影像对比列表") + + # 8.4 3D重建 + resp = api_get("/reconstruction/3d/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "影像", "8.4", "3D重建列表") + +# ============================ +# 测试模块9: 手术麻醉 +# ============================ +def test_surgery(): + print("\n" + "=" * 50) + print("模块9: 手术麻醉") + print("=" * 50) + + # 9.1 手术列表 + resp = api_get("/clinical-manage/surgery/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "手术", "9.1", "手术列表查询") + + # 9.2 手术排程 + resp = api_get("/clinical-manage/surgery-schedule/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "手术", "9.2", "手术排程列表") + + # 9.3 术前讨论 + resp = api_get("/preopmanage/discussion/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "手术", "9.3", "术前讨论列表") + + # 9.4 手术安全核查 + resp = api_get("/surgery-safety-check/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "手术", "9.4", "手术安全核查列表") + + # 9.5 麻醉记录 + resp = api_get("/api/v1/anesthesia/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "手术", "9.5", "麻醉记录列表") + + # 9.6 麻醉增强 + resp = api_get("/anesthesia-enhanced/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "手术", "9.6", "麻醉增强列表") + + # 9.7 麻醉质控 + resp = api_get("/anesthesia-quality-control/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "手术", "9.7", "麻醉质控列表") + +# ============================ +# 测试模块10: 院感管理 +# ============================ +def test_infection(): + print("\n" + "=" * 50) + print("模块10: 院感管理") + print("=" * 50) + + modules = [ + ("10.1", "院感监测", "/infection-enhanced/surveillance/page"), + ("10.2", "院感预警", "/infection-enhanced/warning/page"), + ("10.3", "耐药监测", "/infection-enhanced/resistance/page"), + ("10.4", "职业暴露", "/infection-enhanced/exposure/page"), + ("10.5", "手卫生", "/infection-enhanced/hand-hygiene/page"), + ("10.6", "环境监测", "/infection-enhanced/environment/page"), + ] + for case_id, name, path in modules: + resp = api_get(path, {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "院感", case_id, name) + +# ============================ +# 测试模块11: 质量管理 +# ============================ +def test_quality(): + print("\n" + "=" * 50) + print("模块11: 质量管理") + print("=" * 50) + + # 11.1 运行质控 + resp = api_get("/quality-enhanced/runtime/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "质控", "11.1", "运行质控列表") + + # 11.2 终末质控 + resp = api_get("/api/v1/emr-quality/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "质控", "11.2", "终末质控列表") + + # 11.3 质量统计 + resp = api_get("/quality-enhanced/statistics/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "质控", "11.3", "质量统计列表") + +# ============================ +# 测试模块12: 中医管理 +# ============================ +def test_tcm(): + print("\n" + "=" * 50) + print("模块12: 中医管理") + print("=" * 50) + + # 12.1 中医体质列表 - 应包含我们插入的气虚质和阳虚质 + resp = api_get("/api/v1/tcm/constitution/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "中医", "12.1", "中医体质列表", min_rows=1) + + # 12.2 中医方剂列表 - 应包含四君子汤、六味地黄丸、小柴胡汤 + resp = api_get("/api/v1/tcm/prescriptions", {"pageNum": 1, "pageSize": 10}) + data = resp + rows = data.get("rows", data.get("data", [])) + passed = len(rows) >= 3 + detail = "" if passed else f"方剂数量不足: {len(rows)}, 预期>=3" + stats.record("中医", "12.2", "中医方剂列表-至少3个方剂", passed, detail) + + # 12.3 中医统计 + resp = api_get("/api/v1/tcm/statistics") + assert_response(resp, "中医", "12.3", "中医统计查询", + expected_code=200) + +# ============================ +# 测试模块13: 会诊管理 +# ============================ +def test_consultation(): + print("\n" + "=" * 50) + print("模块13: 会诊管理") + print("=" * 50) + + # 13.1 会诊记录 + resp = api_get("/consultation/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "会诊", "13.1", "会诊记录列表") + + # 13.2 会诊反馈 + resp = api_get("/cross-module/consult-feedback/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "会诊", "13.2", "会诊反馈列表") + + # 13.3 会诊超时 + resp = api_get("/cross-module/consulttimeout/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "会诊", "13.3", "会诊超时列表") + +# ============================ +# 测试模块14: 临床路径 +# ============================ +def test_pathway(): + print("\n" + "=" * 50) + print("模块14: 临床路径") + print("=" * 50) + + # 14.1 临床路径列表 - 应包含社区获得性肺炎、急性阑尾炎、2型糖尿病 + resp = api_get("/clinical-pathway/page", {"pageNum": 1, "pageSize": 10}) + data = resp + rows = data.get("rows", data.get("data", [])) + passed = len(rows) >= 3 + detail = "" if passed else f"路径数量不足: {len(rows)}, 预期>=3" + stats.record("路径", "14.1", "临床路径列表-至少3条路径", passed, detail) + +# ============================ +# 测试模块15: 危急值管理 +# ============================ +def test_critical(): + print("\n" + "=" * 50) + print("模块15: 危急值管理") + print("=" * 50) + + # 15.1 危急值列表 - 应包含血钾6.8和血红蛋白52 + resp = api_get("/api/v1/critical-value/page", {"pageNum": 1, "pageSize": 10}) + data = resp + rows = data.get("rows", data.get("data", [])) + # 检查是否有危急值记录 + passed = isinstance(rows, list) + detail = "" if passed else "危急值列表返回格式异常" + stats.record("危急值", "15.1", "危急值列表查询", passed, detail) + +# ============================ +# 测试模块16: 处方点评 +# ============================ +def test_review(): + print("\n" + "=" * 50) + print("模块16: 处方点评") + print("=" * 50) + + # 16.1 点评计划 + resp = api_get("/api/v1/review/plans", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "点评", "16.1", "点评计划列表") + + # 16.2 点评记录 + resp = api_get("/api/v1/review/records", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "点评", "16.2", "点评记录列表") + + # 16.3 点评统计 + resp = api_get("/api/v1/review/statistics") + assert_response(resp, "点评", "16.3", "点评统计查询", + expected_code=200) + +# ============================ +# 测试模块17: 合理用药 +# ============================ +def test_rational_drug(): + print("\n" + "=" * 50) + print("模块17: 合理用药") + print("=" * 50) + + # 17.1 合理用药列表 + resp = api_get("/api/v1/rational-drug/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "用药", "17.1", "合理用药列表") + + # 17.2 相互作用 + resp = api_get("/api/v1/rational-drug/interaction/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "用药", "17.2", "相互作用列表") + + # 17.3 用药统计 + resp = api_get("/api/v1/rational-drug/statistics") + assert_response(resp, "用药", "17.3", "用药统计查询", + expected_code=200) + + # 17.4 审计日志 + resp = api_get("/api/v1/rational-drug/audit-log", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "用药", "17.4", "审计日志列表") + +# ============================ +# 测试模块18: 药品追溯 +# ============================ +def test_drug_trace(): + print("\n" + "=" * 50) + print("模块18: 药品追溯") + print("=" * 50) + + # 18.1 药品追溯列表 + resp = api_get("/drugtrace/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "追溯", "18.1", "药品追溯列表") + +# ============================ +# 测试模块19: EMPI主索引 +# ============================ +def test_empi(): + print("\n" + "=" * 50) + print("模块19: EMPI主索引") + print("=" * 50) + + # 19.1 EMPI索引列表 + resp = api_get("/api/v1/empi/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "EMPI", "19.1", "EMPI索引列表") + +# ============================ +# 测试模块20: ESB数据集成 +# ============================ +def test_esb(): + print("\n" + "=" * 50) + print("模块20: ESB数据集成") + print("=" * 50) + + # 20.1 ESB消息监控 + resp = api_get("/esbmanage/message/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "ESB", "20.1", "ESB消息列表") + + # 20.2 ESB服务注册 + resp = api_get("/esbmanage/registry/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "ESB", "20.2", "ESB服务注册列表") + +# ============================ +# 测试模块21: 电子签名 +# ============================ +def test_ca(): + print("\n" + "=" * 50) + print("模块21: 电子签名") + print("=" * 50) + + # 21.1 CA签名列表 + resp = api_get("/api/v1/ca-signature/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "CA", "21.1", "CA签名列表") + + # 21.2 CA签名统计 + resp = api_get("/api/v1/ca-signature/statistics") + assert_response(resp, "CA", "21.2", "CA签名统计", + expected_code=200) + +# ============================ +# 测试模块22: 病案管理 +# ============================ +def test_mr(): + print("\n" + "=" * 50) + print("模块22: 病案管理") + print("=" * 50) + + # 22.1 病案首页 + resp = api_get("/api/v1/mr-homepage/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "病案", "22.1", "病案首页列表") + + # 22.2 病案质量检查 + resp = api_get("/api/v1/mr-homepage/quality-check/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "病案", "22.2", "病案质量检查") + +# ============================ +# 测试模块23: 随访管理 +# ============================ +def test_followup(): + print("\n" + "=" * 50) + print("模块23: 随访管理") + print("=" * 50) + + # 23.1 随访计划 + resp = api_get("/followup/plan/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "随访", "23.1", "随访计划列表") + +# ============================ +# 测试模块24: 知情同意 +# ============================ +def test_consent(): + print("\n" + "=" * 50) + print("模块24: 知情同意") + print("=" * 50) + + # 24.1 知情同意列表 + resp = api_get("/api/v1/informed-consent/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "知情", "24.1", "知情同意列表") + +# ============================ +# 测试模块25: 消毒供应 +# ============================ +def test_cssd(): + print("\n" + "=" * 50) + print("模块25: 消毒供应") + print("=" * 50) + + # 25.1 消毒追溯 + resp = api_get("/cssd/trace/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "CSSD", "25.1", "消毒追溯列表") + +# ============================ +# 测试模块26: 急诊管理 +# ============================ +def test_emergency(): + print("\n" + "=" * 50) + print("模块26: 急诊管理") + print("=" * 50) + + # 26.1 急诊记录 + resp = api_get("/emergency/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "急诊", "26.1", "急诊记录列表") + + # 26.2 分诊排队 + resp = api_get("/triage/queue/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "急诊", "26.2", "分诊排队列表") + +# ============================ +# 测试模块27: 医保管理 +# ============================ +def test_insurance(): + print("\n" + "=" * 50) + print("模块27: 医保管理") + print("=" * 50) + + # 27.1 医保目录 + resp = api_get("/ybmanage/catalog/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "医保", "27.1", "医保目录列表") + +# ============================ +# 测试模块28: 抗菌药物 +# ============================ +def test_antibiotic(): + print("\n" + "=" * 50) + print("模块28: 抗菌药物") + print("=" * 50) + + # 28.1 抗菌药物列表 + resp = api_get("/api/v1/antibiotic/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "抗菌", "28.1", "抗菌药物列表") + +# ============================ +# 测试模块29: DRG分析 +# ============================ +def test_drg(): + print("\n" + "=" * 50) + print("模块29: DRG分析") + print("=" * 50) + + # 29.1 DRG分析 + resp = api_get("/api/v1/mr-homepage/drg/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "DRG", "29.1", "DRG分析列表") + + # 29.2 DRG预警 + resp = api_get("/cross-module/enhanced-drg-alert/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "DRG", "29.2", "DRG预警列表") + +# ============================ +# 测试模块30: 经营分析 +# ============================ +def test_analytics(): + print("\n" + "=" * 50) + print("模块30: 经营分析") + print("=" * 50) + + # 30.1 经营分析 + resp = api_get("/business-analytics/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "经营", "30.1", "经营分析列表") + +# ============================ +# 测试模块31: 系统管理 +# ============================ +def test_system(): + print("\n" + "=" * 50) + print("模块31: 系统管理") + print("=" * 50) + + # 31.1 字典类型 + resp = api_get("/dict/type/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "系统", "31.1", "字典类型列表") + + # 31.2 用户管理 + resp = api_get("/system/user/page", {"pageNum": 1, "pageSize": 10}) + data = resp + rows = data.get("rows", data.get("data", [])) + passed = isinstance(rows, list) and len(rows) > 0 + detail = "" if passed else "用户列表为空,系统用户数据异常" + stats.record("系统", "31.2", "用户管理-列表非空", passed, detail) + + # 31.3 角色管理 + resp = api_get("/system/role/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "系统", "31.3", "角色管理列表") + + # 31.4 菜单管理 + resp = api_get("/system/menu/list") + data = resp + rows = data.get("data", []) + passed = isinstance(rows, list) and len(rows) > 50 + detail = "" if passed else f"菜单数量异常: {len(rows) if isinstance(rows, list) else 'N/A'}, 预期>50" + stats.record("系统", "31.4", "菜单管理-菜单数量>50", passed, detail) + + # 31.5 部门管理 + resp = api_get("/system/dept/list") + data = resp + rows = data.get("data", []) + passed = isinstance(rows, list) and len(rows) > 5 + detail = "" if passed else f"部门数量异常: {len(rows) if isinstance(rows, list) else 'N/A'}, 预期>5" + stats.record("系统", "31.5", "部门管理-部门数量>5", passed, detail) + + # 31.6 岗位管理 + resp = api_get("/system/post/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "系统", "31.6", "岗位管理列表") + + # 31.7 通知管理 + resp = api_get("/system/notice/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "系统", "31.7", "通知管理列表") + + # 31.8 审计日志 + resp = api_get("/audit-log/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "系统", "31.8", "审计日志列表") + + # 31.9 仪表盘数据 + resp = api_get("/dashboard/data") + assert_response(resp, "系统", "31.9", "仪表盘数据", + expected_code=200) + +# ============================ +# 测试模块32: 药房管理 +# ============================ +def test_pharmacy(): + print("\n" + "=" * 50) + print("模块32: 药房管理") + print("=" * 50) + + # 32.1 库存预警 + resp = api_get("/pharmacy-stock-alert/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "药房", "32.1", "库存预警列表") + + # 32.2 西药发药 + resp = api_get("/pharmacy-manage/western-medicine-dispense/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "药房", "32.2", "西药发药列表") + + # 32.3 退药管理 + resp = api_get("/pharmacy-manage/return-medicine/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "药房", "32.3", "退药管理列表") + + # 32.4 药品详情 + resp = api_get("/pharmacy-manage/medication-details/page", {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "药房", "32.4", "药品详情列表") + +# ============================ +# 测试模块33: 报表管理 +# ============================ +def test_reports(): + print("\n" + "=" * 50) + print("模块33: 报表管理") + print("=" * 50) + + reports = [ + ("33.1", "挂号报表", "/report-manage/register/page"), + ("33.2", "收费报表", "/report-manage/charge/page"), + ("33.3", "住院首页采集", "/medicalRecordHomePage-manage/collection/page"), + ("33.4", "经营统计", "/report-manage/report-statistics/page"), + ] + for case_id, name, path in reports: + resp = api_get(path, {"pageNum": 1, "pageSize": 10}) + assert_page_response(resp, "报表", case_id, name) + +# ============================ +# 主入口 +# ============================ +if __name__ == "__main__": + print("=" * 70) + print("HealthLink-HIS 三甲医院全流程业务逻辑测试") + print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + print(f"测试环境: {BASE_URL}") + print("=" * 70) + + # 登录 + print("\n>>> 登录系统...") + TOKEN = login() + if not TOKEN: + print("❌ 登录失败,无法继续测试!") + sys.exit(1) + print(f"✅ 登录成功") + + # 执行所有测试模块 + test_modules = [ + test_auth, + test_registration, + test_doctor_station, + test_charge, + test_inpatient, + test_nursing, + test_inspection, + test_radiology, + test_surgery, + test_infection, + test_quality, + test_tcm, + test_consultation, + test_pathway, + test_critical, + test_review, + test_rational_drug, + test_drug_trace, + test_empi, + test_esb, + test_ca, + test_mr, + test_followup, + test_consent, + test_cssd, + test_emergency, + test_insurance, + test_antibiotic, + test_drg, + test_analytics, + test_system, + test_pharmacy, + test_reports, + ] + + for test_func in test_modules: + try: + test_func() + except Exception as e: + print(f" ❌ 模块执行异常: {test_func.__name__}: {e}") + stats.record("异常", test_func.__name__, "模块执行异常", False, str(e)) + + # 输出汇总 + success = stats.summary() + + # 生成报告文件 + report_path = f"MD/test/reports/business_logic_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md" + import os + os.makedirs("MD/test/reports", exist_ok=True) + with open(report_path, "w", encoding="utf-8") as f: + f.write("# HealthLink-HIS 业务逻辑测试报告\n\n") + f.write(f"**测试时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n") + f.write(f"**测试环境**: {BASE_URL}\n\n") + f.write("## 测试汇总\n\n") + f.write(f"- 总测试数: {stats.total}\n") + f.write(f"- 通过数: {stats.passed}\n") + f.write(f"- 失败数: {stats.failed}\n") + f.write(f"- 通过率: {stats.passed*100/stats.total:.1f}%\n\n" if stats.total > 0 else "") + f.write("## 详细结果\n\n") + f.write("| 模块 | 编号 | 测试项 | 状态 | 说明 |\n") + f.write("|------|------|--------|------|------|\n") + for r in stats.results: + f.write(f"| {r['module']} | {r['case_id']} | {r['name']} | {r['status']} | {r['detail']} |\n") + + print(f"\n📄 测试报告已生成: {report_path}") + + sys.exit(0 if success else 1) diff --git a/MD/test/04_test_business_logic_v2.py b/MD/test/04_test_business_logic_v2.py new file mode 100755 index 000000000..a25657c69 --- /dev/null +++ b/MD/test/04_test_business_logic_v2.py @@ -0,0 +1,631 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +HealthLink-HIS 三甲医院全流程业务逻辑测试 v2 +使用实际Controller中的正确API路径 +""" + +import requests, json, sys, os, time +from datetime import datetime +from typing import Dict, Any, List + +BASE_URL = "http://localhost:18082/healthlink-his" +TOKEN = "" + +class TestStats: + def __init__(self): + self.total = self.passed = self.failed = 0 + self.results = [] + def record(self, module, case_id, name, passed, detail=""): + self.total += 1 + if passed: self.passed += 1 + else: self.failed += 1 + status = "✅ PASS" if passed else "❌ FAIL" + self.results.append({"module":module,"case_id":case_id,"name":name,"status":status,"detail":detail}) + print(f" {status} [{module}] {case_id}: {name}") + if detail and not passed: print(f" → {detail}") + def summary(self): + print(f"\n{'='*70}") + print(f"测试汇总: 总数={self.total}, 通过={self.passed}, 失败={self.failed}") + if self.total > 0: print(f"通过率: {self.passed*100/self.total:.1f}%") + print(f"{'='*70}") + return self.failed == 0 + +stats = TestStats() + +def login(): + r = requests.post(f"{BASE_URL}/login", json={"username":"admin","password":"admin123","tenantId":"1"}) + return r.json().get("token","") + +def H(): return {"Authorization":f"Bearer {TOKEN}","Content-Type":"application/json"} + +def GET(p, params=None): return requests.get(f"{BASE_URL}{p}", headers=H(), params=params).json() +def POST(p, d=None): return requests.post(f"{BASE_URL}{p}", headers=H(), json=d).json() +def PUT(p, d=None): return requests.put(f"{BASE_URL}{p}", headers=H(), json=d).json() + +def chk_resp(resp, mod, cid, name, code=200, fields=None, not_empty=None): + ok = True; detail = "" + if resp.get("code") != code: + ok = False; detail = f"code={resp.get('code')}, msg={resp.get('msg','')[:120]}" + if ok and fields: + for f in fields: + if f not in resp: ok = False; detail=f"缺少字段: {f}"; break + if ok and not_empty: + for f in not_empty: + v = resp.get(f) + if v is None or (isinstance(v,(list,dict)) and len(v)==0): + ok=False; detail=f"字段{f}为空"; break + stats.record(mod, cid, name, ok, detail) + return resp + +def chk_page(resp, mod, cid, name, min_rows=0): + ok = True; detail = "" + if resp.get("code") != 200: + ok = False; detail = f"code={resp.get('code')}, msg={resp.get('msg','')[:120]}" + else: + rows = resp.get("rows", resp.get("data", [])) + if not isinstance(rows, list): + ok = False; detail = f"rows类型异常: {type(rows)}" + elif len(rows) < min_rows: + ok = False; detail = f"rows={len(rows)}, 需要>={min_rows}" + stats.record(mod, cid, name, ok, detail) + return resp + +# ============================ +# 模块1: 系统登录认证 +# ============================ +def test_auth(): + print(f"\n{'='*50}\n模块1: 系统登录认证\n{'='*50}") + + r = POST("/login", {"username":"admin","password":"admin123","tenantId":"1"}) + chk_resp(r, "认证","1.1","登录成功-返回token", 200, ["token"], ["token"]) + + r = POST("/login", {"username":"admin","password":"wrong","tenantId":"1"}) + chk_resp(r, "认证","1.2","错误密码-应失败", 500) + + r = GET("/getInfo") + chk_resp(r, "认证","1.3","获取用户信息", 200, ["user","roles"], ["user"]) + + r = GET("/getRouters") + chk_resp(r, "认证","1.4","获取路由菜单", 200, ["data"], ["data"]) + +# ============================ +# 模块2: 门诊挂号 (实际路径: /charge-manage/register) +# ============================ +def test_registration(): + print(f"\n{'='*50}\n模块2: 门诊挂号流程\n{'='*50}") + + # 2.1 挂号初始化 - 应返回选项数据 + r = GET("/charge-manage/register/init") + chk_resp(r, "挂号","2.1","挂号初始化", 200) + + # 2.2 当日挂号列表 (current-day-encounter) + r = GET("/charge-manage/register/current-day-encounter") + chk_resp(r, "挂号","2.2","当日挂号列表", 200) + + # 2.3 患者元数据查询 + r = GET("/charge-manage/register/patient-metadata", {"searchKey":"测试"}) + chk_resp(r, "挂号","2.3","患者元数据查询", 200) + + # 2.4 医生列表 + r = GET("/charge-manage/register/all-doctors") + chk_resp(r, "挂号","2.4","全部医生列表", 200) + +# ============================ +# 模块3: 门诊医生站 (实际路径) +# ============================ +def test_doctor_station(): + print(f"\n{'='*50}\n模块3: 门诊医生站\n{'='*50}") + + # 3.1 医生站初始化 + r = GET("/doctor-station/main/init") + chk_resp(r, "医生站","3.1","医生站初始化", 200) + + # 3.2 患者信息查询 + r = GET("/doctor-station/main/patient-info") + chk_resp(r, "医生站","3.2","患者信息查询", 200) + + # 3.3 接诊统计 + r = GET("/doctor-station/main/reception-statistics") + chk_resp(r, "医生站","3.3","接诊统计", 200) + + # 3.4 医嘱基础信息 + r = GET("/doctor-station/advice/advice-base-info") + chk_resp(r, "医生站","3.4","医嘱基础信息", 200) + + # 3.5 诊断初始化 + r = GET("/doctor-station/diagnosis/init") + chk_resp(r, "医生站","3.5","诊断初始化", 200) + + # 3.6 诊断定义分类 + r = GET("/doctor-station/diagnosis/get-condition-definition-class") + chk_resp(r, "医生站","3.6","诊断定义分类", 200) + + # 3.7 检查申请 + r = GET("/doctor-station/inspection/init") + chk_resp(r, "医生站","3.7","检查申请初始化", 200) + +# ============================ +# 模块4: 收费管理 (实际路径) +# ============================ +def test_charge(): + print(f"\n{'='*50}\n模块4: 收费管理\n{'='*50}") + + # 4.1 门诊收费初始化 + r = GET("/charge-manage/charge/init") + chk_resp(r, "收费","4.1","门诊收费初始化", 200) + + # 4.2 门诊收费-患者列表 + r = GET("/charge-manage/charge/encounter-patient-page") + chk_resp(r, "收费","4.2","收费患者列表", 200) + + # 4.3 退费初始化 + r = GET("/charge-manage/refund/init") + chk_resp(r, "收费","4.3","退费初始化", 200) + + # 4.4 退费患者列表 + r = GET("/charge-manage/refund/encounter-patient-page") + chk_resp(r, "收费","4.4","退费患者列表", 200) + + # 4.5 住院收费初始化 + r = GET("/charge-manage/inpatient-charge/init") + chk_resp(r, "收费","4.5","住院收费初始化", 200) + + # 4.6 住院收费-患者列表 + r = GET("/charge-manage/inpatient-charge/encounter-patient-page") + chk_resp(r, "收费","4.6","住院收费患者列表", 200) + + # 4.7 定价-患者信息 + r = GET("/charge-manage/pricing/patient-info") + chk_resp(r, "收费","4.7","定价患者信息", 200) + +# ============================ +# 模块5: 住院管理 (实际路径) +# ============================ +def test_inpatient(): + print(f"\n{'='*50}\n模块5: 住院管理\n{'='*50}") + + # 5.1 患者主页初始化 + r = GET("/patient-home-manage/init") + chk_resp(r, "住院","5.1","患者主页初始化", 200) + + # 5.2 空床查询 + r = GET("/patient-home-manage/empty-bed") + chk_resp(r, "住院","5.2","空床查询", 200) + + # 5.3 科室统计 + r = GET("/patient-home-manage/caty") + chk_resp(r, "住院","5.3","科室统计", 200) + + # 5.4 押金初始化 + r = GET("/deposit-manage/init") + chk_resp(r, "住院","5.4","押金初始化", 200) + + # 5.5 入院登记-按医生 + r = GET("/inhospitalmanage/register/ward-list") + chk_resp(r, "住院","5.5","入院登记-病区列表", 200) + + # 5.6 入院登记-床位数 + r = GET("/inhospitalmanage/register/beds-num") + chk_resp(r, "住院","5.6","入院登记-床位数", 200) + + # 5.7 入院登记-患者信息 + r = GET("/inhospitalmanage/register/patient-info") + chk_resp(r, "住院","5.7","入院登记-患者信息", 200) + +# ============================ +# 模块6: 护理管理 +# ============================ +def test_nursing(): + print(f"\n{'='*50}\n模块6: 护理管理\n{'='*50}") + + # 6.1 护理评估列表 + r = GET("/nursing-assessment-enhanced/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "护理","6.1","护理评估列表") + + # 6.2 护理评估统计 + r = GET("/nursing-assessment-enhanced/stats") + chk_resp(r, "护理","6.2","护理评估统计", 200) + + # 6.3 Braden评估 - 验证分数计算 + braden = {"patientName":"测试患者甲","encounterId":"6006", + "itemScores":json.dumps({"sensation":2,"moisture":2,"activity":1,"mobility":2,"nutrition":3,"friction":2}), + "detail":"压疮高危"} + r = POST("/nursing-assessment-enhanced/braden/assess", braden) + chk_resp(r, "护理","6.3","Braden评估-成功", 200) + + # 6.4 Morse跌倒评估 + morse = {"patientName":"测试患者乙","encounterId":"6007", + "itemScores":json.dumps({"history":15,"diagnosis":0,"ambulation":15,"iv":20,"gait":0,"mental":15}), + "detail":"跌倒高危"} + r = POST("/nursing-assessment-enhanced/morse/assess", morse) + chk_resp(r, "护理","6.4","Morse评估-成功", 200) + + # 6.5 体征记录查询 + r = GET("/vital-signs/record-search") + chk_resp(r, "护理","6.5","体征记录查询", 200) + + # 6.6 体征图表 + r = GET("/vital-signs-chart/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "护理","6.6","体征图表") + + # 6.7 护理执行列表 + r = GET("/nurse-station/advice-process/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "护理","6.7","护理执行列表") + + # 6.8 护理质量 + r = GET("/nursing-quality/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "护理","6.8","护理质量指标") + +# ============================ +# 模块7: 检验检查 +# ============================ +def test_inspection(): + print(f"\n{'='*50}\n模块7: 检验检查\n{'='*50}") + + endpoints = [ + ("7.1","标本采集","/inspection/collection/page"), + ("7.2","检验观察","/inspection/observation/page"), + ("7.3","标本定义","/inspection/specimen/page"), + ("7.4","LIS配置","/inspection/lisConfig/page"), + ("7.5","仪器管理","/inspection/instrument/page"), + ("7.6","检验结果","/inspection/laboratory/page"), + ("7.7","参考范围","/lab-ref-range/page"), + ("7.8","检查申请","/exam/apply/page"), + ] + for cid,name,path in endpoints: + r = GET(path, {"pageNum":1,"pageSize":10}) + chk_page(r, "检验", cid, name) + +# ============================ +# 模块8: 影像检查 +# ============================ +def test_radiology(): + print(f"\n{'='*50}\n模块8: 影像检查\n{'='*50}") + + r = GET("/radiology-image/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "影像","8.1","影像列表") + r = GET("/radiology-enhanced/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "影像","8.2","影像增强") + r = GET("/radiology-comparison/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "影像","8.3","影像对比") + r = GET("/reconstruction/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "影像","8.4","3D重建") + +# ============================ +# 模块9: 手术麻醉 +# ============================ +def test_surgery(): + print(f"\n{'='*50}\n模块9: 手术麻醉\n{'='*50}") + + r = GET("/clinical-manage/surgery/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "手术","9.1","手术列表") + r = GET("/clinical-manage/surgery-schedule/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "手术","9.2","手术排程") + r = GET("/preop-discussion/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "手术","9.3","术前讨论") + r = GET("/surgery-safety-check/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "手术","9.4","安全核查") + r = GET("/api/v1/anesthesia/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "麻醉","9.5","麻醉记录") + r = GET("/anesthesia-enhanced/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "麻醉","9.6","麻醉增强") + +# ============================ +# 模块10: 院感管理 +# ============================ +def test_infection(): + print(f"\n{'='*50}\n模块10: 院感管理\n{'='*50}") + + r = GET("/infection-enhanced/surveillance/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "院感","10.1","院感监测") + r = GET("/infection-enhanced/warning/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "院感","10.2","院感预警") + r = GET("/infection-enhanced/resistance/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "院感","10.3","耐药监测") + r = GET("/infection-enhanced/exposure/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "院感","10.4","职业暴露") + r = GET("/infection-enhanced/hand-hygiene/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "院感","10.5","手卫生") + r = GET("/infection-enhanced/environment/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "院感","10.6","环境监测") + +# ============================ +# 模块11: 质量管理 +# ============================ +def test_quality(): + print(f"\n{'='*50}\n模块11: 质量管理\n{'='*50}") + + r = GET("/quality-enhanced/runtime/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "质控","11.1","运行质控") + r = GET("/api/v1/emr-quality/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "质控","11.2","终末质控") + r = GET("/quality-enhanced/statistics/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "质控","11.3","质量统计") + +# ============================ +# 模块12: 中医管理 +# ============================ +def test_tcm(): + print(f"\n{'='*50}\n模块12: 中医管理\n{'='*50}") + + r = GET("/api/v1/tcm/constitution/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "中医","12.1","中医体质", min_rows=1) + + r = GET("/api/v1/tcm/prescriptions", {"pageNum":1,"pageSize":10}) + rows = r.get("rows", r.get("data", [])) + ok = isinstance(rows, list) and len(rows) >= 3 + stats.record("中医","12.2","方剂列表>=3个", ok, "" if ok else f"实际={len(rows)}") + + r = GET("/api/v1/tcm/statistics") + chk_resp(r, "中医","12.3","中医统计", 200) + +# ============================ +# 模块13: 会诊管理 +# ============================ +def test_consultation(): + print(f"\n{'='*50}\n模块13: 会诊管理\n{'='*50}") + + r = GET("/consultation/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "会诊","13.1","会诊记录") + r = GET("/cross-module/consult-feedback/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "会诊","13.2","会诊反馈") + r = GET("/cross-module/consulttimeout/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "会诊","13.3","会诊超时") + +# ============================ +# 模块14: 临床路径 +# ============================ +def test_pathway(): + print(f"\n{'='*50}\n模块14: 临床路径\n{'='*50}") + + r = GET("/clinical-pathway/page", {"pageNum":1,"pageSize":10}) + rows = r.get("rows", r.get("data", [])) + ok = isinstance(rows, list) and len(rows) >= 2 + stats.record("路径","14.1","临床路径>=2条", ok, "" if ok else f"实际={len(rows)}") + +# ============================ +# 模块15: 危急值 +# ============================ +def test_critical(): + print(f"\n{'='*50}\n模块15: 危急值管理\n{'='*50}") + + r = GET("/api/v1/critical-value/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "危急值","15.1","危急值列表") + +# ============================ +# 模块16: 处方点评 +# ============================ +def test_review(): + print(f"\n{'='*50}\n模块16: 处方点评\n{'='*50}") + + r = GET("/api/v1/review/plans", {"pageNum":1,"pageSize":10}) + chk_page(r, "点评","16.1","点评计划") + r = GET("/api/v1/review/records", {"pageNum":1,"pageSize":10}) + chk_page(r, "点评","16.2","点评记录") + r = GET("/api/v1/review/statistics") + chk_resp(r, "点评","16.3","点评统计", 200) + +# ============================ +# 模块17: 合理用药 +# ============================ +def test_rational_drug(): + print(f"\n{'='*50}\n模块17: 合理用药\n{'='*50}") + + r = GET("/api/v1/rational-drug/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "用药","17.1","合理用药") + r = GET("/api/v1/rational-drug/interaction/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "用药","17.2","相互作用") + r = GET("/api/v1/rational-drug/statistics") + chk_resp(r, "用药","17.3","用药统计", 200) + r = GET("/api/v1/rational-drug/audit-log", {"pageNum":1,"pageSize":10}) + chk_page(r, "用药","17.4","审计日志") + +# ============================ +# 模块18: 药品追溯 +# ============================ +def test_drug_trace(): + print(f"\n{'='*50}\n模块18: 药品追溯\n{'='*50}") + r = GET("/drugtrace/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "追溯","18.1","药品追溯") + +# ============================ +# 模块19: EMPI +# ============================ +def test_empi(): + print(f"\n{'='*50}\n模块19: EMPI主索引\n{'='*50}") + r = GET("/api/v1/empi/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "EMPI","19.1","EMPI索引") + +# ============================ +# 模块20: ESB +# ============================ +def test_esb(): + print(f"\n{'='*50}\n模块20: ESB数据集成\n{'='*50}") + r = GET("/esb/message/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "ESB","20.1","ESB消息") + r = GET("/esb/registry/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "ESB","20.2","ESB服务注册") + +# ============================ +# 模块21: CA签名 +# ============================ +def test_ca(): + print(f"\n{'='*50}\n模块21: 电子签名\n{'='*50}") + r = GET("/api/v1/ca-signature/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "CA","21.1","CA签名") + r = GET("/api/v1/ca-signature/statistics") + chk_resp(r, "CA","21.2","CA签名统计", 200) + +# ============================ +# 模块22: 病案管理 +# ============================ +def test_mr(): + print(f"\n{'='*50}\n模块22: 病案管理\n{'='*50}") + r = GET("/api/v1/mr-homepage/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "病案","22.1","病案首页") + +# ============================ +# 模块23: 随访 +# ============================ +def test_followup(): + print(f"\n{'='*50}\n模块23: 随访管理\n{'='*50}") + r = GET("/followup/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "随访","23.1","随访计划") + +# ============================ +# 模块24: 知情同意 +# ============================ +def test_consent(): + print(f"\n{'='*50}\n模块24: 知情同意\n{'='*50}") + r = GET("/informed-consent/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "知情","24.1","知情同意") + +# ============================ +# 模块25: 消毒供应 +# ============================ +def test_cssd(): + print(f"\n{'='*50}\n模块25: 消毒供应\n{'='*50}") + r = GET("/cssd/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "CSSD","25.1","消毒追溯") + +# ============================ +# 模块26: 急诊 +# ============================ +def test_emergency(): + print(f"\n{'='*50}\n模块26: 急诊管理\n{'='*50}") + r = GET("/emergency/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "急诊","26.1","急诊记录") + r = GET("/triage/queue/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "急诊","26.2","分诊排队") + +# ============================ +# 模块27: 医保 +# ============================ +def test_insurance(): + print(f"\n{'='*50}\n模块27: 医保管理\n{'='*50}") + r = GET("/yb-request/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "医保","27.1","医保请求") + +# ============================ +# 模块28: 抗菌药物 +# ============================ +def test_antibiotic(): + print(f"\n{'='*50}\n模块28: 抗菌药物\n{'='*50}") + r = GET("/api/v1/antibiotic/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "抗菌","28.1","抗菌药物") + +# ============================ +# 模块29: DRG分析 +# ============================ +def test_drg(): + print(f"\n{'='*50}\n模块29: DRG分析\n{'='*50}") + r = GET("/drg-analysis/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "DRG","29.1","DRG分析") + r = GET("/mr-drg/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "DRG","29.2","DRG分组") + +# ============================ +# 模块30: 经营分析 +# ============================ +def test_analytics(): + print(f"\n{'='*50}\n模块30: 经营分析\n{'='*50}") + r = GET("/business-analytics/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "经营","30.1","经营分析") + +# ============================ +# 模块31: 系统管理 +# ============================ +def test_system(): + print(f"\n{'='*50}\n模块31: 系统管理\n{'='*50}") + + r = GET("/dict-dictionary/definition/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "系统","31.1","字典定义") + + r = GET("/system/user/list") + data = r.get("data",[]) + ok = isinstance(data, list) and len(data) > 0 + stats.record("系统","31.2","用户列表非空", ok, "" if ok else "用户列表为空") + + r = GET("/system/role/list") + data = r.get("data",[]) + ok = isinstance(data, list) and len(data) > 0 + stats.record("系统","31.3","角色列表非空", ok, "" if ok else "角色列表为空") + + r = GET("/system/menu/list") + data = r.get("data",[]) + ok = isinstance(data, list) and len(data) > 50 + stats.record("系统","31.4","菜单>50条", ok, "" if ok else f"实际={len(data) if isinstance(data,list) else 'N/A'}") + + r = GET("/system/dept/list") + data = r.get("data",[]) + ok = isinstance(data, list) and len(data) > 5 + stats.record("系统","31.5","部门>5个", ok, "" if ok else f"实际={len(data) if isinstance(data,list) else 'N/A'}") + +# ============================ +# 模块32: 药房管理 +# ============================ +def test_pharmacy(): + print(f"\n{'='*50}\n模块32: 药房管理\n{'='*50}") + r = GET("/pharmacy-stock-alert/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "药房","32.1","库存预警") + r = GET("/pharmacy-manage/western-medicine-dispense/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "药房","32.2","西药发药") + r = GET("/pharmacy-manage/return-medicine/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "药房","32.3","退药管理") + +# ============================ +# 模块33: 报表管理 +# ============================ +def test_reports(): + print(f"\n{'='*50}\n模块33: 报表管理\n{'='*50}") + r = GET("/report-manage/register/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "报表","33.1","挂号报表") + r = GET("/report-manage/charge/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "报表","33.2","收费报表") + r = GET("/report-manage/report-statistics/page", {"pageNum":1,"pageSize":10}) + chk_page(r, "报表","33.3","经营统计") + +# ============================ +# 主入口 +# ============================ +if __name__ == "__main__": + print(f"{'='*70}") + print("HealthLink-HIS 三甲医院全流程业务逻辑测试 v2") + print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + print(f"测试环境: {BASE_URL}") + print(f"{'='*70}") + + print("\n>>> 登录系统...") + TOKEN = login() + if not TOKEN: + print("❌ 登录失败!"); sys.exit(1) + print("✅ 登录成功") + + for fn in [test_auth, test_registration, test_doctor_station, test_charge, + test_inpatient, test_nursing, test_inspection, test_radiology, + test_surgery, test_infection, test_quality, test_tcm, + test_consultation, test_pathway, test_critical, test_review, + test_rational_drug, test_drug_trace, test_empi, test_esb, + test_ca, test_mr, test_followup, test_consent, test_cssd, + test_emergency, test_insurance, test_antibiotic, test_drg, + test_analytics, test_system, test_pharmacy, test_reports]: + try: fn() + except Exception as e: + print(f" ❌ 异常: {fn.__name__}: {e}") + stats.record("异常", fn.__name__, "执行异常", False, str(e)) + + ok = stats.summary() + + os.makedirs("MD/test/reports", exist_ok=True) + rp = f"MD/test/reports/biz_test_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md" + with open(rp, "w") as f: + f.write(f"# 业务逻辑测试报告\n\n") + f.write(f"**时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n") + f.write(f"**环境**: {BASE_URL}\n\n") + f.write(f"## 汇总\n\n- 总数: {stats.total}\n- 通过: {stats.passed}\n- 失败: {stats.failed}\n- 通过率: {stats.passed*100/stats.total:.1f}%\n\n" if stats.total else "") + f.write("## 详细\n\n| 模块 | 编号 | 测试项 | 状态 | 说明 |\n|------|------|--------|------|------|\n") + for r in stats.results: + f.write(f"| {r['module']} | {r['case_id']} | {r['name']} | {r['status']} | {r['detail']} |\n") + print(f"\n📄 报告: {rp}") + sys.exit(0 if ok else 1) diff --git a/MD/test/HEALTHLINK_HIS_TEST_PLAN.md b/MD/test/HEALTHLINK_HIS_TEST_PLAN.md new file mode 100644 index 000000000..55c3e533c --- /dev/null +++ b/MD/test/HEALTHLINK_HIS_TEST_PLAN.md @@ -0,0 +1,485 @@ +# HealthLink-HIS 三甲医院全流程测试计划 + +## 1. 测试概述 + +**项目**: HealthLink-HIS 三甲医院信息系统 +**版本**: v2.0 (JDK 25 + Spring Boot 4.0.6 + Vue 3 + Element Plus) +**测试范围**: 门诊、住院、药房、护理、检验、影像、手术、麻醉、院感、质控、中医等全流程 +**测试环境**: 本地开发环境 (localhost:18082) + +--- + +## 2. 测试数据准备 + +### 2.1 基础数据 + +```sql +-- 测试科室 +INSERT INTO sys_dept (dept_name, parent_id, order_num) VALUES +('内科', 0, 1), ('外科', 0, 2), ('妇产科', 0, 3), ('儿科', 0, 4), +('ICU', 0, 5), ('急诊科', 0, 6), ('手术室', 0, 7), ('药房', 0, 8), +('检验科', 0, 9), ('影像科', 0, 10), ('门诊部', 0, 11), ('住院部', 0, 12); + +-- 测试医生 +INSERT INTO sys_user (user_name, nick_name, dept_id, email) VALUES +('zhangsan', '张三', 1, 'zhangsan@hospital.com'), +('lisi', '李四', 2, 'lisi@hospital.com'), +('wangwu', '王五', 3, 'wangwu@hospital.com'), +('zhaoliu', '赵六', 5, 'zhaoliu@hospital.com'); + +-- 测试护士 +INSERT INTO sys_user (user_name, nick_name, dept_id) VALUES +('nurse1', '护士A', 1), +('nurse2', '护士B', 5); + +-- 测试药品 +INSERT INTO drug_info (drug_code, drug_name, drug_spec, drug_category) VALUES +('DRG001', '阿莫西林胶囊', '0.5g*24片', '抗生素'), +('DRG002', '布洛芬缓释胶囊', '0.3g*20粒', '解热镇痛'), +('DRG003', '奥美拉唑肠溶胶囊', '20mg*14粒', '消化系统'), +('DRG004', '氨氯地平片', '5mg*7片', '心血管'), +('DRG005', '头孢曲松注射液', '1g', '抗生素'); +``` + +### 2.2 测试患者数据 + +```sql +-- 门诊患者 +INSERT INTO patient_info (patient_name, id_card, gender, birth_date, phone) VALUES +('患者甲', '450102199001011234', 'M', '1990-01-01', '13800138001'), +('患者乙', '450102198505052345', 'F', '1985-05-05', '13800138002'), +('患者丙', '450102200010103456', 'M', '2000-10-10', '13800138003'), +('患者丁', '450102197512124567', 'F', '1975-12-12', '13800138004'); + +-- 住院患者 +INSERT INTO inpatient_info (patient_id, bed_no, admission_date, diagnosis) VALUES +(1, 'ICU-01', '2026-06-01', '重症肺炎'), +(2, '内-01', '2026-06-03', '高血压3级'), +(3, '外-01', '2026-06-05', '急性阑尾炎'); +``` + +--- + +## 3. 全流程测试用例 + +### 3.1 门诊就诊流程 + +#### 流程图 +``` +患者挂号 → 医生接诊 → 开具处方 → 药房发药 → 收费结算 + ↓ ↓ ↓ ↓ ↓ +[挂号管理] [门诊医生站] [处方管理] [药房管理] [收费管理] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 挂号 | 创建挂号记录 | POST /api/v1/outpatient/registration | 返回挂号单号 | +| 2. 接诊 | 医生接诊患者 | POST /api/v1/outpatient/encounter | 创建就诊记录 | +| 3. 开方 | 开具处方 | POST /api/v1/outpatient/prescription | 返回处方号 | +| 4. 发药 | 药房发药 | POST /api/v1/pharmacy/dispense | 更新库存 | +| 5. 结算 | 收费结算 | POST /api/v1/charge/settle | 生成收费记录 | + +#### 测试数据 +```json +// 1. 挂号 +{ + "patientId": 1, + "doctorId": 1, + "deptId": 1, + "appointTime": "2026-06-07 09:00:00", + "regType": "普通" +} + +// 2. 开方 +{ + "encounterId": 1001, + "patientId": 1, + "doctorId": 1, + "items": [ + {"drugCode": "DRG001", "quantity": 2, "usage": "tid po"}, + {"drugCode": "DRG002", "quantity": 1, "usage": "bid po"} + ] +} +``` + +--- + +### 3.2 住院入院流程 + +#### 流程图 +``` +入院登记 → 护理评估 → 医嘱开具 → 执行医嘱 → 出院结算 + ↓ ↓ ↓ ↓ ↓ +[入院管理] [护理评估] [医嘱管理] [护理执行] [出院管理] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 入院登记 | 创建入院记录 | POST /api/v1/inpatient/admission | 返回住院号 | +| 2. 护理评估 | Braden压疮评估 | POST /nursing-assessment-enhanced/braden/assess | 评估完成 | +| 3. 跌倒评估 | Morse跌倒评估 | POST /nursing-assessment-enhanced/morse/assess | 评估完成 | +| 4. 开医嘱 | 医生开具医嘱 | POST /api/v1/order/submit | 医嘱生效 | +| 5. 执行医嘱 | 护士执行医嘱 | POST /api/v1/order/execute | 执行完成 | +| 6. 出院结算 | 出院结算 | POST /api/v1/inpatient/discharge | 结算完成 | + +#### 测试数据 +```json +// 1. 入院登记 +{ + "patientId": 1, + "deptId": 5, + "bedNo": "ICU-01", + "admissionDate": "2026-06-07", + "diagnosis": "重症肺炎", + "admissionDoctor": "赵六" +} + +// 2. Braden评估 +{ + "patientName": "患者甲", + "encounterId": 1001, + "itemScores": "{\"sensation\":2,\"moisture\":2,\"activity\":1,\"mobility\":2,\"nutrition\":3,\"friction\":2}", + "detail": "压疮高危患者" +} + +// 3. Morse评估 +{ + "patientName": "患者甲", + "encounterId": 1001, + "itemScores": "{\"history\":15,\"diagnosis\":0,\"ambulation\":15,\"iv\":20,\"gait\":0,\"mental\":0}", + "detail": "跌倒高危患者" +} +``` + +--- + +### 3.3 药房管理流程 + +#### 流程图 +``` +采购入库 → 库存管理 → 处方审核 → 发药 → 库存预警 + ↓ ↓ ↓ ↓ ↓ +[采购管理] [库存管理] [合理用药] [发药管理] [库存预警] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 采购入库 | 药品采购 | POST /api/v1/pharmacy/purchase | 库存增加 | +| 2. 库存查询 | 查询库存 | GET /api/v1/pharmacy/stock | 返回库存列表 | +| 3. 处方审核 | 审核处方 | POST /api/v1/rational-drug/audit | 审核完成 | +| 4. 发药 | 药房发药 | POST /api/v1/pharmacy/dispense | 库存减少 | +| 5. 库存预警 | 查询预警 | GET /pharmacystockalert/page | 返回预警列表 | + +--- + +### 3.4 检验管理流程 + +#### 流程图 +``` +开具检验单 → 标本采集 → 标本接收 → 检验执行 → 报告审核 → 结果查看 + ↓ ↓ ↓ ↓ ↓ ↓ +[检验申请] [标本管理] [标本接收] [检验执行] [报告审核] [结果查看] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 开检验单 | 申请检验 | POST /api/v1/inspection/apply | 返回申请单号 | +| 2. 标本采集 | 采集标本 | POST /api/v1/specimen/collect | 标本登记 | +| 3. 标本接收 | 接收标本 | POST /api/v1/specimen/receive | 状态更新 | +| 4. 检验执行 | 录入结果 | POST /api/v1/inspection/result | 结果保存 | +| 5. 报告审核 | 审核报告 | POST /api/v1/inspection/audit | 报告完成 | + +--- + +### 3.5 影像检查流程 + +#### 流程图 +``` +开具检查单 → 预约排队 → 检查执行 → 报告编写 → 结果查看 → 历史对比 + ↓ ↓ ↓ ↓ ↓ ↓ +[检查申请] [预约管理] [检查执行] [报告管理] [结果查看] [影像对比] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 开检查单 | 申请检查 | POST /api/v1/exam/apply | 返回申请单号 | +| 2. 预约检查 | 预约排队 | POST /api/v1/exam/appointment | 预约成功 | +| 3. 检查执行 | 执行检查 | POST /api/v1/exam/execute | 检查完成 | +| 4. 编写报告 | 编写报告 | POST /api/v1/exam/report | 报告保存 | +| 5. 历史对比 | 对比影像 | GET /radiology-comparison/compare | 返回对比数据 | + +--- + +### 3.6 手术管理流程 + +#### 流程图 +``` +手术申请 → 术前讨论 → 手术排班 → 术前准备 → 手术执行 → 术后随访 + ↓ ↓ ↓ ↓ ↓ ↓ +[手术申请] [术前讨论] [手术排班] [术前检查] [手术记录] [术后随访] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 手术申请 | 申请手术 | POST /api/v1/surgery/apply | 申请成功 | +| 2. 术前讨论 | 讨论记录 | POST /api/v1/surgery/discussion | 讨论完成 | +| 3. 手术排班 | 安排手术 | POST /api/v1/surgery/schedule | 排班成功 | +| 4. 术前准备 | 准备检查 | POST /api/v1/surgery/preop-check | 准备完成 | +| 5. 手术记录 | 记录手术 | POST /api/v1/surgery/record | 记录保存 | +| 6. 术后随访 | 随访记录 | POST /api/v1/anesthesia/followup | 随访完成 | + +--- + +### 3.7 麻醉管理流程 + +#### 流程图 +``` +麻醉评估 → 麻醉记录 → 术中监测 → 术后随访 → 麻醉质控 + ↓ ↓ ↓ ↓ ↓ +[麻醉评估] [麻醉记录] [生命体征] [术后随访] [质控统计] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 麻醉评估 | 评估患者 | POST /api/v1/anesthesia/record | 评估完成 | +| 2. 麻醉记录 | 记录麻醉 | POST /api/v1/anesthesia/record | 记录保存 | +| 3. 术中监测 | 记录体征 | POST /api/v1/anesthesia/vital-sign | 体征保存 | +| 4. 术后随访 | 随访记录 | POST /api/v1/anesthesia/followup | 随访完成 | +| 5. 质控统计 | 统计分析 | GET /anesthesia-enhanced/qc/stats | 返回统计 | + +--- + +### 3.8 院感管理流程 + +#### 流程图 +``` +感染监测 → 暴发预警 → 疫情报告 → 干预措施 → 效果评估 + ↓ ↓ ↓ ↓ ↓ +[感染监测] [暴发预警] [疫情报告] [干预措施] [效果评估] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 感染监测 | 目标性监测 | POST /infection/surveillance/add | 监测记录 | +| 2. 暴发预警 | 预警记录 | POST /infection/warning/add | 预警记录 | +| 3. 多重耐药 | 耐药监测 | POST /infection/resistant/add | 耐药记录 | +| 4. 职业暴露 | 暴露报告 | POST /infection/exposure/add | 暴露记录 | +| 5. 手卫生 | 手卫生监测 | POST /infection/hygiene/add | 手卫生记录 | +| 6. 环境监测 | 环境采样 | POST /infection/environment/add | 环境记录 | + +--- + +### 3.9 质量管理流程 + +#### 流程图 +``` +运行质控 → 终末质控 → 缺陷记录 → 整改追踪 → 质量统计 + ↓ ↓ ↓ ↓ ↓ +[运行质控] [终末质控] [缺陷管理] [整改追踪] [质量统计] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 运行质控 | 检查病历 | POST /api/v1/emr-quality/runtime-check/{id} | 检查结果 | +| 2. 终末质控 | 评分 | POST /api/v1/emr-quality/terminal-check/{id} | 评分结果 | +| 3. 缺陷记录 | 记录缺陷 | GET /api/v1/emr-quality/defect/{id} | 缺陷列表 | +| 4. 护理质量 | 质量指标 | GET /nursing-quality/summary | 质量统计 | + +--- + +### 3.10 处方点评流程 + +#### 流程图 +``` +创建计划 → 自动筛查 → 人工点评 → 整改通知 → 统计分析 + ↓ ↓ ↓ ↓ ↓ +[点评计划] [自动筛查] [人工点评] [整改通知] [统计排名] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 创建计划 | 创建点评计划 | POST /api/v1/review/plan | 计划创建 | +| 2. 自动筛查 | 筛选处方 | POST /api/v1/review/auto-screen | 筛选结果 | +| 3. 人工点评 | 点评处方 | POST /api/v1/review/record | 点评完成 | +| 4. 医生排名 | 排名统计 | GET /api/v1/review/ranking | 排名列表 | + +--- + +### 3.11 临床路径管理流程 + +#### 流程图 +``` +路径定义 → 入径管理 → 执行监控 → 变异分析 → 效果评价 + ↓ ↓ ↓ ↓ ↓ +[路径管理] [入径管理] [执行监控] [变异分析] [效果评价] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 路径定义 | 创建路径 | POST /clinical-pathway/add | 路径创建 | +| 2. 入径管理 | 患者入径 | POST /clinical-pathway/enter | 入径完成 | +| 3. 完成路径 | 完成治疗 | PUT /clinical-pathway/complete/{id} | 路径完成 | +| 4. 变异记录 | 记录变异 | PUT /clinical-pathway/vary/{id} | 变异记录 | + +--- + +### 3.12 中医管理流程 + +#### 流程图 +``` +体质辨识 → 辨证论治 → 方剂开具 → 中药处方 → 疗效评价 + ↓ ↓ ↓ ↓ ↓ +[体质辨识] [辨证论治] [方剂管理] [中药处方] [疗效评价] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 体质辨识 | 辨识体质 | POST /api/v1/tcm/constitution | 辨识完成 | +| 2. 查询方剂 | 查询方剂 | GET /api/v1/tcm/prescriptions | 方剂列表 | +| 3. 新增方剂 | 新增方剂 | POST /api/v1/tcm/prescription | 方剂创建 | +| 4. 统计查询 | 统计分析 | GET /api/v1/tcm/statistics | 统计结果 | + +--- + +### 3.13 医嘱闭环管理流程 + +#### 流程图 +``` +医嘱开具 → 药师审核 → 护士执行 → 执行确认 → 闭环完成 + ↓ ↓ ↓ ↓ ↓ +[医嘱管理] [处方审核] [护理执行] [执行确认] [闭环统计] +``` + +#### 测试步骤 + +| 步骤 | 操作 | API接口 | 预期结果 | +|------|------|---------|----------| +| 1. 执行医嘱 | 执行医嘱 | POST /api/v1/order-closed-loop/execute | 执行完成 | +| 2. 完成医嘱 | 完成医嘱 | POST /api/v1/order-closed-loop/complete | 闭环完成 | +| 3. 取消医嘱 | 取消医嘱 | POST /api/v1/order-closed-loop/cancel | 取消完成 | +| 4. 统计查询 | 统计分析 | GET /api/v1/order-closed-loop/statistics | 统计结果 | + +--- + +## 4. 测试执行计划 + +### 4.1 测试顺序 + +| 阶段 | 模块 | 优先级 | 预计耗时 | +|------|------|--------|----------| +| Phase 1 | 基础数据 + 登录认证 | P0 | 30分钟 | +| Phase 2 | 门诊就诊流程 | P0 | 60分钟 | +| Phase 3 | 住院入院流程 | P0 | 60分钟 | +| Phase 4 | 药房管理流程 | P1 | 45分钟 | +| Phase 5 | 检验管理流程 | P1 | 45分钟 | +| Phase 6 | 影像检查流程 | P1 | 45分钟 | +| Phase 7 | 手术麻醉流程 | P1 | 60分钟 | +| Phase 8 | 院感管理流程 | P2 | 45分钟 | +| Phase 9 | 质量管理流程 | P2 | 45分钟 | +| Phase 10 | 处方点评流程 | P2 | 30分钟 | +| Phase 11 | 临床路径流程 | P2 | 30分钟 | +| Phase 12 | 中医管理流程 | P2 | 30分钟 | +| Phase 13 | 医嘱闭环流程 | P1 | 30分钟 | + +### 4.2 测试验证点 + +每个测试用例需要验证: +1. **接口返回码**: 确认API返回200 +2. **数据完整性**: 确认数据正确保存 +3. **业务逻辑**: 确认流程正确执行 +4. **异常处理**: 确认异常情况正确处理 +5. **权限控制**: 确认权限正确验证 + +--- + +## 5. 测试报告模板 + +```markdown +### 测试报告 + +**测试日期**: 2026-06-07 +**测试人员**: AI Agent +**测试环境**: 本地开发环境 + +#### 测试结果汇总 + +| 模块 | 测试用例数 | 通过数 | 失败数 | 通过率 | +|------|-----------|--------|--------|--------| +| 门诊就诊 | 5 | 5 | 0 | 100% | +| 住院入院 | 6 | 6 | 0 | 100% | +| 药房管理 | 5 | 5 | 0 | 100% | +| 检验管理 | 5 | 5 | 0 | 100% | +| 影像检查 | 6 | 6 | 0 | 100% | +| 手术麻醉 | 6 | 6 | 0 | 100% | +| 院感管理 | 6 | 6 | 0 | 100% | +| 质量管理 | 4 | 4 | 0 | 100% | +| 处方点评 | 4 | 4 | 0 | 100% | +| 临床路径 | 4 | 4 | 0 | 100% | +| 中医管理 | 4 | 4 | 0 | 100% | +| 医嘱闭环 | 4 | 4 | 0 | 100% | +| **总计** | **59** | **59** | **0** | **100%** | + +#### 发现问题 + +| 序号 | 问题描述 | 严重程度 | 状态 | +|------|----------|----------|------| +| 1 | 无 | - | - | + +#### 结论 + +所有测试用例全部通过,系统功能完整,可以交付使用。 +``` + +--- + +## 6. 附录 + +### 6.1 API接口清单 + +| 模块 | 接口前缀 | 方法 | +|------|----------|------| +| 门诊管理 | /api/v1/outpatient | GET/POST | +| 住院管理 | /api/v1/inpatient | GET/POST | +| 药房管理 | /api/v1/pharmacy | GET/POST | +| 检验管理 | /api/v1/inspection | GET/POST | +| 影像管理 | /api/v1/exam | GET/POST | +| 手术管理 | /api/v1/surgery | GET/POST | +| 麻醉管理 | /api/v1/anesthesia | GET/POST | +| 护理管理 | /nursing-assessment-enhanced | GET/POST | +| 院感管理 | /infection | GET/POST | +| 质量管理 | /api/v1/emr-quality | GET/POST | +| 处方点评 | /api/v1/review | GET/POST | +| 临床路径 | /clinical-pathway | GET/POST | +| 中医管理 | /api/v1/tcm | GET/POST | +| 医嘱闭环 | /api/v1/order-closed-loop | GET/POST | + +### 6.2 测试数据文件 + +- `test_data.sql` - SQL测试数据 +- `test_api.json` - API测试数据 +- `test_report.md` - 测试报告 + diff --git a/MD/test/reports/biz_test_20260607_215348.md b/MD/test/reports/biz_test_20260607_215348.md new file mode 100644 index 000000000..26810f570 --- /dev/null +++ b/MD/test/reports/biz_test_20260607_215348.md @@ -0,0 +1,128 @@ +# 业务逻辑测试报告 + +**时间**: 2026-06-07 21:53:48 + +**环境**: http://localhost:18082/healthlink-his + +## 汇总 + +- 总数: 107 +- 通过: 34 +- 失败: 73 +- 通过率: 31.8% + +## 详细 + +| 模块 | 编号 | 测试项 | 状态 | 说明 | +|------|------|--------|------|------| +| 认证 | 1.1 | 登录成功-返回token | ✅ PASS | | +| 认证 | 1.2 | 错误密码-应失败 | ✅ PASS | | +| 认证 | 1.3 | 获取用户信息 | ✅ PASS | | +| 认证 | 1.4 | 获取路由菜单 | ✅ PASS | | +| 挂号 | 2.1 | 挂号初始化 | ✅ PASS | | +| 挂号 | 2.2 | 当日挂号列表 | ✅ PASS | | +| 挂号 | 2.3 | 患者元数据查询 | ✅ PASS | | +| 挂号 | 2.4 | 全部医生列表 | ✅ PASS | | +| 医生站 | 3.1 | 医生站初始化 | ✅ PASS | | +| 医生站 | 3.2 | 患者信息查询 | ✅ PASS | | +| 医生站 | 3.3 | 接诊统计 | ❌ FAIL | code=500, msg=Required request parameter 'startTime' for method parameter type String is not present | +| 医生站 | 3.4 | 医嘱基础信息 | ✅ PASS | | +| 医生站 | 3.5 | 诊断初始化 | ✅ PASS | | +| 医生站 | 3.6 | 诊断定义分类 | ❌ FAIL | code=500, msg=Required request parameter 'patientId' for method parameter type Long is not present | +| 医生站 | 3.7 | 检查申请初始化 | ❌ FAIL | code=500, msg=No static resource doctor-station/inspection/init for request '/healthlink-his/doctor-station/inspection/init'. | +| 收费 | 4.1 | 门诊收费初始化 | ✅ PASS | | +| 收费 | 4.2 | 收费患者列表 | ✅ PASS | | +| 收费 | 4.3 | 退费初始化 | ✅ PASS | | +| 收费 | 4.4 | 退费患者列表 | ✅ PASS | | +| 收费 | 4.5 | 住院收费初始化 | ✅ PASS | | +| 收费 | 4.6 | 住院收费患者列表 | ✅ PASS | | +| 收费 | 4.7 | 定价患者信息 | ✅ PASS | | +| 住院 | 5.1 | 患者主页初始化 | ✅ PASS | | +| 住院 | 5.2 | 空床查询 | ✅ PASS | | +| 住院 | 5.3 | 科室统计 | ✅ PASS | | +| 住院 | 5.4 | 押金初始化 | ✅ PASS | | +| 住院 | 5.5 | 入院登记-病区列表 | ❌ FAIL | code=500, msg=No static resource inhospitalmanage/register/ward-list for request '/healthlink-his/inhospitalmanage/register/ward-list' | +| 住院 | 5.6 | 入院登记-床位数 | ❌ FAIL | code=500, msg=No static resource inhospitalmanage/register/beds-num for request '/healthlink-his/inhospitalmanage/register/beds-num'. | +| 住院 | 5.7 | 入院登记-患者信息 | ❌ FAIL | code=500, msg=No static resource inhospitalmanage/register/patient-info for request '/healthlink-his/inhospitalmanage/register/patient | +| 护理 | 6.1 | 护理评估列表 | ❌ FAIL | rows类型异常: | +| 护理 | 6.2 | 护理评估统计 | ✅ PASS | | +| 护理 | 6.3 | Braden评估-成功 | ✅ PASS | | +| 护理 | 6.4 | Morse评估-成功 | ✅ PASS | | +| 护理 | 6.5 | 体征记录查询 | ✅ PASS | | +| 护理 | 6.6 | 体征图表 | ❌ FAIL | rows类型异常: | +| 护理 | 6.7 | 护理执行列表 | ❌ FAIL | code=500, msg=No static resource nurse-station/advice-process/page for request '/healthlink-his/nurse-station/advice-process/page'. | +| 护理 | 6.8 | 护理质量指标 | ❌ FAIL | rows类型异常: | +| 检验 | 7.1 | 标本采集 | ❌ FAIL | code=500, msg=No static resource inspection/collection/page for request '/healthlink-his/inspection/collection/page'. | +| 检验 | 7.2 | 检验观察 | ❌ FAIL | code=500, msg=No static resource inspection/observation/page for request '/healthlink-his/inspection/observation/page'. | +| 检验 | 7.3 | 标本定义 | ❌ FAIL | code=500, msg=No static resource inspection/specimen/page for request '/healthlink-his/inspection/specimen/page'. | +| 检验 | 7.4 | LIS配置 | ❌ FAIL | code=500, msg=No static resource inspection/lisConfig/page for request '/healthlink-his/inspection/lisConfig/page'. | +| 检验 | 7.5 | 仪器管理 | ❌ FAIL | code=500, msg=No static resource inspection/instrument/page for request '/healthlink-his/inspection/instrument/page'. | +| 检验 | 7.6 | 检验结果 | ❌ FAIL | code=500, msg=请求参数类型不匹配,参数[id]要求类型为:'java.lang.Long',但输入值为:'page' | +| 检验 | 7.7 | 参考范围 | ❌ FAIL | rows类型异常: | +| 检验 | 7.8 | 检查申请 | ❌ FAIL | code=500, msg=未找到申请单信息 | +| 影像 | 8.1 | 影像列表 | ❌ FAIL | code=500, msg=No static resource radiology-image/page for request '/healthlink-his/radiology-image/page'. | +| 影像 | 8.2 | 影像增强 | ❌ FAIL | code=500, msg=No static resource radiology-enhanced/page for request '/healthlink-his/radiology-enhanced/page'. | +| 影像 | 8.3 | 影像对比 | ❌ FAIL | code=500, msg=No static resource radiology-comparison/page for request '/healthlink-his/radiology-comparison/page'. | +| 影像 | 8.4 | 3D重建 | ❌ FAIL | code=500, msg=No static resource reconstruction/page for request '/healthlink-his/reconstruction/page'. | +| 手术 | 9.1 | 手术列表 | ❌ FAIL | code=500, msg=No static resource clinical-manage/surgery/page for request '/healthlink-his/clinical-manage/surgery/page'. | +| 手术 | 9.2 | 手术排程 | ❌ FAIL | rows类型异常: | +| 手术 | 9.3 | 术前讨论 | ❌ FAIL | code=500, msg= +### Error querying database. Cause: org.postgresql.util.PSQLException: ERROR: column "delete_flag" does not exist + Po | +| 手术 | 9.4 | 安全核查 | ❌ FAIL | rows类型异常: | +| 麻醉 | 9.5 | 麻醉记录 | ❌ FAIL | code=500, msg=No static resource api/v1/anesthesia/page for request '/healthlink-his/api/v1/anesthesia/page'. | +| 麻醉 | 9.6 | 麻醉增强 | ❌ FAIL | code=500, msg=No static resource anesthesia-enhanced/page for request '/healthlink-his/anesthesia-enhanced/page'. | +| 院感 | 10.1 | 院感监测 | ❌ FAIL | rows类型异常: | +| 院感 | 10.2 | 院感预警 | ❌ FAIL | code=500, msg=No static resource infection-enhanced/warning/page for request '/healthlink-his/infection-enhanced/warning/page'. | +| 院感 | 10.3 | 耐药监测 | ❌ FAIL | code=500, msg=No static resource infection-enhanced/resistance/page for request '/healthlink-his/infection-enhanced/resistance/page'. | +| 院感 | 10.4 | 职业暴露 | ❌ FAIL | code=500, msg=No static resource infection-enhanced/exposure/page for request '/healthlink-his/infection-enhanced/exposure/page'. | +| 院感 | 10.5 | 手卫生 | ❌ FAIL | rows类型异常: | +| 院感 | 10.6 | 环境监测 | ❌ FAIL | code=500, msg=No static resource infection-enhanced/environment/page for request '/healthlink-his/infection-enhanced/environment/page' | +| 质控 | 11.1 | 运行质控 | ❌ FAIL | code=500, msg=No static resource quality-enhanced/runtime/page for request '/healthlink-his/quality-enhanced/runtime/page'. | +| 质控 | 11.2 | 终末质控 | ❌ FAIL | code=500, msg=No static resource api/v1/emr-quality/page for request '/healthlink-his/api/v1/emr-quality/page'. | +| 质控 | 11.3 | 质量统计 | ❌ FAIL | code=500, msg=No static resource quality-enhanced/statistics/page for request '/healthlink-his/quality-enhanced/statistics/page'. | +| 中医 | 12.1 | 中医体质 | ❌ FAIL | code=500, msg=No static resource api/v1/tcm/constitution/page for request '/healthlink-his/api/v1/tcm/constitution/page'. | +| 中医 | 12.2 | 方剂列表>=3个 | ✅ PASS | | +| 中医 | 12.3 | 中医统计 | ✅ PASS | | +| 会诊 | 13.1 | 会诊记录 | ❌ FAIL | code=500, msg=No static resource consultation/page for request '/healthlink-his/consultation/page'. | +| 会诊 | 13.2 | 会诊反馈 | ❌ FAIL | code=500, msg=No static resource cross-module/consult-feedback/page for request '/healthlink-his/cross-module/consult-feedback/page'. | +| 会诊 | 13.3 | 会诊超时 | ❌ FAIL | code=500, msg=No static resource cross-module/consulttimeout/page for request '/healthlink-his/cross-module/consulttimeout/page'. | +| 路径 | 14.1 | 临床路径>=2条 | ❌ FAIL | 实际=5 | +| 危急值 | 15.1 | 危急值列表 | ❌ FAIL | code=500, msg=No static resource api/v1/critical-value/page for request '/healthlink-his/api/v1/critical-value/page'. | +| 点评 | 16.1 | 点评计划 | ❌ FAIL | rows类型异常: | +| 点评 | 16.2 | 点评记录 | ❌ FAIL | rows类型异常: | +| 点评 | 16.3 | 点评统计 | ✅ PASS | | +| 用药 | 17.1 | 合理用药 | ❌ FAIL | code=500, msg=No static resource api/v1/rational-drug/page for request '/healthlink-his/api/v1/rational-drug/page'. | +| 用药 | 17.2 | 相互作用 | ❌ FAIL | code=500, msg=No static resource api/v1/rational-drug/interaction/page for request '/healthlink-his/api/v1/rational-drug/interaction/p | +| 用药 | 17.3 | 用药统计 | ✅ PASS | | +| 用药 | 17.4 | 审计日志 | ❌ FAIL | code=500, msg=No static resource api/v1/rational-drug/audit-log for request '/healthlink-his/api/v1/rational-drug/audit-log'. | +| 追溯 | 18.1 | 药品追溯 | ❌ FAIL | code=500, msg=No static resource drugtrace/page for request '/healthlink-his/drugtrace/page'. | +| EMPI | 19.1 | EMPI索引 | ❌ FAIL | code=500, msg=No static resource api/v1/empi/page for request '/healthlink-his/api/v1/empi/page'. | +| ESB | 20.1 | ESB消息 | ❌ FAIL | rows类型异常: | +| ESB | 20.2 | ESB服务注册 | ❌ FAIL | rows类型异常: | +| CA | 21.1 | CA签名 | ❌ FAIL | code=500, msg=No static resource api/v1/ca-signature/page for request '/healthlink-his/api/v1/ca-signature/page'. | +| CA | 21.2 | CA签名统计 | ✅ PASS | | +| 病案 | 22.1 | 病案首页 | ❌ FAIL | code=500, msg=请求参数类型不匹配,参数[id]要求类型为:'java.lang.Long',但输入值为:'page' | +| 随访 | 23.1 | 随访计划 | ❌ FAIL | code=500, msg=No static resource followup/page for request '/healthlink-his/followup/page'. | +| 知情 | 24.1 | 知情同意 | ❌ FAIL | rows类型异常: | +| CSSD | 25.1 | 消毒追溯 | ❌ FAIL | code=500, msg=No static resource cssd/page for request '/healthlink-his/cssd/page'. | +| 急诊 | 26.1 | 急诊记录 | ❌ FAIL | code=500, msg=No static resource emergency/page for request '/healthlink-his/emergency/page'. | +| 急诊 | 26.2 | 分诊排队 | ❌ FAIL | code=500, msg=No static resource index.html for request '/healthlink-his/index.html'. | +| 医保 | 27.1 | 医保请求 | ❌ FAIL | code=500, msg=No static resource yb-request/page for request '/healthlink-his/yb-request/page'. | +| 抗菌 | 28.1 | 抗菌药物 | ❌ FAIL | code=500, msg=No static resource api/v1/antibiotic/page for request '/healthlink-his/api/v1/antibiotic/page'. | +| DRG | 29.1 | DRG分析 | ❌ FAIL | code=500, msg=No static resource drg-analysis/page for request '/healthlink-his/drg-analysis/page'. | +| DRG | 29.2 | DRG分组 | ❌ FAIL | code=500, msg= +### Error querying database. Cause: org.postgresql.util.PSQLException: ERROR: column "create_by" does not exist + Posi | +| 经营 | 30.1 | 经营分析 | ❌ FAIL | rows类型异常: | +| 系统 | 31.1 | 字典定义 | ❌ FAIL | code=500, msg=No static resource dict-dictionary/definition/page for request '/healthlink-his/dict-dictionary/definition/page'. | +| 系统 | 31.2 | 用户列表非空 | ❌ FAIL | 用户列表为空 | +| 系统 | 31.3 | 角色列表非空 | ❌ FAIL | 角色列表为空 | +| 系统 | 31.4 | 菜单>50条 | ✅ PASS | | +| 系统 | 31.5 | 部门>5个 | ✅ PASS | | +| 药房 | 32.1 | 库存预警 | ❌ FAIL | rows类型异常: | +| 药房 | 32.2 | 西药发药 | ❌ FAIL | code=500, msg=No static resource pharmacy-manage/western-medicine-dispense/page for request '/healthlink-his/pharmacy-manage/western-m | +| 药房 | 32.3 | 退药管理 | ❌ FAIL | code=500, msg=No static resource pharmacy-manage/return-medicine/page for request '/healthlink-his/pharmacy-manage/return-medicine/pag | +| 报表 | 33.1 | 挂号报表 | ❌ FAIL | code=500, msg=No static resource report-manage/register/page for request '/healthlink-his/report-manage/register/page'. | +| 报表 | 33.2 | 收费报表 | ❌ FAIL | code=500, msg=No static resource report-manage/charge/page for request '/healthlink-his/report-manage/charge/page'. | +| 报表 | 33.3 | 经营统计 | ❌ FAIL | code=500, msg=No static resource report-manage/report-statistics/page for request '/healthlink-his/report-manage/report-statistics/pag | diff --git a/MD/test/reports/business_logic_report_20260607_215100.md b/MD/test/reports/business_logic_report_20260607_215100.md new file mode 100644 index 000000000..78423581d --- /dev/null +++ b/MD/test/reports/business_logic_report_20260607_215100.md @@ -0,0 +1,148 @@ +# HealthLink-HIS 业务逻辑测试报告 + +**测试时间**: 2026-06-07 21:51:00 + +**测试环境**: http://localhost:18082/healthlink-his + +## 测试汇总 + +- 总测试数: 111 +- 通过数: 21 +- 失败数: 90 +- 通过率: 18.9% + +## 详细结果 + +| 模块 | 编号 | 测试项 | 状态 | 说明 | +|------|------|--------|------|------| +| 认证 | 1.1 | 登录成功验证 | ❌ FAIL | 响应缺少字段: permissions | +| 认证 | 1.2 | 错误密码应返回失败 | ✅ PASS | | +| 认证 | 1.3 | 获取用户信息 | ✅ PASS | | +| 认证 | 1.4 | 获取路由菜单 | ✅ PASS | | +| 认证 | 1.5 | 获取验证码 | ✅ PASS | | +| 挂号 | 2.1 | 挂号初始化-返回优先级选项 | ❌ FAIL | 响应缺少字段: priorityLevelOptionOptions | +| 挂号 | 2.2 | 挂号列表分页查询 | ❌ FAIL | code=500, msg=No static resource charge-manage/register/page for request '/healthlink-his/charge-manage/register/page'. | +| 挂号 | 2.3 | 查询患者-搜索'测试' | ❌ FAIL | 预期code=200, 实际code=500, msg=No static resource charge-manage/register/patient for request '/healthlink-his/charge-manage/register/patient'. | +| 挂号 | 2.4 | 查询不存在的患者 | ❌ FAIL | 预期code=200, 实际code=500, msg=No static resource charge-manage/register/patient for request '/healthlink-his/charge-manage/register/patient'. | +| 医生站 | 3.1 | 待诊患者列表 | ❌ FAIL | 预期code=200, 实际code=500, msg=No static resource doctor-station/main/patient-list for request '/healthlink-his/doctor-station/main/patient-list'. | +| 医生站 | 3.2 | 医嘱列表分页查询 | ❌ FAIL | code=500, msg=No static resource doctor-station/advice/page for request '/healthlink-his/doctor-station/advice/page'. | +| 医生站 | 3.3 | 诊断列表分页查询 | ❌ FAIL | code=500, msg=No static resource doctor-station/diagnosis/page for request '/healthlink-his/doctor-station/diagnosis/page'. | +| 医生站 | 3.4 | 检查申请列表 | ❌ FAIL | code=500, msg=No static resource doctor-station/inspection/page for request '/healthlink-his/doctor-station/inspection/page'. | +| 收费 | 4.1 | 收费初始化 | ✅ PASS | | +| 收费 | 4.2 | 收费记录分页查询 | ❌ FAIL | code=500, msg=No static resource charge-manage/charge/page for request '/healthlink-his/charge-manage/charge/page'. | +| 收费 | 4.3 | 退费记录分页查询 | ❌ FAIL | code=500, msg=No static resource charge-manage/refund/page for request '/healthlink-his/charge-manage/refund/page'. | +| 收费 | 4.4 | 收费定价列表 | ❌ FAIL | code=500, msg=No static resource charge-manage/pricing/page for request '/healthlink-his/charge-manage/pricing/page'. | +| 住院 | 5.1 | 入院登记列表 | ❌ FAIL | code=500, msg=No static resource inhospitalmanage/register/page for request '/healthlink-his/inhospitalmanage/register/page'. | +| 住院 | 5.2 | 患者主页初始化 | ✅ PASS | | +| 住院 | 5.3 | 空床查询 | ✅ PASS | | +| 住院 | 5.4 | 押金管理初始化 | ✅ PASS | | +| 住院 | 5.5 | 押金记录分页查询 | ❌ FAIL | code=500, msg= +### Error querying database. Cause: org.postgresql.util.PSQLException: ERROR: column t4.pay_enum does not exist + Hint: Perhaps you meant to reference the column "t6.pay_enum". + Position: 275 +### The error may exist in URL [jar:nested:/root/.openclaw/workspace/his-repo/healthlink-his-server/healthlink-his-application/target/healthlink-his-application.jar/!BOOT-INF/classes/!/mapper/inpatientmanage/DepositMapper.xml] +### The error may involve com.healthlink.his.web.inpatientmanage.mapper.DepositMapper.getPage-Inline +### The error occurred while setting parameters +### SQL: SELECT COUNT(*) AS total FROM (SELECT T1.id AS patient_id, T1.name, T1.gender_enum, T1.birth_date, T3.location_id AS bed_location_id, T1.organization_id, COALESCE(SUM_TOTAL.total_price, 0) AS total_price, COALESCE(SUM_DEPOSIT.deposit, 0) AS deposit, T4.balance_amount, CASE T4.pay_enum WHEN '220100' THEN '微信' WHEN '220200' THEN '支付宝' WHEN '220300' THEN '银联' WHEN '220400' THEN '现金' ELSE '其他' END AS pay_way, T5.payment_enum, T5.tendered_amount, T7.bus_no, T7.status_enum, T6.after_balance, T6.pay_trans_date AS pay_time, T5.enterer_id FROM adm_patient AS T1 INNER JOIN adm_encounter AS T2 ON T2.patient_id = T1.id AND T2.class_enum = ? LEFT JOIN adm_encounter_location AS T3 ON T3.encounter_id = T2.id AND T3.form_enum = ? AND T3.delete_flag = '0' LEFT JOIN adm_account AS T4 ON T4.patient_id = T1.id AND T4.encounter_id = T2.id AND T4.delete_flag = '0' LEFT JOIN fin_payment_reconciliation AS T5 ON T5.patient_id = T1.id AND T5.encounter_id = T2.id AND T5.delete_flag = '0' LEFT JOIN fin_payment_rec_detail AS T6 ON T6.reconciliation_id = T5.id AND T6.delete_flag = '0' LEFT JOIN adm_invoice AS T7 ON T7.reconciliation_id = T6.reconciliation_id AND T7.patient_id = T1.id AND T7.delete_flag = '0' LEFT JOIN (SELECT patient_id, SUM(tendered_amount) AS total_price FROM fin_payment_reconciliation WHERE kind_enum = 2 GROUP BY patient_id) AS SUM_TOTAL ON SUM_TOTAL.patient_id = T1.id LEFT JOIN (SELECT patient_id, SUM(tendered_amount) AS deposit FROM fin_payment_reconciliation WHERE kind_enum = 1 GROUP BY patient_id) AS SUM_DEPOSIT ON SUM_DEPOSIT.patient_id = T1.id WHERE T1.delete_flag = '0' ORDER BY T6.pay_trans_date DESC) AS T8 WHERE (tenant_id = ?) +### Cause: org.postgresql.util.PSQLException: ERROR: column t4.pay_enum does not exist + Hint: Perhaps you meant to reference the column "t6.pay_enum". + Position: 275 +; bad SQL grammar [] | +| 住院 | 5.6 | 住院收费记录 | ❌ FAIL | code=500, msg=No static resource charge-manage/inpatient-charge/page for request '/healthlink-his/charge-manage/inpatient-charge/page'. | +| 护理 | 6.1 | 护理评估列表 | ❌ FAIL | rows不是数组类型: | +| 护理 | 6.2 | 护理评估统计 | ✅ PASS | | +| 护理 | 6.3 | Braden压疮评估-分数计算正确 | ✅ PASS | | +| 护理 | 6.4 | Morse跌倒评估-分数计算正确 | ✅ PASS | | +| 护理 | 6.5 | 护理记录患者列表 | ❌ FAIL | rows不是数组类型: | +| 护理 | 6.6 | 体征记录查询 | ✅ PASS | | +| 护理 | 6.7 | 体征图表分页查询 | ❌ FAIL | rows不是数组类型: | +| 护理 | 6.8 | 护理执行列表 | ❌ FAIL | code=500, msg=No static resource nurse-station/advice-process/page for request '/healthlink-his/nurse-station/advice-process/page'. | +| 护理 | 6.9 | 交接班记录查询 | ❌ FAIL | code=500, msg=No static resource nursing-handoff/page for request '/healthlink-his/nursing-handoff/page'. | +| 护理 | 6.10 | 护理质量指标查询 | ❌ FAIL | rows不是数组类型: | +| 检验 | 7.1 | 标本采集列表 | ❌ FAIL | code=500, msg=No static resource inspection/collection/page for request '/healthlink-his/inspection/collection/page'. | +| 检验 | 7.2 | 检验观察定义列表 | ❌ FAIL | code=500, msg=No static resource inspection/observation/page for request '/healthlink-his/inspection/observation/page'. | +| 检验 | 7.3 | 标本定义列表 | ❌ FAIL | code=500, msg=No static resource inspection/specimen/page for request '/healthlink-his/inspection/specimen/page'. | +| 检验 | 7.4 | LIS配置列表 | ❌ FAIL | code=500, msg=No static resource inspection/lisConfig/page for request '/healthlink-his/inspection/lisConfig/page'. | +| 检验 | 7.5 | 仪器管理列表 | ❌ FAIL | code=500, msg=No static resource inspection/instrument/page for request '/healthlink-his/inspection/instrument/page'. | +| 检验 | 7.6 | 检验结果列表 | ❌ FAIL | code=500, msg=请求参数类型不匹配,参数[id]要求类型为:'java.lang.Long',但输入值为:'page' | +| 检验 | 7.7 | 参考范围列表 | ❌ FAIL | rows不是数组类型: | +| 检验 | 7.8 | 检查申请列表 | ❌ FAIL | code=500, msg=No static resource index.html for request '/healthlink-his/index.html'. | +| 影像 | 8.1 | 影像列表查询 | ❌ FAIL | code=500, msg=No static resource index.html for request '/healthlink-his/index.html'. | +| 影像 | 8.2 | 影像增强列表 | ❌ FAIL | code=500, msg=No static resource index.html for request '/healthlink-his/index.html'. | +| 影像 | 8.3 | 影像对比列表 | ❌ FAIL | code=500, msg=No static resource index.html for request '/healthlink-his/index.html'. | +| 影像 | 8.4 | 3D重建列表 | ❌ FAIL | code=500, msg=No static resource reconstruction/3d/page for request '/healthlink-his/reconstruction/3d/page'. | +| 手术 | 9.1 | 手术列表查询 | ❌ FAIL | code=500, msg=No static resource clinical-manage/surgery/page for request '/healthlink-his/clinical-manage/surgery/page'. | +| 手术 | 9.2 | 手术排程列表 | ❌ FAIL | rows不是数组类型: | +| 手术 | 9.3 | 术前讨论列表 | ❌ FAIL | code=500, msg=No static resource preopmanage/discussion/page for request '/healthlink-his/preopmanage/discussion/page'. | +| 手术 | 9.4 | 手术安全核查列表 | ❌ FAIL | rows不是数组类型: | +| 手术 | 9.5 | 麻醉记录列表 | ❌ FAIL | code=500, msg=No static resource api/v1/anesthesia/page for request '/healthlink-his/api/v1/anesthesia/page'. | +| 手术 | 9.6 | 麻醉增强列表 | ❌ FAIL | code=500, msg=No static resource anesthesia-enhanced/page for request '/healthlink-his/anesthesia-enhanced/page'. | +| 手术 | 9.7 | 麻醉质控列表 | ❌ FAIL | code=500, msg=No static resource anesthesia-quality-control/page for request '/healthlink-his/anesthesia-quality-control/page'. | +| 院感 | 10.1 | 院感监测 | ❌ FAIL | rows不是数组类型: | +| 院感 | 10.2 | 院感预警 | ❌ FAIL | code=500, msg=No static resource infection-enhanced/warning/page for request '/healthlink-his/infection-enhanced/warning/page'. | +| 院感 | 10.3 | 耐药监测 | ❌ FAIL | code=500, msg=No static resource infection-enhanced/resistance/page for request '/healthlink-his/infection-enhanced/resistance/page'. | +| 院感 | 10.4 | 职业暴露 | ❌ FAIL | code=500, msg=No static resource infection-enhanced/exposure/page for request '/healthlink-his/infection-enhanced/exposure/page'. | +| 院感 | 10.5 | 手卫生 | ❌ FAIL | rows不是数组类型: | +| 院感 | 10.6 | 环境监测 | ❌ FAIL | code=500, msg=No static resource infection-enhanced/environment/page for request '/healthlink-his/infection-enhanced/environment/page'. | +| 质控 | 11.1 | 运行质控列表 | ❌ FAIL | code=500, msg=No static resource quality-enhanced/runtime/page for request '/healthlink-his/quality-enhanced/runtime/page'. | +| 质控 | 11.2 | 终末质控列表 | ❌ FAIL | code=500, msg=No static resource api/v1/emr-quality/page for request '/healthlink-his/api/v1/emr-quality/page'. | +| 质控 | 11.3 | 质量统计列表 | ❌ FAIL | code=500, msg=No static resource quality-enhanced/statistics/page for request '/healthlink-his/quality-enhanced/statistics/page'. | +| 中医 | 12.1 | 中医体质列表 | ❌ FAIL | code=500, msg=No static resource api/v1/tcm/constitution/page for request '/healthlink-his/api/v1/tcm/constitution/page'. | +| 中医 | 12.2 | 中医方剂列表-至少3个方剂 | ✅ PASS | | +| 中医 | 12.3 | 中医统计查询 | ✅ PASS | | +| 会诊 | 13.1 | 会诊记录列表 | ❌ FAIL | code=500, msg=No static resource consultation/page for request '/healthlink-his/consultation/page'. | +| 会诊 | 13.2 | 会诊反馈列表 | ❌ FAIL | code=500, msg=No static resource cross-module/consult-feedback/page for request '/healthlink-his/cross-module/consult-feedback/page'. | +| 会诊 | 13.3 | 会诊超时列表 | ❌ FAIL | code=500, msg=No static resource cross-module/consulttimeout/page for request '/healthlink-his/cross-module/consulttimeout/page'. | +| 路径 | 14.1 | 临床路径列表-至少3条路径 | ✅ PASS | | +| 危急值 | 15.1 | 危急值列表查询 | ✅ PASS | | +| 点评 | 16.1 | 点评计划列表 | ❌ FAIL | rows不是数组类型: | +| 点评 | 16.2 | 点评记录列表 | ❌ FAIL | rows不是数组类型: | +| 点评 | 16.3 | 点评统计查询 | ✅ PASS | | +| 用药 | 17.1 | 合理用药列表 | ❌ FAIL | code=500, msg=No static resource api/v1/rational-drug/page for request '/healthlink-his/api/v1/rational-drug/page'. | +| 用药 | 17.2 | 相互作用列表 | ❌ FAIL | code=500, msg=No static resource api/v1/rational-drug/interaction/page for request '/healthlink-his/api/v1/rational-drug/interaction/page'. | +| 用药 | 17.3 | 用药统计查询 | ✅ PASS | | +| 用药 | 17.4 | 审计日志列表 | ❌ FAIL | code=500, msg=No static resource api/v1/rational-drug/audit-log for request '/healthlink-his/api/v1/rational-drug/audit-log'. | +| 追溯 | 18.1 | 药品追溯列表 | ❌ FAIL | code=500, msg=No static resource drugtrace/page for request '/healthlink-his/drugtrace/page'. | +| EMPI | 19.1 | EMPI索引列表 | ❌ FAIL | code=500, msg=No static resource api/v1/empi/page for request '/healthlink-his/api/v1/empi/page'. | +| ESB | 20.1 | ESB消息列表 | ❌ FAIL | code=500, msg=No static resource esbmanage/message/page for request '/healthlink-his/esbmanage/message/page'. | +| ESB | 20.2 | ESB服务注册列表 | ❌ FAIL | code=500, msg=No static resource esbmanage/registry/page for request '/healthlink-his/esbmanage/registry/page'. | +| CA | 21.1 | CA签名列表 | ❌ FAIL | code=500, msg=No static resource api/v1/ca-signature/page for request '/healthlink-his/api/v1/ca-signature/page'. | +| CA | 21.2 | CA签名统计 | ✅ PASS | | +| 病案 | 22.1 | 病案首页列表 | ❌ FAIL | code=500, msg=请求参数类型不匹配,参数[id]要求类型为:'java.lang.Long',但输入值为:'page' | +| 病案 | 22.2 | 病案质量检查 | ❌ FAIL | code=500, msg=请求参数类型不匹配,参数[homepageId]要求类型为:'java.lang.Long',但输入值为:'page' | +| 随访 | 23.1 | 随访计划列表 | ❌ FAIL | rows不是数组类型: | +| 知情 | 24.1 | 知情同意列表 | ❌ FAIL | code=500, msg=No static resource api/v1/informed-consent/page for request '/healthlink-his/api/v1/informed-consent/page'. | +| CSSD | 25.1 | 消毒追溯列表 | ❌ FAIL | code=500, msg=No static resource cssd/trace/page for request '/healthlink-his/cssd/trace/page'. | +| 急诊 | 26.1 | 急诊记录列表 | ❌ FAIL | code=500, msg=No static resource emergency/page for request '/healthlink-his/emergency/page'. | +| 急诊 | 26.2 | 分诊排队列表 | ❌ FAIL | code=500, msg=No static resource index.html for request '/healthlink-his/index.html'. | +| 医保 | 27.1 | 医保目录列表 | ❌ FAIL | code=500, msg=No static resource ybmanage/catalog/page for request '/healthlink-his/ybmanage/catalog/page'. | +| 抗菌 | 28.1 | 抗菌药物列表 | ❌ FAIL | code=500, msg=No static resource api/v1/antibiotic/page for request '/healthlink-his/api/v1/antibiotic/page'. | +| DRG | 29.1 | DRG分析列表 | ❌ FAIL | code=500, msg=No static resource api/v1/mr-homepage/drg/page for request '/healthlink-his/api/v1/mr-homepage/drg/page'. | +| DRG | 29.2 | DRG预警列表 | ❌ FAIL | code=500, msg=No static resource cross-module/enhanced-drg-alert/page for request '/healthlink-his/cross-module/enhanced-drg-alert/page'. | +| 经营 | 30.1 | 经营分析列表 | ❌ FAIL | rows不是数组类型: | +| 系统 | 31.1 | 字典类型列表 | ❌ FAIL | code=500, msg=No static resource dict/type/page for request '/healthlink-his/dict/type/page'. | +| 系统 | 31.2 | 用户管理-列表非空 | ❌ FAIL | 用户列表为空,系统用户数据异常 | +| 系统 | 31.3 | 角色管理列表 | ❌ FAIL | code=500, msg=请求参数类型不匹配,参数[roleId]要求类型为:'java.lang.Long',但输入值为:'page' | +| 系统 | 31.4 | 菜单管理-菜单数量>50 | ✅ PASS | | +| 系统 | 31.5 | 部门管理-部门数量>5 | ✅ PASS | | +| 系统 | 31.6 | 岗位管理列表 | ❌ FAIL | code=500, msg=请求参数类型不匹配,参数[postId]要求类型为:'java.lang.Long',但输入值为:'page' | +| 系统 | 31.7 | 通知管理列表 | ❌ FAIL | code=500, msg=请求参数类型不匹配,参数[noticeId]要求类型为:'java.lang.Long',但输入值为:'page' | +| 系统 | 31.8 | 审计日志列表 | ❌ FAIL | code=500, msg= +### Error querying database. Cause: org.postgresql.util.PSQLException: ERROR: column "delete_flag" does not exist + Position: 51 +### The error may exist in com/healthlink/his/sys/mapper/SysAuditLogMapper.java (best guess) +### The error may involve defaultParameterMap +### The error occurred while setting parameters +### SQL: SELECT COUNT(*) AS total FROM sys_audit_log WHERE delete_flag = '0' +### Cause: org.postgresql.util.PSQLException: ERROR: column "delete_flag" does not exist + Position: 51 +; bad SQL grammar [] | +| 系统 | 31.9 | 仪表盘数据 | ❌ FAIL | 预期code=200, 实际code=500, msg=请求参数类型不匹配,参数[id]要求类型为:'java.lang.Long',但输入值为:'data' | +| 药房 | 32.1 | 库存预警列表 | ❌ FAIL | rows不是数组类型: | +| 药房 | 32.2 | 西药发药列表 | ❌ FAIL | code=500, msg=No static resource pharmacy-manage/western-medicine-dispense/page for request '/healthlink-his/pharmacy-manage/western-medicine-dispense/page'. | +| 药房 | 32.3 | 退药管理列表 | ❌ FAIL | code=500, msg=No static resource pharmacy-manage/return-medicine/page for request '/healthlink-his/pharmacy-manage/return-medicine/page'. | +| 药房 | 32.4 | 药品详情列表 | ❌ FAIL | code=500, msg=No static resource pharmacy-manage/medication-details/page for request '/healthlink-his/pharmacy-manage/medication-details/page'. | +| 报表 | 33.1 | 挂号报表 | ❌ FAIL | code=500, msg=No static resource report-manage/register/page for request '/healthlink-his/report-manage/register/page'. | +| 报表 | 33.2 | 收费报表 | ❌ FAIL | code=500, msg=No static resource report-manage/charge/page for request '/healthlink-his/report-manage/charge/page'. | +| 报表 | 33.3 | 住院首页采集 | ❌ FAIL | code=500, msg=No static resource medicalRecordHomePage-manage/collection/page for request '/healthlink-his/medicalRecordHomePage-manage/collection/page'. | +| 报表 | 33.4 | 经营统计 | ❌ FAIL | code=500, msg=No static resource report-manage/report-statistics/page for request '/healthlink-his/report-manage/report-statistics/page'. | diff --git a/MD/test/test_api.sh b/MD/test/test_api.sh new file mode 100755 index 000000000..31aaf6fb0 --- /dev/null +++ b/MD/test/test_api.sh @@ -0,0 +1,162 @@ +#!/bin/bash +# HealthLink-HIS 全流程API测试脚本 + +BASE_URL="http://localhost:18082/healthlink-his" +TOKEN="" +PASS=0 +FAIL=0 +TOTAL=0 + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# 登录获取Token +login() { + echo -e "${YELLOW}1. 登录认证${NC}" + TOKEN=$(curl -s -X POST "$BASE_URL/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"admin123","tenantId":"1"}' | \ + python3 -c "import sys,json;print(json.load(sys.stdin).get('token',''))") + + if [ -n "$TOKEN" ]; then + echo -e "${GREEN}✅ 登录成功${NC}" + PASS=$((PASS+1)) + else + echo -e "${RED}❌ 登录失败${NC}" + FAIL=$((FAIL+1)) + fi + TOTAL=$((TOTAL+1)) +} + +# 测试API +test_api() { + local name=$1 + local method=$2 + local path=$3 + local data=$4 + + local response + if [ "$method" = "GET" ]; then + response=$(curl -s "$BASE_URL$path" -H "Authorization: Bearer $TOKEN") + else + response=$(curl -s -X POST "$BASE_URL$path" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "$data") + fi + + local code=$(echo "$response" | python3 -c "import sys,json;print(json.load(sys.stdin).get('code','ERROR'))" 2>/dev/null) + + TOTAL=$((TOTAL+1)) + if [ "$code" = "200" ]; then + echo -e "${GREEN}✅ $name${NC}" + PASS=$((PASS+1)) + else + echo -e "${RED}❌ $name (Code: $code)${NC}" + FAIL=$((FAIL+1)) + fi +} + +echo "==========================================" +echo " HealthLink-HIS 全流程API测试" +echo "==========================================" +echo "" + +# 1. 登录认证 +login + +# 2. 门诊就诊流程 +echo "" +echo -e "${YELLOW}2. 门诊就诊流程${NC}" +test_api "门诊挂号" "POST" "/api/v1/outpatient/registration" '{"patientId":1,"doctorId":1,"deptId":1}' +test_api "门诊处方" "POST" "/api/v1/outpatient/prescription" '{"encounterId":1001,"patientId":1}' + +# 3. 住院入院流程 +echo "" +echo -e "${YELLOW}3. 住院入院流程${NC}" +test_api "入院登记" "POST" "/api/v1/inpatient/admission" '{"patientId":1,"deptId":5,"bedNo":"ICU-01"}' +test_api "护理评估(Braden)" "POST" "/nursing-assessment-enhanced/braden/assess" '{"patientName":"患者甲","encounterId":1001,"itemScores":"{\"sensation\":2,\"moisture\":2,\"activity\":1,\"mobility\":2,\"nutrition\":3,\"friction\":2}"}' +test_api "护理评估(Morse)" "POST" "/nursing-assessment-enhanced/morse/assess" '{"patientName":"患者甲","encounterId":1001,"itemScores":"{\"history\":15,\"diagnosis\":0,\"ambulation\":15,\"iv\":20,\"gait\":0,\"mental\":0}"}' + +# 4. 药房管理流程 +echo "" +echo -e "${YELLOW}4. 药房管理流程${NC}" +test_api "库存查询" "GET" "/pharmacystockalert/page?pageNo=1&pageSize=10" "" +test_api "库存预警" "GET" "/pharmacystockalert/summary" "" + +# 5. 检验管理流程 +echo "" +echo -e "${YELLOW}5. 检验管理流程${NC}" +test_api "检验申请" "GET" "/inspection/page?pageNo=1&pageSize=10" "" + +# 6. 影像检查流程 +echo "" +echo -e "${YELLOW}6. 影像检查流程${NC}" +test_api "影像对比" "GET" "/radiology-comparison/compare?patientId=1" "" + +# 7. 手术麻醉流程 +echo "" +echo -e "${YELLOW}7. 手术麻醉流程${NC}" +test_api "麻醉记录" "GET" "/anesthesia-enhanced/specimen/page?pageNo=1&pageSize=10" "" +test_api "麻醉质控" "GET" "/anesthesia-enhanced/qc/stats" "" + +# 8. 院感管理流程 +echo "" +echo -e "${YELLOW}8. 院感管理流程${NC}" +test_api "感染监测" "GET" "/infection/surveillance/page?pageNo=1&pageSize=10" "" +test_api "暴发预警" "GET" "/infection/warning/page?pageNo=1&pageSize=10" "" +test_api "多重耐药" "GET" "/infection/resistant/page?pageNo=1&pageSize=10" "" +test_api "职业暴露" "GET" "/infection/exposure/page?pageNo=1&pageSize=10" "" +test_api "手卫生" "GET" "/infection/hygiene/page?pageNo=1&pageSize=10" "" +test_api "环境监测" "GET" "/infection/environment/page?pageNo=1&pageSize=10" "" + +# 9. 质量管理流程 +echo "" +echo -e "${YELLOW}9. 质量管理流程${NC}" +test_api "护理质量" "GET" "/nursing-quality/page?pageNo=1&pageSize=10" "" +test_api "护理质量统计" "GET" "/nursing-quality/summary" "" +test_api "病历质量" "GET" "/api/v1/emr-quality/defect-statistics" "" + +# 10. 处方点评流程 +echo "" +echo -e "${YELLOW}10. 处方点评流程${NC}" +test_api "点评计划" "GET" "/api/v1/review/plans?pageNum=1&pageSize=10" "" +test_api "点评统计" "GET" "/api/v1/review/statistics" "" + +# 11. 临床路径流程 +echo "" +echo -e "${YELLOW}11. 临床路径流程${NC}" +test_api "路径管理" "GET" "/clinical-pathway/page?pageNo=1&pageSize=10" "" + +# 12. 中医管理流程 +echo "" +echo -e "${YELLOW}12. 中医管理流程${NC}" +test_api "中医方剂" "GET" "/api/v1/tcm/prescriptions" "" +test_api "中医统计" "GET" "/api/v1/tcm/statistics" "" + +# 13. 医嘱闭环流程 +echo "" +echo -e "${YELLOW}13. 医嘱闭环流程${NC}" +test_api "医嘱闭环" "GET" "/api/v1/order-closed-loop/list" "" +test_api "闭环统计" "GET" "/api/v1/order-closed-loop/statistics" "" + +# 14. ESB管理 +echo "" +echo -e "${YELLOW}14. ESB管理${NC}" +test_api "ESB监控" "GET" "/esb-reliability/monitor/stats" "" + +# 汇总 +echo "" +echo "==========================================" +echo " 测试结果汇总" +echo "==========================================" +echo -e "总测试数: $TOTAL" +echo -e "${GREEN}通过: $PASS${NC}" +echo -e "${RED}失败: $FAIL${NC}" +echo -e "通过率: $((PASS*100/TOTAL))%" +echo "==========================================" + +exit $FAIL