# 数据同步接口说明文档 ## 概述 本模块提供HIS/PACS系统与本系统之间的数据同步接口,用于接收检查申请和DICOM影像数据。 **模块位置**: `/src/main/java/com/zskk/pacsonline/modules/api` **接口前缀**: `/api/sync` --- ## 接口列表 ### 1. 保存PACS检查申请数据 #### 接口信息 - **接口地址**: `POST /api/sync/savePacs` - **接口说明**: 当HIS/PACS系统发送检查申请时调用此接口,系统会自动创建患者信息、studies记录和exams记录 - **使用场景**: HIS系统开立检查申请单后,推送检查申请数据到本系统 #### 请求参数 (SavePacsVO) | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | applicationFormNo | String | 是 | 检查号/申请单号 | "APP20251213001" | | clinicId | String | 是 | 机构ID/诊所ID | "12345678" | | patientName | String | 是 | 患者姓名 | "张三" | | patientSex | String | 否 | 患者性别 | "男" | | patientBirthDate | String | 否 | 患者出生日期 | "1990-01-01" | | patientAge | String | 否 | 患者年龄 | "35" | | patientId | String | 是 | 患者ID(HIS系统中的患者ID) | "P123456" | | startDate | String | 否 | 检查开始日期 | "2025-12-13 10:00:00" | | modality | Integer | 否 | Modality类型(1=US超声, 其他=OP) | 1 | | contentDescription | String | 否 | 检查内容描述 | "腹部超声检查" | | department | String | 否 | 科室 | "超声科" | | clinicalDoctor | String | 否 | 临床医生 | "李医生" | | symptom | String | 否 | 症状 | "腹痛" | | patientWeight | String | 否 | 患者体重 | "65kg" | #### 请求示例 ```json { "applicationFormNo": "APP20251213001", "clinicId": "12345678", "patientName": "张三", "patientSex": "男", "patientBirthDate": "1990-01-01", "patientAge": "35", "patientId": "P123456", "startDate": "2025-12-13 10:00:00", "modality": 1, "contentDescription": "腹部超声检查", "department": "超声科", "clinicalDoctor": "李医生", "symptom": "腹痛", "patientWeight": "65kg" } ``` #### 返回结果 **成功响应**: ```json { "code": 200, "message": "保存成功", "data": "{\"code\":\"0\"}" } ``` **失败响应**: ```json { "code": 500, "message": "保存失败: 错误详情", "data": null } ``` #### 业务逻辑 1. **去重检查**: 检查是否已存在相同的申请单(根据applicationFormNo + clinicId) - 如果已存在,直接返回成功(避免重复创建) 2. **创建患者信息**: 在patient_infos表中创建患者记录 - 生成UUID作为患者ID - 保存患者基本信息(姓名、性别、年龄、生日等) 3. **创建Studies记录**: 在studies表中创建检查研究记录 - 生成UUID作为studies ID - 生成studyuid(格式:1.3.6.1.4.1.30071.8.{timestamp}{clinicId}{patientId}{applicationFormNo}) - modality类型转换:1=US(超声),其他=OP 4. **创建Exams记录**: 在exams表中创建检查记录 - 生成UUID作为exam ID - 初始状态设置为1(登记状态) - 关联患者ID、studies ID 5. **关联更新**: 更新studies表的exam_id字段,建立关联关系 #### 状态码说明 - `{"code":"0"}`: 操作成功 - `{"code":"1"}`: 操作失败 --- ### 2. 保存检查数据 #### 接口信息 - **接口地址**: `POST /api/sync/saveExam` - **接口说明**: 当DICOM影像数据到达时调用此接口,系统会更新或创建检查记录 - **使用场景**: DICOM设备采集完影像后,推送影像数据到本系统时触发 #### 请求参数 (SaveExamVO) | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | studyId | String | 否 | Study ID | "abc-123-def" | | studyuid | String | 否 | Study UID | "1.3.6.1.4.1.30071.8.xxx" | | patientId | String | 否 | 患者ID | "patient-uuid-123" | | patientNum | String | 否 | 病历号 | "P123456" | | accessionNum | String | 否 | 检查号 | "APP20251213001" | | examDatetime | String | 否 | 检查时间 | "2025-12-13 10:00:00" | | examClass | String | 否 | 检查类别 | "US" | | institutionId | String | 是 | 机构ID | "12345678" | | deviceName | String | 否 | 设备名称 | "GE超声设备" | | bodyPart | String | 否 | 检查部位 | "ABDOMEN" | | name | String | 否 | 患者姓名 | "张三" | | phone | String | 否 | 患者手机号 | "13800138000" | | cardNum | String | 否 | 身份证号 | "110101199001011234" | | sex | String | 否 | 性别 | "男" | | age | String | 否 | 年龄 | "35" | | nodeType | Integer | 否 | 节点类型 | 1 | | studyid | String | 否 | studyid | "study-123" | #### 请求示例 ```json { "studyId": "abc-123-def", "studyuid": "1.3.6.1.4.1.30071.8.1702456789", "patientId": "patient-uuid-123", "patientNum": "P123456", "accessionNum": "APP20251213001", "examDatetime": "2025-12-13 10:30:00", "examClass": "US", "institutionId": "12345678", "deviceName": "GE超声设备", "bodyPart": "ABDOMEN", "name": "张三", "phone": "13800138000", "cardNum": "110101199001011234", "sex": "男", "age": "35", "nodeType": 1 } ``` #### 返回结果 **成功响应**: ```json { "code": 200, "message": "保存成功", "data": "exam-uuid-456" } ``` **失败响应**: ```json { "code": 500, "message": "保存失败: 错误详情", "data": null } ``` #### 业务逻辑 **情况1: 检查记录已存在**(根据study_id查询) 1. 获取现有检查记录 2. 更新检查记录的部分字段: - update_time(更新时间) - status(设置为1,有效状态) - node_type(如果传入) - exam_class(如果与现有值不同) 3. 根据当前exam_status更新状态: - 如果exam_status = -1,更新为9 - 如果exam_status < 3,更新为3(影像到达),并分配医生 - 其他情况保持不变 **情况2: 检查记录不存在** 1. 查询studies表获取studyuid(如果传入studyId) 2. 创建新的检查记录: - 生成UUID作为exam ID - exam_status设置为3(影像到达状态) - 设置所有传入的患者和检查信息 - node_type默认为1 3. 分配医生(TODO) **特定机构处理逻辑**: - **机构71900004**: 自动去除患者姓名中的"="字符 - **机构16100014**: 将exam_class从"RF"转换为"DX" - **机构71900007/71900008**: 将exam_class从"CR"转换为"DR" - **机构43600001**: 查询时需要同时匹配studyId、studyuid和institutionId #### 检查状态说明 | 状态值 | 说明 | |--------|------| | -1 | 异常状态 | | 1 | 登记 | | 2 | 登记完成 | | 3 | 影像到达 | | 7 | 写报告 | | 8 | 审核报告 | | 9 | 确认报告 | --- ## 待实现功能清单 (TODO List) ### 高优先级 #### 1. 医生管理功能 **位置**: `ApiServiceImpl.java:99` **需求说明**: 在savePacs接口中,当接收到临床医生信息时,需要: - 检查doctors表中是否存在该医生 - 如果不存在,自动创建医生记录 - 将医生ID关联到exam记录的register字段 **实现建议**: ```java // 在ApiServiceImpl中添加方法 private String checkOrCreateDoctor(String doctorName, String institutionId) { // 1. 根据姓名和机构ID查询医生 // 2. 如果存在,返回医生ID // 3. 如果不存在,创建医生记录并返回新ID } ``` **相关表**: doctors **原PHP代码参考**: XzService.php 96-110行 --- #### 2. 医生队列自动分派 **位置**: `ApiServiceImpl.java:285` **需求说明**: 在saveExam接口中,当影像到达时需要自动分配医生: - 根据机构ID获取可用医生队列 - 实现轮询分派算法 - 考虑医生工作负载均衡 **实现建议**: ```java private String handleQueue(String institutionId) { // 1. 查询该机构的可用医生列表 // 2. 获取每个医生当前待诊数量 // 3. 按照轮询或负载均衡算法分配 // 4. 返回分配的医生ID } ``` **涉及字段**: exams.doctor_sign **原PHP代码参考**: XzService.php 382、444行(调用handle_queue方法) --- ### 中优先级 #### 3. 胶片流水管理 **位置**: `ApiServiceImpl.java:211, 258` **需求说明**: 处理电子胶片的费用流水: - 检查机构的胶片收费模式(医院托管/医院代收) - 如果是医院托管模式,创建胶片流水记录 - 更新exam的pay_status字段 **实现建议**: ```java private void saveInsFilmWater(String examId, String institutionId) { // 1. 查询机构胶片配置(charge_mode, film_price) // 2. 如果charge_mode是医院托管,创建money_water记录 // 3. 更新exam.pay_status = 1 } ``` **相关表**: - institution_film(机构胶片配置) - money_water(流水记录) **原PHP代码参考**: XzService.php 530-544行 --- #### 4. 检查部位代码转换 **位置**: `ApiServiceImpl.java:229` **需求说明**: 将DICOM标准的部位代码转换为中文描述 - 接收body_part代码(如"ABDOMEN") - 转换为中文文本(如"腹部") - 保存到body_part_text字段 **实现建议**: ```java private String getBodyText(String bodyPartCode) { // 1. 维护一个部位代码映射表 // 2. 根据代码查询对应的中文描述 // 3. 返回中文文本 } ``` **涉及字段**: exams.body_part_text **原PHP代码参考**: XzService.php 413-416行 --- ### 低优先级 #### 5. xz表数据同步 **位置**: `ApiServiceImpl.java:110` **需求说明**: 保留原PHP项目的检查申请原始数据表 - 判断是否需要在新系统中保留xz表 - 如果需要,创建xz实体类和mapper - 保存检查申请的原始数据 **实现建议**: - 确认业务需求是否需要xz表 - 如果需要,创建对应的实体类、mapper和XML - 在savePacs方法中添加xz表的insert和update逻辑 **相关表**: xz(检查申请表) **原PHP代码参考**: XzService.php 41-50, 113-115行 --- #### 6. 患者短信通知 **位置**: `ApiServiceImpl.java:276` **需求说明**: 当检查影像到达时,发送短信通知患者 - 检查机构是否开启短信功能 - 生成分享码 - 发送短信给患者 **实现建议**: ```java private void sendPatientSms(String examId, String phone, String institutionId) { // 1. 查询机构配置,检查是否开启patient_sms // 2. 生成随机验证码 // 3. 创建share_exam记录 // 4. 调用短信服务发送通知 } ``` **相关表**: - share_exam(分享记录) - institution_config(机构配置) **原PHP代码参考**: XzService.php 461-491行 --- #### 7. API回调处理 **位置**: `ApiServiceImpl.java:279` **需求说明**: 某些特定机构需要在数据创建后回调其API - 根据机构ID和action类型获取API配置 - 调用对应的action方法 - 处理回调结果 **实现建议**: ```java private void handleApiCallback(String institutionId, SaveExamVO params, Exams exam) { // 1. 查询api_config表获取该机构的回调配置 // 2. 根据action类型调用对应的回调方法 // 3. 记录回调结果 } ``` **相关表**: api_config(API配置表) **原PHP代码参考**: XzService.php 492-506行(包含金盛达、医健康等特定机构的回调) --- #### 8. 监控数据统计 **位置**: `ApiServiceImpl.java:301` **需求说明**: 保存检查监控数据用于统计分析 - 记录检查的关键信息 - 用于后续数据分析和报表 **实现建议**: ```java private void saveMonitorExam(SaveExamVO params) { // 1. 查询机构名称 // 2. 组装监控数据 // 3. 插入monitor_exam表 } ``` **相关表**: monitor_exam(监控数据表) **原PHP代码参考**: XzService.php 515-527行 --- ## 数据库表说明 ### 核心表 #### 1. patient_infos(患者信息表) - 存储患者基本信息 - 主键: id(UUID) - 关键字段: name, sex, age, birthday, phone, card_num #### 2. studies(检查研究表) - 存储DICOM Study级别信息 - 主键: id(UUID) - 关键字段: studyuid, patient_id, exam_id, accession_num #### 3. exams(检查信息表) - 存储检查记录 - 主键: id(UUID) - 关键字段: patient_id, study_id, exam_status, institution_id ### 待确认表 以下表在原PHP项目中使用,新系统中可能需要创建: - **xz**: 检查申请原始数据表 - **doctors**: 医生信息表 - **money_water**: 费用流水表 - **institution_film**: 机构胶片配置表 - **share_exam**: 患者分享记录表 - **api_config**: API回调配置表 - **monitor_exam**: 监控数据表 --- ## 接口调用流程 ### 完整流程示例 ``` 1. HIS系统开立检查申请 ↓ 2. HIS调用 POST /api/sync/savePacs - 创建patient_infos记录 - 创建studies记录 - 创建exams记录(状态=1 登记) ↓ 3. 患者到检查设备处检查 ↓ 4. DICOM设备采集影像完成 ↓ 5. DICOM系统调用 POST /api/sync/saveExam - 更新exams记录(状态=3 影像到达) - 分配医生 - 发送短信通知(如果配置) ↓ 6. 医生查看影像并出具报告 ``` --- ## 注意事项 1. **事务处理**: savePacs和saveExam方法都使用了`@Transactional`注解,确保数据一致性 2. **UUID生成**: 所有ID字段使用UUID生成,格式为去除"-"的32位字符串 3. **日期格式**: - 建议使用格式: `yyyy-MM-dd HH:mm:ss` - 例如: `2025-12-13 10:00:00` 4. **字符编码**: 所有字符串使用UTF-8编码 5. **去重逻辑**: savePacs接口有去重检查,重复调用不会创建重复数据 6. **状态机制**: exam_status字段遵循严格的状态流转规则 7. **特定机构逻辑**: saveExam方法中包含多个特定机构的数据处理逻辑,后续可考虑抽象为配置 --- ## 开发建议 ### 优先级排序 **第一阶段** (必须实现): 1. 医生管理功能 2. 医生队列自动分派 **第二阶段** (推荐实现): 3. 胶片流水管理 4. 检查部位代码转换 **第三阶段** (可选实现): 5. xz表数据同步(根据业务需求) 6. 患者短信通知 7. API回调处理 8. 监控数据统计 ### 测试建议 1. 单元测试:测试每个TODO功能的独立实现 2. 集成测试:测试完整的数据同步流程 3. 性能测试:模拟高并发场景下的接口性能 4. 兼容性测试:测试与不同HIS/PACS系统的对接 --- ## 更新日志 | 版本 | 日期 | 说明 | 作者 | |------|------|------|------| | 1.0.0 | 2025-12-13 | 初始版本,实现核心数据同步功能 | system | --- ## 联系方式 如有问题,请联系开发团队。