报告详情.txt 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. 基于对 PHP 项目的代码分析,我为您整理了 report/details 接口的完整实现逻辑:
  2. ---
  3. 1. 接口路由和调用链
  4. 路由: report/details
  5. 调用链: ReportController::details() → ReportService::getReportDetail() → ReportDao → ReportModel
  6. ---
  7. 2. 参数验证(ReportValidate::check)
  8. 验证规则:
  9. - exam_id:必填,检查ID
  10. - is_remote:必填,枚举值 1 或 2
  11. - 1 = 远程申请报告
  12. - 2 = 本地检查报告
  13. - ra_id:可选,远程申请ID(当 is_remote=1 时使用)
  14. ---
  15. 3. 核心业务逻辑(ReportService::getReportDetail,第64-162行)
  16. 3.1 查询报告基础信息
  17. 分支判断:根据 ra_id 是否为空,决定查询本地报告还是远程报告
  18. 本地报告查询(ra_id 为空):
  19. SELECT
  20. -- 检查信息(exams表)
  21. e.patient_num, e.exam_class, e.exam_datetime, e.exam_status,
  22. e.name, e.sex, e.age, e.phone, e.exam_project,
  23. e.hopitalized_no, e.accession_num, e.write_report,
  24. CONCAT(study_id,'&node_type=',node_type) as study_id,
  25. e.node_type, e.institution_id,
  26. -- 报告信息(report表,type=1表示本地报告)
  27. r.id as report_id, r.impression, r.description,
  28. r.report_result, r.report_doctor_id, r.report_doctor_name,
  29. r.report_datetime, r.review_doctor_id, r.review_doctor_name,
  30. r.review_datetime, r.confirm_doctor_id, r.confirm_doctor_name,
  31. r.confirm_datetime, r.remote_application_id, r.qr_code,
  32. -- 登记信息(register表)
  33. re.body_part, re.exam_sub_class, re.hr_status,
  34. -- 医生签名信息(doctors表,三次关联)
  35. dp.is_use_autograph as report_use_autograph,
  36. dp.autograph as report_autograph,
  37. dp.autograph_type as report_autograph_type,
  38. dv.is_use_autograph as review_use_autograph,
  39. dv.autograph as review_autograph,
  40. dv.autograph_type as review_autograph_type,
  41. dc.is_use_autograph as confirm_use_autograph,
  42. dc.autograph as confirm_autograph,
  43. dc.autograph_type as confirm_autograph_type
  44. FROM exams e
  45. LEFT JOIN register re ON re.exam_id = e.id
  46. LEFT JOIN report r ON e.id = r.exam_id AND r.type = 1
  47. LEFT JOIN doctors dp ON dp.id = r.report_doctor_id
  48. LEFT JOIN doctors dv ON dv.id = r.review_doctor_id
  49. LEFT JOIN doctors dc ON dc.id = r.confirm_doctor_id
  50. WHERE e.id = $examId
  51. 远程报告查询(ra_id 不为空):
  52. SELECT
  53. -- 远程申请信息(remote_application表)
  54. e.patient_num, e.exam_class, e.exam_datetime, e.body_part,
  55. e.study_id, e.hopitalized_no, e.name, e.sex, e.age, e.phone,
  56. e.report_status, e.local_institution_name, e.req_doctor_name,
  57. e.remote_department, e.exam_project, e.accession_num,
  58. e.local_institution_id as institution_id,
  59. -- 报告信息(type=2表示远程报告)
  60. r.id as report_id, r.impression, r.description,
  61. r.report_result, r.report_doctor_id, r.report_doctor_name,
  62. r.report_datetime, r.review_doctor_id, r.review_doctor_name,
  63. r.review_datetime, r.confirm_doctor_id, r.confirm_doctor_name,
  64. r.confirm_datetime, r.remote_application_id, r.qr_code,
  65. -- 医生签名信息
  66. dp.is_use_autograph as report_use_autograph,
  67. dp.autograph as report_autograph,
  68. dp.autograph_type as report_autograph_type,
  69. dv.is_use_autograph as review_use_autograph,
  70. dv.autograph as review_autograph,
  71. dv.autograph_type as review_autograph_type,
  72. dc.is_use_autograph as confirm_use_autograph,
  73. dc.autograph as confirm_autograph,
  74. dc.autograph_type as confirm_autograph_type
  75. FROM remote_application e
  76. LEFT JOIN report r ON r.remote_application_id = e.id
  77. LEFT JOIN doctors dp ON dp.id = r.report_doctor_id
  78. LEFT JOIN doctors dv ON dv.id = r.review_doctor_id
  79. LEFT JOIN doctors dc ON dc.id = r.confirm_doctor_id
  80. WHERE e.id = $ra_id
  81. 自动创建报告记录(第70-81行):
  82. - 如果本地检查没有报告记录(report_id 为空),则自动创建一条:
  83. INSERT INTO report (id, exam_id, createdAt, type)
  84. VALUES (UUID(), $examId, NOW(), 1)
  85. ---
  86. 3.2 补充机构信息(第86-89行)
  87. SELECT report_subtitle, report_title, hr_info
  88. FROM institution
  89. WHERE id = $detail['institution_id']
  90. 字段说明:
  91. - report_title:报告标题
  92. - report_subtitle:报告副标题
  93. - hr_info:医院简介信息
  94. ---
  95. 3.3 获取 DICOM 文件路径(第90-99行)
  96. SELECT dcm_path, dcm_type
  97. FROM dcm_path
  98. WHERE effective_date > NOW()
  99. AND study_id = $detail['study_id']
  100. 字段说明:
  101. - dcm_path:DICOM 文件路径
  102. - dcm_type:存储类型(1=本地路径,其他=云存储)
  103. - effective_date:有效期(只查询未过期的)
  104. 路径处理:
  105. - 如果 dcm_type != 1,调用 makeFileUrl() 生成云存储访问URL
  106. ---
  107. 3.4 处理医生签名(第101-117行)
  108. // 三个医生的签名处理逻辑相同
  109. $detail['report_autograph'] = ($detail['report_use_autograph'] == 1)
  110. ? (empty($detail['report_autograph'])
  111. ? ''
  112. : $this->makeFileUrl($detail['report_autograph'], $detail['report_autograph_type']))
  113. : '';
  114. 逻辑:
  115. 1. 检查医生是否启用签名(is_use_autograph = 1)
  116. 2. 如果启用且有签名文件,则生成访问URL
  117. 3. 否则返回空字符串
  118. ---
  119. 3.5 查询医生所属机构(第119-126行)
  120. -- 根据报告医生ID查询
  121. SELECT i.name, d.introduce
  122. FROM doctors d
  123. LEFT JOIN institution i ON d.institution_id = i.id
  124. WHERE d.id = $detail['report_doctor_id']
  125. 返回字段:
  126. - institution:医生所属机构名称
  127. - introduce:医生简介
  128. ---
  129. 3.6 获取操作痕迹(第129-138行)
  130. SELECT
  131. r.impression, -- 印象(诊断结论)
  132. r.description, -- 描述(报告内容)
  133. r.report_result, -- 报告结果
  134. r.createdAt as handle_time, -- 操作时间
  135. d.realname, -- 操作医生姓名
  136. r.type -- 操作类型
  137. FROM report_record r
  138. LEFT JOIN doctors d ON r.doctor_id = d.id
  139. WHERE r.report_id = $detail['report_id']
  140. ORDER BY r.createdAt ASC
  141. 字段说明:
  142. - report_record 表记录报告的每次修改历史
  143. - type 可能值:1=书写,2=审核,3=确认等
  144. ---
  145. 3.7 获取草稿内容(第139-160行)
  146. 逻辑:
  147. 1. 如果报告已完成(exam_status = 9 或 report_status = 9),不加载草稿
  148. 2. 从缓存中读取当前医生的草稿:
  149. $userId = getUserId($token);
  150. $cacheToken = getStageKey($report_id, $userId);
  151. $stage = getCache($cacheToken);
  152. 3. 如果存在草稿,用草稿内容覆盖数据库内容:
  153. $detail['impression'] = $stage['impression']; // 诊断结论
  154. $detail['description'] = $stage['description']; // 报告描述
  155. ---
  156. 4. 数据表结构
  157. 涉及的主要数据表:
  158. | 表名 | 作用 |
  159. |--------------------|--------------------|
  160. | exams | 检查信息(患者、检查项目、状态等) |
  161. | report | 报告信息(印象、描述、医生、时间等) |
  162. | register | 登记信息(检查部位、检查子类等) |
  163. | remote_application | 远程申请信息 |
  164. | doctors | 医生信息(姓名、签名、所属机构等) |
  165. | institution | 机构信息(报告标题、副标题等) |
  166. | dcm_path | DICOM文件路径 |
  167. | report_record | 报告操作记录(历史痕迹) |
  168. ---
  169. 5. 返回数据结构
  170. {
  171. // 检查基础信息
  172. exam_id: "检查ID",
  173. is_remote: "1=远程 2=本地",
  174. patient_num: "病历号",
  175. name: "患者姓名",
  176. sex: "性别",
  177. age: "年龄",
  178. phone: "手机号",
  179. exam_class: "检查类别",
  180. exam_datetime: "检查时间",
  181. exam_status: "检查状态",
  182. exam_project: "检查项目",
  183. accession_num: "检查号",
  184. body_part: "检查部位",
  185. // 报告信息
  186. report_id: "报告ID",
  187. impression: "印象(诊断结论)",
  188. description: "描述(报告内容)",
  189. report_result: "报告结果",
  190. // 医生信息
  191. report_doctor_id: "报告医生ID",
  192. report_doctor_name: "报告医生姓名",
  193. report_datetime: "报告时间",
  194. review_doctor_id: "审核医生ID",
  195. review_doctor_name: "审核医生姓名",
  196. review_datetime: "审核时间",
  197. confirm_doctor_id: "确认医生ID",
  198. confirm_doctor_name: "确认医生姓名",
  199. confirm_datetime: "确认时间",
  200. // 医生签名
  201. report_use_autograph: "报告医生是否使用签名",
  202. report_autograph: "报告医生签名URL",
  203. review_use_autograph: "审核医生是否使用签名",
  204. review_autograph: "审核医生签名URL",
  205. confirm_use_autograph: "确认医生是否使用签名",
  206. confirm_autograph: "确认医生签名URL",
  207. // 机构信息
  208. institution_id: "机构ID",
  209. institution: "报告医生所属机构名称",
  210. introduce: "医生简介",
  211. report_title: "报告标题",
  212. report_subtitle: "报告副标题",
  213. hr_info: "医院简介",
  214. // DICOM信息
  215. study_id: "StudyID",
  216. dcm_path: "DICOM文件路径",
  217. dcm_type: "存储类型",
  218. // 操作痕迹
  219. trace: [
  220. {
  221. impression: "印象",
  222. description: "描述",
  223. report_result: "结果",
  224. handle_time: "操作时间",
  225. realname: "操作医生",
  226. type: "操作类型"
  227. }
  228. ],
  229. // 其他
  230. qr_code: "二维码",
  231. remote_application_id: "远程申请ID"
  232. }
  233. ---
  234. 6. 核心特性
  235. 1. 自动创建报告:首次打开报告详情时,如果不存在报告记录,自动创建
  236. 2. 草稿机制:未完成的报告优先显示缓存中的草稿内容
  237. 3. 医生签名:支持三个医生(报告、审核、确认)的电子签名
  238. 4. 操作痕迹:记录报告的所有修改历史
  239. 5. DICOM路径:支持本地路径和云存储,且有有效期校验
  240. 6. 远程报告:支持本地报告和远程申请报告两种模式
  241. ---
  242. 这就是 report/details 接口的完整实现逻辑。该接口是报告书写页面的核心数据接口,提供了报告编写所需的所有信息。
  243. 无论本地还是远程报告,获取基础信息后,都会执行相同的补充逻辑:
  244. 1. ✅ 查询机构信息(报告标题、副标题)
  245. 2. ✅ 获取 DICOM 文件路径
  246. 3. ✅ 处理医生签名(报告/审核/确认医生)
  247. 4. ✅ 查询医生所属机构
  248. 5. ✅ 获取操作痕迹
  249. 6. ✅ 加载草稿内容