ZskkDefaultService.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. <?php
  2. namespace app\api\servies;
  3. use app\api\actions\ZskkCache;
  4. use app\api\dao\doctor\DoctorDao;
  5. use app\api\model\institution\InstitutionModel;
  6. use app\api\model\rota\RotaModel;
  7. use app\common\base\service\BaseService;
  8. use app\common\base\actions\IBaseAction;
  9. use app\common\base\actions\IBaseLog;
  10. use app\api\actions\ZskkDefaultAction;
  11. use app\api\actions\ZskkDefaultLog;
  12. use app\common\library\uploadToCloud;
  13. use think\Db;
  14. use think\Exception;
  15. /**
  16. * 后台控制器基类
  17. * 接口方法权限 必传参数 接口返回 错误抛出 通用参数处理
  18. */
  19. class ZskkDefaultService extends BaseService implements IBaseAction, IBaseLog {
  20. use ZskkDefaultAction;
  21. use ZskkDefaultLog;
  22. use ZskkCache;
  23. protected $logName = "ZskkDefaultService";
  24. /**
  25. * 获取列表模糊搜索 where 条件
  26. * @param $params
  27. * @param $field
  28. * @return array|bool
  29. */
  30. public function getListFuzzyWhere($params, $field)
  31. {
  32. $where = false;
  33. if(isset($params['fuzzy_search']) && !empty($params['fuzzy_search'])){
  34. $where = '';
  35. $value = $params['fuzzy_search'];
  36. foreach ($field as $k=>$v){
  37. $where .= '`'. $v . '`' . ' LIKE '. ' \'%'. $value . '%\' ';
  38. // $where .= '`'. $v . '`' . ' = '. ' \''. $value . '\' ';
  39. if($k < count($field)-1){
  40. $where .= ' OR ';
  41. }
  42. }
  43. }
  44. return $where;
  45. }
  46. /**
  47. * 获取列表具体搜索 where 条件
  48. * @param $params
  49. * @param $field
  50. * @return array|bool
  51. */
  52. public function getListSpecificWhere($params, $field)
  53. {
  54. $where = false;
  55. if(isset($params['more_search']) && !empty($params['more_search'])){
  56. $more_search = $params['more_search'];
  57. $where = [];
  58. foreach ($more_search as $k=>$v){
  59. if(in_array($k, $field)){
  60. if($v['type'] == 'datetime'){
  61. if(empty($v['value'][0])){
  62. continue;
  63. }
  64. if($v['value'][0] == $v['value'][1]){
  65. $where[$k] = $v['value'][0];
  66. }else{
  67. $where[] = [$k,'between',[$v['value'][0], $v['value'][1]]];
  68. }
  69. }else{
  70. // 根据 type 获取具体的 where 条件
  71. $value = $this->formatSpecificWhere($v);
  72. if($value){
  73. $where[$k] = $value;
  74. }
  75. }
  76. }
  77. }
  78. }
  79. return $where;
  80. }
  81. //处理sex
  82. public function getSex($sexData)
  83. {
  84. $sex = '';
  85. switch ($sexData){
  86. case '男':
  87. $sex = 'M';
  88. break;
  89. case '女':
  90. $sex = 'F';
  91. break;
  92. case 'M':
  93. $sex = 'M';
  94. break;
  95. case 'F':
  96. $sex = 'F';
  97. break;
  98. default :
  99. $sex = $sexData;
  100. break;
  101. }
  102. return $sex;
  103. }
  104. /**
  105. * 格式化集体搜索 where 值
  106. * @param $value
  107. * @return array|bool
  108. * @author 马铁龙
  109. */
  110. public function formatSpecificWhere($value)
  111. {
  112. if(isset($value['type']) && !empty($value['type']) && isset($value['value']) && !empty($value['value'])){
  113. switch ($value['type']){
  114. case 'datetime':
  115. if(!isset($value['value'][0]) || empty($value['value'][0]) || !isset($value['value'][1]) || empty($value['value'][1])){
  116. return false;
  117. }
  118. return ['between',[$value['value'][0], $value['value'][1]]];
  119. case 'text' :
  120. if(!empty($value['value'])){
  121. return $value['value'];
  122. }
  123. return false;
  124. case 'in' :
  125. if(!empty($value['value'])){
  126. return ['in',explode(',', $value['value'])];
  127. }
  128. return false;
  129. case 'like':
  130. if(!empty($value['value'])){
  131. return [['like','%'.$value['value'].'%']];
  132. }
  133. return false;
  134. default:
  135. return false;
  136. }
  137. }
  138. return false;
  139. }
  140. public function getStageKey($report_id, $user_id)
  141. {
  142. return 'stage' . $report_id . $user_id;
  143. }
  144. public function curlJsonPost($url,$data)
  145. {
  146. $header = array(
  147. 'Authorization:'.'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJRCI6IjM0YmMxNjFmNWNjYmMyNzgyZGFkODkwYjYyNzE0Y2NiZjhhMzY0NzciLCJwYXRoIjoiXC9oaXNcL3YxXC90aWJldFwvbWVkaWNhbGNlbnRlcmFnZW50c1wvcHJlcGFyYXRpb25zIiwidXRjdGltZSI6IjIwMTktMDYtMjVUMDI6MjE6MjVaIn0.TZwTQxqvpXtBkE51fbzi2YYREO1LylH4EiQYWJ00i4o',
  148. 'Content-Type:'.'application/json;'
  149. );
  150. $ch = curl_init();
  151. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  152. curl_setopt($ch, CURLOPT_URL, $url);
  153. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  154. curl_setopt($ch, CURLOPT_HEADER, 0);
  155. curl_setopt($ch, CURLOPT_POST, 1);
  156. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  157. $data = curl_exec($ch);
  158. curl_close($ch);
  159. return $data;
  160. }
  161. public function curlJsonYbPost($url,$data)
  162. {
  163. $header = array(
  164. 'Authorization:'.'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBJRCI6IjM0YmMxNjFmNWNjYmMyNzgyZGFkODkwYjYyNzE0Y2NiZjhhMzY0NzciLCJwYXRoIjoiXC9oaXNcL3YxXC90aWJldFwvbWVkaWNhbGNlbnRlcmFnZW50c1wvcHJlcGFyYXRpb25zIiwidXRjdGltZSI6IjIwMTktMDYtMjVUMDI6MjE6MjVaIn0.TZwTQxqvpXtBkE51fbzi2YYREO1LylH4EiQYWJ00i4o',
  165. 'Content-Type:'.'application/json;'
  166. );
  167. $ch = curl_init();
  168. curl_setopt($ch, CURLOPT_TIMEOUT, 1);
  169. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  170. curl_setopt($ch, CURLOPT_URL, $url);
  171. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  172. curl_setopt($ch, CURLOPT_HEADER, 0);
  173. curl_setopt($ch, CURLOPT_POST, 1);
  174. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  175. $data = curl_exec($ch);
  176. curl_close($ch);
  177. return $data;
  178. }
  179. function curlPost($url, $data) {
  180. //初使化init方法
  181. $ch = curl_init();
  182. //指定URL
  183. curl_setopt($ch, CURLOPT_URL, $url);
  184. //设定请求后返回结果
  185. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  186. //声明使用POST方式来进行发送
  187. curl_setopt($ch, CURLOPT_POST, 1);
  188. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
  189. //发送什么数据呢
  190. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  191. //忽略证书
  192. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  193. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  194. //忽略header头信息
  195. curl_setopt($ch, CURLOPT_HEADER, 0);
  196. //设置超时时间
  197. // curl_setopt($ch, CURLOPT_TIMEOUT, 10);
  198. //发送请求
  199. $output = curl_exec($ch);
  200. //关闭curl
  201. curl_close($ch);
  202. //返回数据
  203. return $output;
  204. }
  205. // public function curl_get($url){
  206. // //初始化
  207. // $curl = curl_init();
  208. // //设置抓取的url
  209. // curl_setopt($curl, CURLOPT_URL, $url);
  210. // //设置头文件的信息作为数据流输出
  211. // curl_setopt($curl, CURLOPT_HEADER, 0);
  212. // //设置获取的信息以文件流的形式返回,而不是直接输出。
  213. // curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  214. // // 重定向
  215. // curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
  216. // //执行命令
  217. // $data = curl_exec($curl);
  218. // //关闭URL请求
  219. // curl_close($curl);
  220. // return $data;
  221. // }
  222. function msectime() {
  223. list($msec, $sec) = explode(' ', microtime());
  224. $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
  225. return $msectime;
  226. }
  227. function request_by_curl($remote_server, $post_string,$header = array ('Content-Type: application/json;charset=utf-8')) {
  228. $ch = curl_init();
  229. curl_setopt($ch, CURLOPT_URL, $remote_server);
  230. curl_setopt($ch, CURLOPT_POST, 1);
  231. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
  232. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  233. curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
  234. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  235. // 线下环境不用开启curl证书验证, 未调通情况可尝试添加该代码
  236. // curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
  237. // curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
  238. $data = curl_exec($ch);
  239. curl_close($ch);
  240. return $data;
  241. }
  242. public function new_wechat_push($openid,$pushType,$content)
  243. {
  244. $c = urlencode($content);
  245. $url = "https://wechat.pacsonline.cn/wx_patient/api/sendMsg?openid=$openid&pushType=$pushType&content=$c";
  246. $data = $this->curl_get($url);
  247. return $data;
  248. }
  249. function curl_get($url){
  250. $header = array(
  251. 'Accept: application/json',
  252. );
  253. $curl = curl_init();
  254. //设置抓取的url
  255. curl_setopt($curl, CURLOPT_URL, $url);
  256. //设置头文件的信息作为数据流输出
  257. curl_setopt($curl, CURLOPT_HEADER, 0);
  258. // 超时设置,以秒为单位
  259. curl_setopt($curl, CURLOPT_TIMEOUT, 1000);
  260. // 超时设置,以毫秒为单位
  261. // curl_setopt($curl, CURLOPT_TIMEOUT_MS, 500);
  262. // 设置请求头
  263. curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
  264. //设置获取的信息以文件流的形式返回,而不是直接输出。
  265. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  266. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  267. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  268. //执行命令
  269. $data = curl_exec($curl);
  270. return $data;
  271. // 显示错误信息
  272. // if (curl_error($curl)) {
  273. // print "Error: " . curl_error($curl);
  274. // } else {
  275. // // 打印返回的内容
  276. // curl_close($curl);
  277. // }
  278. }
  279. //计算总权重
  280. public function sum($arr)
  281. {
  282. $total = 0;
  283. foreach ($arr as $value) {
  284. $total += $value['weight'];
  285. }
  286. return $total;
  287. }
  288. // 处理队列
  289. public function handle_queue($institution)
  290. {
  291. //获取排队信息
  292. $queue = $this->getCache($institution.'_queue_'.date('Ymd'));
  293. //使用到了第几个
  294. $using = $this->getCache($institution.'_using_'.date('Ymd'));
  295. //医院每一轮的数量
  296. $allWeight = $this->getCache($institution.'_weight_'.date('Ymd'));
  297. if(empty($queue))
  298. {
  299. $insInfo = InstitutionModel::where('id',$institution)->find();
  300. if(empty($insInfo))
  301. {
  302. return "";
  303. }
  304. if($insInfo['is_auto_mode'] == '0')
  305. {
  306. // 没有开启自动分配
  307. return '';
  308. }
  309. $toady = date('Ymd');
  310. $rota = RotaModel::where('institution_id',$institution)->where('rota_datetime',$toady)->select()->toArray();
  311. if(empty($rota))
  312. {
  313. //没有今天的队列消息
  314. return '';
  315. }
  316. $using_num = 1;
  317. //获取医生列表
  318. $list = DB::table('doctors')->where('institution_id',$institution)->order('weight desc')->select();
  319. $arr = [];
  320. $use = [];
  321. foreach ($list as $k=>$v)
  322. {
  323. $arr[$v['id']] = $v['weight'];
  324. $use[$v['id']] = $v['weight'];
  325. }
  326. arsort($arr);
  327. arsort($use);
  328. // 获取权重总数
  329. $all = $this->sum($list);
  330. // 存储总权重
  331. $this->setCache($institution.'_weight_'.date('Ymd'),$all,86400);
  332. $data = [];
  333. for($i=1;$i<=$all;$i++)
  334. {
  335. if($i == 1)
  336. {
  337. //获取当前权重最大的一个医生
  338. $did = array_search(max($arr), $arr);
  339. $data[$i] = $did;
  340. //当前医生可使用-1
  341. $use[$did]--;
  342. }else{
  343. $second = [];
  344. //获取当前可使用权重最大的一个医生
  345. $did = array_search(max($use), $use);
  346. if($use[$did] == $arr[$did])
  347. {
  348. //当前医生权重已使用为最大权重 代表使用率为0 则分配给当前医生
  349. $data[$i] = $did;
  350. $use[$did] --;
  351. }else{
  352. $secondArray = $use;
  353. unset($second[$did]);
  354. $second = array_search(max($secondArray), $secondArray);
  355. if($use[$second] == $arr[$second])
  356. {
  357. //当前医生权重已使用为0 则分配给当前医生
  358. $data[$i] = $second;
  359. $use[$second] --;
  360. }else{
  361. if($use[$did] == $use[$second])
  362. {
  363. //存在多个未使用权重相同的情况
  364. $third = 0;
  365. $lastDoctor = $use[$second];
  366. foreach ($use as $k=>$v)
  367. {
  368. if($third == 0)
  369. {
  370. $lastDoctor = $k;
  371. $third = $v;
  372. }else{
  373. if($third == $v)
  374. {
  375. $lastDoctor = $k;
  376. }
  377. }
  378. }
  379. // 多个医生剩余权重使用数相同的情况 则分配给初始权重最低的那一个
  380. $data[$i] = $lastDoctor;
  381. $use[$lastDoctor]--;
  382. }else{
  383. $data[$i] = $did;
  384. $use[$did]--;
  385. }
  386. }
  387. }
  388. }
  389. }
  390. $using_num++;
  391. // 存储轮换使用的个数
  392. $this->setCache($institution.'_using_'.date('Ymd'),$using_num);
  393. // 存储医生队列的信息
  394. $this->setCache($institution.'_queue_'.date('Ymd'),$data,86400);
  395. //第一次进来
  396. return $data[$using_num];
  397. }else{
  398. $useing_num = $using+1;
  399. if ($useing_num == $allWeight)
  400. {
  401. // 满足一轮权重轮换
  402. $this->setCache($institution.'_using_'.date('Ymd'),0);
  403. }else{
  404. $this->setCache($institution.'_using_'.date('Ymd'),$useing_num);
  405. }
  406. return $queue[$useing_num];
  407. }
  408. }
  409. public function downLoad($url, $path,$create) {
  410. $pic_local = $path.'.dcm';
  411. if (!file_exists($create)) {
  412. mkdir($create, 0777,true);
  413. @chmod($create, 0777);
  414. }
  415. // 创建一个上下文,忽略证书验证
  416. $context = stream_context_create([
  417. 'ssl' => [
  418. 'verify_peer' => false,
  419. 'verify_peer_name' => false,
  420. ]
  421. ]);
  422. // 使用上下文打开 URL
  423. ob_start(); // 打开输出缓冲
  424. readfile($url, false, $context); // 输出图片文件
  425. $img = ob_get_contents(); //得到浏览器输出
  426. ob_end_clean(); //清除输出并关闭
  427. file_put_contents($pic_local, $img);
  428. return $pic_local;
  429. }
  430. //获取毫秒级年月日时分秒
  431. public function ts_time($format = 'u', $utimestamp = null) {
  432. if (is_null($utimestamp)){
  433. $utimestamp = microtime(true);
  434. }
  435. $timestamp = floor($utimestamp);
  436. $milliseconds = round(($utimestamp - $timestamp) * 1000);
  437. return date('Y-m-d H:i:s.'.str_pad(preg_replace('`(?<!\\\\)u`', $milliseconds, $format),3,0), $timestamp);
  438. }
  439. public function makeFileUrl($file,$type,$fileType='attachment',$expires='+12 hours',$bucket='')
  440. {
  441. $data = $file;
  442. if($type == '2')
  443. {
  444. // 移动云普通文件
  445. if(!empty($file))
  446. {
  447. $upload = new uploadToCloud();
  448. $data = $upload->makeUrl($file,$fileType,$expires,$bucket);
  449. }
  450. }elseif ($type == '1')
  451. {
  452. // 普通ris文件
  453. if(!empty($file))
  454. {
  455. $data = $file;
  456. }
  457. }elseif ($type == '3')
  458. {
  459. // 远程诊断视频
  460. if(!empty($file))
  461. {
  462. $upload = new uploadToCloud();
  463. $data = $upload->makeCloudUrl($file,$fileType,2,$expires);
  464. }
  465. }elseif ($type == '4')
  466. {
  467. // dcm影像压缩包
  468. if(!empty($file))
  469. {
  470. $upload = new uploadToCloud();
  471. $data = $upload->makeCloudUrl($file,$fileType,3,$expires);
  472. }
  473. }
  474. return $data;
  475. }
  476. }