# apply/step1 接口说明 ## 接口概述 **接口路径**: `POST apply/step1` **功能**: 获取远程申请第一步的数据,用于初始化远程诊断申请表单 **业务场景**: - 下级医院医生发起远程诊断申请时调用 - 如果是新建申请,会自动创建一条 remote_application 记录 - 如果是编辑已有申请,直接返回申请数据 --- ## 调用链路 ``` Route (route.php) ↓ ApplyController::step1() ↓ ApplicationService::get_step1_data($params, $token) ↓ ApplicationDao (wrapper层) ↓ ApplicationModel (SQL查询) ``` --- ## 请求参数 ### 必传参数 | 参数名 | 类型 | 说明 | |--------|------|------| | id | string | 检查ID (exam_id) | ### 可选参数 | 参数名 | 类型 | 说明 | |--------|------|------| | ra_id | string | 远程申请ID (remote_application表的id),编辑时传入 | **参数说明**: - **新建申请**: 只传 `id`(检查ID),系统自动创建 remote_application 记录 - **编辑申请**: 传 `id` + `ra_id`,系统返回已有的申请数据 --- ## 核心业务逻辑 ### 1. Controller 层 **文件**: `controller/apply/ApplyController.php` ```php public function step1(ApplicationService $service) { try { // 1. 获取请求参数 $params = $this->getParams(); // 2. 参数验证(验证id是否存在) ApplicationValidate::checkId($params); // 3. 获取step1数据 $info = $service->get_step1_data($params, $this->getToken()); // 4. 返回结果 return $this->success($info); } catch(\Exception $e) { $this->throwError($e->getMessage(), 0001); } } ``` --- ### 2. Service 层 **文件**: `servies/application/ApplicationService.php` ```php public function get_step1_data($params, $token) { $id = $params['id']; // exam_id // 情况1:编辑已有申请(传了ra_id) if (isset($params['ra_id']) && !empty($params['ra_id'])) { // 直接从 remote_application 表查询已有数据 $info = $this->application->getApplication($params['ra_id']); return $info; } // 情况2:新建申请(没传ra_id) else { // 1. 定义需要查询的字段 $field = [ // exams表字段 'e.id', 'e.patient_num', // 病历号 'e.exam_datetime', // 检查时间 'e.exam_status', // 检查状态 'e.patient_id', // 患者ID 'e.study_id', // 检查UID 'e.exam_class', // 检查类型 'e.accession_num', // 检查号 'e.exam_project', // 检查项目 'e.name', // 姓名 'e.age', // 年龄 'e.sex', // 性别 'e.phone', // 手机号 'e.birthday', // 生日 'e.card_num', // 身份证号 'e.body_part', // 检查部位 'e.body_part_text', // 检查部位文本 'e.clin_symp', // 临床症状 'e.clin_diag', // 临床诊断 // register表字段 'r.exam_sub_class', // 检查子类型 'r.device_name as device', // 设备名称 'r.illness_desc', // 病情描述(患者主诉) 'r.phys_sign', // 体征 'r.anamnesis', // 既往史 'r.family_ill', // 家族史 'r.application_department as remote_department', // 开单科室 'r.ext as remark' // 备注 ]; // 2. 查询检查数据(联查 exams + register) $info = $this->application->getStep1Data($id, $field); // 3. 获取当前用户信息 $user = $this->getUser($token); // 4. 获取用户所在机构名称 $ins_name = $this->application->getInstitutionName($user['institution_id']); // 5. 构造 remote_application 初始数据 $data = [ 'id' => UUIDUtils::uuid(), // 申请ID(UUID) 'local_institution_id' => $user['institution_id'], 'local_institution_name' => $ins_name, 'req_date_time' => date('Y-m-d H:i:s', time()), 'name' => $info['name'], 'age' => $info['age'], 'sex' => $info['sex'], 'patient_num' => $info['patient_num'], 'accession_num' => $info['accession_num'], 'exam_id' => $info['id'], 'report_status' => 1, // 初始状态:1 'exam_class' => $info['exam_class'], 'phone' => $info['phone'], 'study_id' => $info['study_id'] ]; // 6. 插入 remote_application 表(创建申请记录) $this->application->insertAplication($data); // 7. 将申请ID添加到返回数据中 $info['application_id'] = $data['id']; return $info; } } ``` --- ### 3. Model 层 - SQL 查询 #### 3.1 查询检查数据(新建申请) **文件**: `model/application/ApplicationModel.php` ```php public function getStep1Data($id, $field) { // 联查 exams 和 register 表 $info = ExamModel::alias('e') ->join(['register' => 'r'], 'r.exam_id = e.id', 'LEFT') ->where('e.id', $id) ->field($field) ->find(); return $info; } ``` **等价SQL**: ```sql SELECT e.id, e.patient_num, e.exam_datetime, e.exam_status, e.patient_id, e.study_id, e.exam_class, e.accession_num, e.exam_project, e.name, e.age, e.sex, e.phone, e.birthday, e.card_num, e.body_part, e.body_part_text, e.clin_symp, e.clin_diag, r.exam_sub_class, r.device_name as device, r.illness_desc, r.phys_sign, r.anamnesis, r.family_ill, r.application_department as remote_department, r.ext as remark FROM exams e LEFT JOIN register r ON r.exam_id = e.id WHERE e.id = :exam_id ``` **涉及表**: - `exams` - 检查表 - `register` - 登记表 --- #### 3.2 查询已有申请(编辑) ```php public function getApplication($id) { $info = $this->where('id', $id)->find(); $info['application_id'] = $id; return $info; } ``` **等价SQL**: ```sql SELECT * FROM remote_application WHERE id = :ra_id ``` **涉及表**: - `remote_application` - 远程申请表 --- #### 3.3 插入申请记录 ```php public function insertAplication($info) { $data = $this->insert($info); return $data; } ``` **等价SQL**: ```sql INSERT INTO remote_application ( id, local_institution_id, local_institution_name, req_date_time, name, age, sex, patient_num, accession_num, exam_id, report_status, exam_class, phone, study_id ) VALUES (...) ``` --- #### 3.4 查询机构名称 ```php public function getInstitutionName($id) { $name = InstitutionModel::where('id', $id)->value('name'); return $name; } ``` **等价SQL**: ```sql SELECT name FROM institution WHERE id = :institution_id ``` --- ## 数据库表结构 ### 1. exams (检查表) 主要字段: - `id` - 检查ID(主键) - `patient_id` - 患者ID - `patient_num` - 病历号 - `exam_datetime` - 检查时间 - `exam_status` - 检查状态 - `study_id` - 检查UID - `exam_class` - 检查类型 - `accession_num` - 检查号 - `exam_project` - 检查项目 - `name` - 姓名 - `age` - 年龄 - `sex` - 性别 - `phone` - 手机号 - `birthday` - 生日 - `card_num` - 身份证号 - `body_part` - 检查部位 - `body_part_text` - 检查部位文本 - `clin_symp` - 临床症状 - `clin_diag` - 临床诊断 --- ### 2. register (登记表) 主要字段: - `id` - 登记ID(主键) - `exam_id` - 检查ID(关联exams.id) - `exam_sub_class` - 检查子类型 - `device_name` - 设备名称 - `illness_desc` - 病情描述(患者主诉) - `phys_sign` - 体征 - `anamnesis` - 既往史 - `family_ill` - 家族史 - `application_department` - 开单科室 - `ext` - 备注 --- ### 3. remote_application (远程申请表) 主要字段: - `id` - 申请ID(主键,UUID) - `exam_id` - 本地检查ID - `local_institution_id` - 下级机构ID - `local_institution_name` - 下级机构名称 - `super_institution_id` - 上级机构ID(后续步骤填写) - `super_institution_name` - 上级机构名称(后续步骤填写) - `req_date_time` - 申请时间 - `report_status` - 申请状态(1=初始,2=待支付,3=已支付...) - `name` - 患者姓名 - `age` - 年龄 - `sex` - 性别 - `phone` - 手机号 - `patient_num` - 病历号 - `accession_num` - 检查号 - `exam_class` - 检查类型 - `exam_project` - 检查项目 - `exam_sub_class` - 检查子类型 - `body_part` - 检查部位 - `body_part_text` - 检查部位文本 - `birthday` - 生日 - `card_num` - 身份证号 - `study_id` - 检查UID - `illness_desc` - 病情描述 - `phys_sign` - 体征 - `anamnesis` - 既往史 - `family_ill` - 家族史 - `device_name` - 设备名称 --- ## 返回数据结构 ### 新建申请返回数据示例 ```json { "code": 200, "message": "成功", "data": { "id": "exam123456", "application_id": "uuid-xxxx-xxxx-xxxx", "patient_num": "P202512180001", "exam_datetime": "2025-12-18 10:30:00", "exam_status": 3, "patient_id": "patient123", "study_id": "1.2.840.113619...", "exam_class": "CT", "accession_num": "ACC20251218001", "exam_project": "胸部CT平扫", "name": "张三", "age": "45", "sex": "M", "phone": "13800138000", "birthday": "1979-05-20", "card_num": "110101197905201234", "body_part": "胸部", "body_part_text": "胸部", "clin_symp": "咳嗽、胸闷", "clin_diag": "肺部感染?", "exam_sub_class": "平扫", "device": "西门子CT-01", "illness_desc": "患者诉咳嗽2周,伴胸闷气短", "phys_sign": "体温37.5℃,呼吸稍急促", "anamnesis": "高血压病史5年", "family_ill": "父亲有糖尿病", "remote_department": "呼吸内科", "remark": "" } } ``` ### 编辑申请返回数据示例 ```json { "code": 200, "message": "成功", "data": { "id": "uuid-xxxx-xxxx-xxxx", "application_id": "uuid-xxxx-xxxx-xxxx", "exam_id": "exam123456", "local_institution_id": "13000003", "local_institution_name": "某某医院", "super_institution_id": "13000001", "super_institution_name": "上级医院", "req_date_time": "2025-12-18 10:30:00", "report_status": 2, "name": "张三", "age": "45", "sex": "M", "phone": "13800138000", "patient_num": "P202512180001", "accession_num": "ACC20251218001", "exam_class": "CT", "exam_project": "胸部CT平扫", "exam_sub_class": "平扫", "body_part": "胸部", "body_part_text": "胸部", "birthday": "1979-05-20", "card_num": "110101197905201234", "study_id": "1.2.840.113619...", "illness_desc": "患者诉咳嗽2周,伴胸闷气短", "phys_sign": "体温37.5℃,呼吸稍急促", "anamnesis": "高血压病史5年", "family_ill": "父亲有糖尿病" } } ``` --- ## 业务规则总结 ### 1. 申请状态 (report_status) | 状态值 | 状态名称 | 说明 | |--------|---------|------| | 1 | 初始状态 | step1创建申请时的初始状态 | | 2 | 待支付 | step2保存后,等待支付 | | 3 | 已支付 | 支付完成,等待上级医生接诊 | | ... | ... | 后续状态根据业务流程定义 | ### 2. 新建 vs 编辑 **新建申请**: - 只传 `id`(检查ID) - 系统自动: 1. 从 exams + register 表查询检查数据 2. 创建 remote_application 记录(status=1) 3. 返回检查数据 + application_id **编辑申请**: - 传 `id` + `ra_id` - 直接从 remote_application 表返回已有数据 ### 3. 数据来源 | 字段类型 | 数据来源 | |---------|---------| | 患者基本信息 | exams表 | | 检查信息 | exams表 + register表 | | 申请信息 | 自动生成(机构、时间、状态) | | 病情描述 | register表 | --- ## Java 实现建议 ### 1. DTO #### ApplyStep1RequestVO.java ```java @Data @Schema(description = "远程申请Step1请求参数") public class ApplyStep1RequestVO { @NotBlank(message = "检查ID不能为空") @Schema(description = "检查ID", required = true) private String id; @Schema(description = "远程申请ID(编辑时传入)") private String raId; } ``` #### ApplyStep1ResponseDTO.java ```java @Data @Schema(description = "远程申请Step1返回数据") public class ApplyStep1ResponseDTO { @Schema(description = "检查ID") private String id; @Schema(description = "申请ID") private String applicationId; @Schema(description = "病历号") private String patientNum; @Schema(description = "检查时间") private String examDatetime; @Schema(description = "检查状态") private Integer examStatus; @Schema(description = "患者ID") private String patientId; @Schema(description = "检查UID") private String studyId; @Schema(description = "检查类型") private String examClass; @Schema(description = "检查号") private String accessionNum; @Schema(description = "检查项目") private String examProject; @Schema(description = "姓名") private String name; @Schema(description = "年龄") private String age; @Schema(description = "性别") private String sex; @Schema(description = "手机号") private String phone; @Schema(description = "生日") private String birthday; @Schema(description = "身份证号") private String cardNum; @Schema(description = "检查部位") private String bodyPart; @Schema(description = "检查部位文本") private String bodyPartText; @Schema(description = "临床症状") private String clinSymp; @Schema(description = "临床诊断") private String clinDiag; @Schema(description = "检查子类型") private String examSubClass; @Schema(description = "设备名称") private String device; @Schema(description = "病情描述(患者主诉)") private String illnessDesc; @Schema(description = "体征") private String physSign; @Schema(description = "既往史") private String anamnesis; @Schema(description = "家族史") private String familyIll; @Schema(description = "开单科室") private String remoteDepartment; @Schema(description = "备注") private String remark; } ``` --- ### 2. Mapper #### RemoteApplicationMapper.java ```java @Mapper public interface RemoteApplicationMapper extends BaseMapper { /** * 查询Step1数据(联查exams和register) */ ApplyStep1ResponseDTO getStep1Data(@Param("examId") String examId); } ``` #### RemoteApplicationMapper.xml ```xml ``` --- ### 3. Service 实现 ```java @Service @Slf4j public class ApplyServiceImpl implements ApplyService { @Resource private RemoteApplicationMapper remoteApplicationMapper; @Resource private OrgMapper orgMapper; @Override @Transactional(rollbackFor = Exception.class) public ApplyStep1ResponseDTO getStep1Data(ApplyStep1RequestVO requestVO) { String examId = requestVO.getId(); String raId = requestVO.getRaId(); // 情况1:编辑已有申请 if (StringUtils.isNotBlank(raId)) { RemoteApplication application = remoteApplicationMapper.selectById(raId); if (application == null) { throw new RuntimeException("申请不存在"); } ApplyStep1ResponseDTO dto = new ApplyStep1ResponseDTO(); BeanUtils.copyProperties(application, dto); dto.setApplicationId(raId); return dto; } // 情况2:新建申请 // 1. 查询检查数据 ApplyStep1ResponseDTO dto = remoteApplicationMapper.getStep1Data(examId); if (dto == null) { throw new RuntimeException("检查不存在"); } // 2. 获取当前用户机构信息 String currentOrgId = getCurrentUserOrgId(); Org org = orgMapper.selectById(currentOrgId); if (org == null) { throw new RuntimeException("机构不存在"); } // 3. 创建 remote_application 记录 RemoteApplication application = new RemoteApplication(); application.setExamId(examId); application.setLocalInstitutionId(currentOrgId); application.setLocalInstitutionName(org.getName()); application.setReqDateTime(new Date()); application.setName(dto.getName()); application.setAge(dto.getAge()); application.setSex(dto.getSex()); application.setPatientNum(dto.getPatientNum()); application.setAccessionNum(dto.getAccessionNum()); application.setReportStatus(1); // 初始状态 application.setExamClass(dto.getExamClass()); application.setPhone(dto.getPhone()); application.setStudyId(dto.getStudyId()); // MyBatis-Plus 自动生成 UUID remoteApplicationMapper.insert(application); // 4. 返回数据中包含 application_id dto.setApplicationId(application.getId()); log.info("创建远程申请成功,examId={}, applicationId={}", examId, application.getId()); return dto; } /** * 获取当前用户机构ID */ private String getCurrentUserOrgId() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser)) { throw new RuntimeException("未找到登录用户信息"); } LoginUser loginUser = (LoginUser) authentication.getPrincipal(); return loginUser.getUser().getCurrentOrg(); } } ``` --- ### 4. Controller ```java @RestController @RequestMapping("/api/apply") @Tag(name = "远程申请管理", description = "远程诊断申请相关接口") @Validated public class ApplyController { @Resource private ApplyService applyService; @Operation( summary = "获取申请Step1数据", description = "获取远程申请第一步的数据,用于初始化表单。" + "新建申请时只传id,系统会自动创建remote_application记录;" + "编辑申请时传id+raId,返回已有申请数据" ) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "查询成功"), @ApiResponse(responseCode = "400", description = "参数错误"), @ApiResponse(responseCode = "500", description = "服务器内部错误") }) @SystemLogHandler("获取申请Step1数据|查询") @PostMapping("/step1") public RestResult getStep1Data( @RequestBody @Valid ApplyStep1RequestVO requestVO) { try { ApplyStep1ResponseDTO dto = applyService.getStep1Data(requestVO); return RestResult.ok("查询成功", dto); } catch (RuntimeException e) { return RestResult.error(e.getMessage()); } catch (Exception e) { return RestResult.error("查询失败:" + e.getMessage()); } } } ``` --- ## 注意事项 1. **自动创建申请**: 新建时会自动插入 remote_application 记录,状态为1 2. **联表查询**: exams 和 register 是LEFT JOIN,register可能为空 3. **UUID生成**: application_id 使用 UUID,确保唯一性 4. **机构信息**: 从token获取当前用户的机构ID和名称 5. **事务控制**: Service层方法需要 @Transactional 注解 6. **字段映射**: 注意SQL字段别名与DTO字段名的对应(驼峰命名)