LinkService.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <?php
  2. namespace app\api\servies\link;
  3. use app\api\dao\link\LinkDao;
  4. use app\api\servies\ZskkDefaultService;
  5. use app\api\utils\UUIDUtils;
  6. use think\facade\Cache;
  7. use think\facade\Config;
  8. use think\facade\Log;
  9. use think\Db;
  10. use think\db\exception;
  11. /**
  12. * 后台控制器基类
  13. * 接口方法权限 必传参数 接口返回 错误抛出 通用参数处理
  14. */
  15. class LinkService extends ZskkDefaultService {
  16. protected $logName = "LinkService";
  17. private $linkDao = null;
  18. public function __construct(LinkDao $linkDao) {
  19. parent::__construct();
  20. $this->linkDao = $linkDao;
  21. }
  22. public function getPacsInstitutionExam()
  23. {
  24. $institution = $this->linkDao->getAllIns();
  25. $allIns = [];
  26. foreach ($institution as $k=>$v)
  27. {
  28. $allIns[$v['id']] = $v['name'];
  29. }
  30. $exam = $this->linkDao->getinsExam();
  31. rsort($exam);
  32. $arr = [];
  33. foreach ($exam as $k=>$v)
  34. {
  35. if(empty($allIns[$v['institution_id']] ?? ''))
  36. {
  37. continue;
  38. }
  39. $arr[] = ['name'=>$allIns[$v['institution_id']] ,'num'=> $v['num']];
  40. }
  41. return $arr;
  42. }
  43. public function getPacsAgeExam()
  44. {
  45. $data = $this->linkDao->getPacsAgeExam();
  46. $arr = $this->statisticsAge($data);
  47. return $arr;
  48. }
  49. public function getPacsDateExam()
  50. {
  51. $data = $this->linkDao->getPacsDateExam();
  52. return $data;
  53. }
  54. /**
  55. * 统计年龄分布
  56. */
  57. function statisticsAge($data) {
  58. $ageStats = [];
  59. foreach ($data as $row) {
  60. $age = $this->normalizeAge($row['age']);
  61. $count = (int)$row['row_cnt'];
  62. // 跳过无效年龄
  63. if ($age === null) {
  64. continue;
  65. }
  66. // 累加相同年龄的数量
  67. if (!isset($ageStats[$age])) {
  68. $ageStats[$age] = 0;
  69. }
  70. $ageStats[$age] += $count;
  71. }
  72. // 转换为所需格式并按年龄排序
  73. $result = [];
  74. ksort($ageStats);
  75. foreach ($ageStats as $age => $count) {
  76. $result[] = [
  77. 'age' => $age,
  78. 'count' => $count
  79. ];
  80. }
  81. return $result;
  82. }
  83. function normalizeAge($ageStr) {
  84. if (empty($ageStr) || $ageStr === 'NULL' || $ageStr === '不详') {
  85. return null;
  86. }
  87. $ageStr = trim($ageStr);
  88. // 处理 Y 结尾的年龄(如 27Y, 83Y)
  89. if (preg_match('/^(\d+)Y$/i', $ageStr, $matches)) {
  90. return (int)$matches[1];
  91. }
  92. // 处理"岁"结尾的年龄(如 31岁, 72岁)
  93. if (preg_match('/^(\d+)岁/', $ageStr, $matches)) {
  94. return (int)$matches[1];
  95. }
  96. // 处理小数格式(如 74.00, 64.00)
  97. if (preg_match('/^(\d+)\.?\d*$/', $ageStr, $matches)) {
  98. return (int)$matches[1];
  99. }
  100. // 处理纯数字(如 48, 179)
  101. if (is_numeric($ageStr)) {
  102. return (int)$ageStr;
  103. }
  104. // 处理月份(如 3月28天, 10M)- 转换为 0 岁
  105. if (preg_match('/月|M$/i', $ageStr)) {
  106. return 0;
  107. }
  108. // 处理天数或小时(如 19天, 0小时19分钟)- 转换为 0 岁
  109. if (preg_match('/天|小时|分钟|D$/i', $ageStr)) {
  110. return 0;
  111. }
  112. // 其他无法识别的格式返回 null
  113. return null;
  114. }
  115. public function getPacsCount()
  116. {
  117. $info = Db::query("SELECT TRUNC(createdAt,'MM') AS month_begin,COUNT(*) AS cnt FROM pacs.query_study_logs GROUP BY TRUNC(createdAt,'MM') ORDER BY month_begin");
  118. $all = 0;
  119. foreach ($info as $k=>$v)
  120. {
  121. $info[$k]['month_begin'] = (explode(' ',$v['month_begin'])[0] ?? '');
  122. $all += $v['cnt'];
  123. }
  124. $project = $this->linkDao->countExam();
  125. $data = ['image'=>$all,'project'=>$project,'list'=>$info];
  126. return $data;
  127. }
  128. public function getPacsResult()
  129. {
  130. $arr = $this->linkDao->getReportResult();
  131. $data = ['阴性'=>0,'阳性'=>0,'其他'=>0];
  132. foreach ($arr as $k=>$v)
  133. {
  134. if($v['report_result'] == '1')
  135. {
  136. $data['阴性'] += $v['cnt'];
  137. }elseif ($v['report_result'] == '2')
  138. {
  139. $data['阳性'] += $v['cnt'];
  140. }else{
  141. $data['其他'] += $v['cnt'];
  142. }
  143. }
  144. $return = $this->makeData($data);
  145. return $return;
  146. }
  147. public function makeData($arr)
  148. {
  149. $data = [];
  150. foreach ($arr as $k=>$v)
  151. {
  152. $data[] = ['name'=>$k,'value'=>$v];
  153. }
  154. return $data;
  155. }
  156. public function getPacsSex()
  157. {
  158. $arr = $this->linkDao->getSexData();
  159. $data = ['男'=>0,'女'=>0,'其他'=>0];
  160. foreach ($arr as $k=>$v)
  161. {
  162. if($v['sex'] == 'M' || $v['sex'] == '男' )
  163. {
  164. $data['男'] += $v['cnt'];
  165. }elseif ($v['sex'] == 'F' || $v['sex'] == '女')
  166. {
  167. $data['女'] += $v['cnt'];
  168. }else{
  169. $data['其他'] += $v['cnt'];
  170. }
  171. }
  172. $return = $this->makeData($data);
  173. return $return;
  174. }
  175. public function getMiddleProjectList()
  176. {
  177. $list = $this->linkDao->getMiddleProjectList();
  178. return $list;
  179. }
  180. public function getPacsMapExam()
  181. {
  182. $institution = $this->linkDao->getAllIns();
  183. $allIns = [];
  184. foreach ($institution as $k=>$v)
  185. {
  186. $allIns[$v['id']] = $v;
  187. }
  188. $exam = $this->linkDao->getInsExam();
  189. rsort($exam);
  190. $arr = [];
  191. foreach ($exam as $k=>$v)
  192. {
  193. if(empty($allIns[$v['institution_id']] ?? ''))
  194. {
  195. continue;
  196. }
  197. $arr[] = ['num'=>$v['num'],'lng'=>$allIns[$v['institution_id']]['lng'],'lat'=>$allIns[$v['institution_id']]['lat'],'NAME'=>$allIns[$v['institution_id']]['name']];
  198. }
  199. return $arr;
  200. }
  201. public function getShareToken($param)
  202. {
  203. if(empty($param['B']))
  204. {
  205. $this->throwError('证件号不能为空','-1');
  206. }
  207. $token = UUIDUtils::uuid();
  208. $this->setCache($token,$param,32400);
  209. return $token;
  210. }
  211. public function getViewDetail($info)
  212. {
  213. $cardNum = $info['B'];
  214. $cardWhere = ['card_num'=>$cardNum];
  215. $where = [];
  216. if($info['H'] == 1)
  217. {
  218. $where['institution_id'] = $info['C'];
  219. }
  220. $data = $this->linkDao->getExamData($where,$cardWhere);
  221. if(!empty($data))
  222. {
  223. $patient = [];
  224. $report = [];
  225. $examReport = [];
  226. foreach ($data as $k=>$v)
  227. {
  228. switch ($v['sex'])
  229. {
  230. case 'M':
  231. $sex = '男';
  232. break;
  233. case 'F':
  234. $sex = '女';
  235. break;
  236. default:
  237. $sex = '未知';
  238. }
  239. $patient = [
  240. 'BIRTH_DATE'=>$v['birthday'],
  241. 'CARDNUM'=>$v['card_num'],
  242. 'GENDER'=>$sex,
  243. 'ID_CARDNUM'=>$v['card_num'],
  244. 'MPI'=>$v['accession_num'],
  245. 'NAME'=>$v['name'],
  246. 'PATIENTNAME'=>$v['name'],
  247. 'AGE'=>$v['age']
  248. ];
  249. $report = $this->linkDao->getReportData(['exam_id'=>$v['id']]);
  250. $info = [];
  251. $institution = $this->linkDao->getInsData(['id'=>$v['institution_id']]);
  252. switch ($report['report_result'] ?? '')
  253. {
  254. case '1':
  255. $result = '阴性';
  256. break;
  257. case '2':
  258. $result = '阳性';
  259. break;
  260. default:
  261. $result = '未知';
  262. }
  263. $info['EXAM_REPORT'][] = [
  264. 'ACCESSION_NUM'=>$v['accession_num'],
  265. 'AUDITNAME'=>$report['review_doctor_name'] ?? '',
  266. 'BODYSITE'=>$v['body_part'],
  267. 'DEPTNAME'=>$v['application_department'],
  268. 'DEVICETYPE_CODE'=>$v['exam_class'],
  269. 'EXAM_ITEMNAME'=>$v['exam_project'],
  270. 'OBSERVATIONS_COMMENT'=>$report['description'] ?? '',
  271. 'OBSERVATIONS_RESULT'=>$report['impression'] ?? '',
  272. 'ORGNAME'=>$institution['name'],
  273. 'REPORTTIME'=>$report['report_datetime'] ?? '',
  274. 'RESULT_STATUS'=>$result,
  275. 'STUDYTIME'=>$v['exam_datetime'],
  276. 'STUDY_ID'=>$v['study_id'],
  277. ];
  278. //患者来源
  279. //'1'=>'急诊号 '2'=>住院号', '3'=>'门诊号' '4'=>'体检号'
  280. switch ($v['patient_source'])
  281. {
  282. case '1':
  283. $source = '急诊';
  284. break;
  285. case '2':
  286. $source = '住院';
  287. break;
  288. case '3':
  289. $source = '门诊';
  290. break;
  291. case '4':
  292. $source = '体检';
  293. break;
  294. default:
  295. $source = '';
  296. }
  297. $info['MEDICAL_INFORMATION'] = [
  298. 'AGE'=>$v['age'],
  299. 'CHIEFCOMPLAINT'=>$v['clin_diag'],
  300. 'CLASS'=>$source,
  301. 'DEPTNAME'=>$v['application_department'],
  302. 'DIAGNOSENAME'=>$v['clin_diag'],
  303. 'DOCTORNAME'=>$v['application_doctor'],
  304. 'ENCOUNTER_DATE'=>$v['exam_datetime'],
  305. 'GENDER'=>$sex,
  306. 'NAME'=>$v['name'],
  307. 'ORGCODE'=>$v['institution_id'],
  308. 'ORGNAME'=>$institution['name'],
  309. 'PATIENT_CODE'=>$v['accession_num']
  310. ];
  311. $examReport[] = $info;
  312. }
  313. $return = ['data'=>$examReport,'patient'=>$patient];
  314. return $return;
  315. }else{
  316. return [];
  317. }
  318. }
  319. public function getPatientList($param)
  320. {
  321. $param['code'] = openssl_decrypt(base64_decode($param['code']), 'AES-128-ECB', Config::get('chengde')['key']);
  322. $param['institution_id'] = openssl_decrypt(base64_decode($param['institution_id']), 'AES-128-ECB', Config::get('chengde')['key']);
  323. if(empty($param['institution_id']) || empty($param['code']))
  324. {
  325. $this->throwError('数据解密失败','1210');
  326. }
  327. if(empty($param['type']) || empty($param['code']))
  328. {
  329. $this->throwError('没有相应的类型','1211');
  330. }
  331. $insIds = explode(',',$param['institution_id']);
  332. $type = explode(',',$param['type']);
  333. $code = explode(',',$param['code']);
  334. $where = [];
  335. $institution[] = ['institution_id','in',$insIds];
  336. $whereTime = [];
  337. if(count($type) == 1&& count($code) !== 1)
  338. {
  339. //1个type多个code
  340. if(!(Config::get('institution_docking')[$type[0]] ?? null))
  341. {
  342. $this->throwError('没有相应的类型','1211');
  343. }
  344. $field = Config::get('institution_docking')[$type[0]];
  345. if($field == 'name')
  346. {
  347. $field = 'e.name';
  348. }
  349. $where[] = [$field,'in',$code];
  350. }else{
  351. foreach ($type as $k=>$v)
  352. {
  353. $field = Config::get('institution_docking')[$v];
  354. if(empty($field) /*|| empty($code[$k])*/){
  355. continue;
  356. }
  357. if($field == 'name')
  358. {
  359. $field = 'e.name';
  360. }
  361. if($field == 'exam_datetime')
  362. {
  363. $whereTime['exam_datetime'] = $code[$k];
  364. }else{
  365. if(empty($code[$k]))
  366. {
  367. if(!empty($code[0]))
  368. {
  369. $where[$field] = $code[0];
  370. }
  371. }else{
  372. $where[$field] = $code[$k];
  373. }
  374. }
  375. }
  376. }
  377. if(empty($where) && empty($whereTime))
  378. {
  379. return [];
  380. }
  381. if(($param['check'] ?? null))
  382. {
  383. switch ($param['check'])
  384. {
  385. case 1:
  386. $value = 'card_num';
  387. break;
  388. case 2:
  389. $value = 'phone';
  390. break;
  391. default:
  392. $value = '';
  393. $this->throwError('验证错误','1223');
  394. break;
  395. }
  396. $data = $this->linkDao->getExamsCheck($where,$institution,$value);
  397. if(empty($data))
  398. {
  399. $this->throwError('验证错误','1223');
  400. }
  401. $str = substr($data,-4);
  402. if($param['checkcode'] !== $str)
  403. {
  404. $this->throwError('验证码错误','1224');
  405. }
  406. }
  407. $info = $this->linkDao->getPatientReportList($where,$institution,$whereTime,[]);
  408. foreach ($info as $k=>$v)
  409. {
  410. $info[$k]['insConfig'] = '';
  411. $info[$k]['config_number'] = '';
  412. $config = Config::get('hospital_config');
  413. foreach ($config as $key=>$value)
  414. {
  415. if(isset($v[$key]) && !empty($v[$key]))
  416. {
  417. $info[$k]['insConfig'] = $value;
  418. $info[$k]['config_number'] = $v[$key];
  419. }
  420. }
  421. if(!empty($v['patient_source']))
  422. {
  423. $sourceArr = Config::get('patient_source');
  424. $sourceInfo = $sourceArr[$v['patient_source']] ?? [];
  425. if(!empty($sourceInfo))
  426. {
  427. $info[$k]['insConfig'] = $sourceInfo['name'];
  428. $info[$k]['config_number'] = $v[$sourceInfo['field']];
  429. }
  430. }
  431. }
  432. return $info;
  433. }
  434. public function getPatientInfo($params)
  435. {
  436. $info = $this->linkDao->getConfirmReportInfo($params['exam_id']);
  437. foreach ($info as $k=>$v)
  438. {
  439. $info[$k]['insConfig'] = '';
  440. $info[$k]['config_number'] = '';
  441. $config = Config::get('hospital_config');
  442. foreach ($config as $key=>$value)
  443. {
  444. if(isset($v[$key]) && !empty($v[$key]))
  445. {
  446. $info[$k]['insConfig'] = $value;
  447. $info[$k]['config_number'] = $v[$key];
  448. }
  449. $info[$k]['age'] = str_replace('W','周',str_replace('D','天',str_replace('M','月',str_replace('Y','岁',ltrim($info[$k]['age'],'0')))));
  450. }
  451. }
  452. return $info;
  453. }
  454. public function getJm($param)
  455. {
  456. return base64_encode(openssl_encrypt($param['code'], 'AES-128-ECB', Config::get('chengde')['key']));
  457. }
  458. }