Index.jsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. import React from 'react';
  2. import Login from '@components/login/Index.jsx';
  3. import DoctorScreen from '@pages/doctorScreen/Index.jsx';
  4. import BigScreen from '@pages/bigScreen/Index.jsx';
  5. import OperateScreen from '@pages/operateScreen/Index.jsx';
  6. import FingerprintJS from '@fingerprintjs/fingerprintjs';
  7. import { initSocket } from '@api/index.js';
  8. import { AntOutline, SetOutline } from 'antd-mobile-icons';
  9. import { Toast } from 'antd-mobile';
  10. // // 安卓相关处理
  11. import audioSrc from './../../assets/mp3.wav';
  12. window.webGetDeviceId = function (callback) {
  13. window.callback = callback;
  14. };
  15. class Home extends React.Component {
  16. constructor(props) {
  17. super(props);
  18. this.state = {
  19. visibleLogin: false,
  20. userData: {}, // 用户及房间数据
  21. patList: [], // 就诊等待数据
  22. waitPat: [],
  23. patListArea: [], //区域等待就诊患者数据
  24. reWaitPat: [], // 复诊的患者
  25. roomObj: {},
  26. delayPat: [], //候诊数据
  27. showType: 'doctor', // doctor医生诊室 area诊区叫号 operate手术室
  28. cache: {},
  29. colorName: localStorage.getItem('ZZJ-color'), // white-bg白色 dark-bg深色
  30. deviceID: '',
  31. hosLogo: '',
  32. voiceSrc: [],
  33. isPlay: false,
  34. voiceList: [],
  35. myStatus: false,
  36. // 模拟数据
  37. tempList: [
  38. {
  39. 'roomDesc': '专家诊室一', 'docName': '宦大达', 'callMsg':
  40. {
  41. 'callPat': [{ 'patCallNo': '11号', 'patName': '患*者' }],
  42. 'waitPat': [
  43. { 'patCallNo': '1', 'patName': '患*者1' },
  44. { 'patCallNo': '2', 'patName': '患*者2' },
  45. { 'patCallNo': '3', 'patName': '患*者3' },
  46. { 'patCallNo': '4', 'patName': '患*者4' },
  47. { 'patCallNo': '5', 'patName': '患*者5' },
  48. { 'patCallNo': '6', 'patName': '患*者6' },
  49. { 'patCallNo': '7', 'patName': '患*者7' },
  50. { 'patCallNo': '8', 'patName': '患*者8' },
  51. { 'patCallNo': '9', 'patName': '患*者9' },
  52. { 'patCallNo': '10', 'patName': '患*者10' },
  53. { 'patCallNo': '11', 'patName': '患*者11' },
  54. { 'patCallNo': '12', 'patName': '患*者12' }],
  55. 'reWaitPat': [
  56. { 'patCallNo': '复01', 'patName': '患*者1' },
  57. { 'patCallNo': '复02', 'patName': '患*者2' },
  58. { 'patCallNo': '复03', 'patName': '患者3a' },
  59. { 'patCallNo': '复01', 'patName': '患*者1' },
  60. { 'patCallNo': '复02', 'patName': '患*者2' },
  61. { 'patCallNo': '复03', 'patName': '患者3a' },
  62. { 'patCallNo': '复04', 'patName': '患者4a' }],
  63. },
  64. delayPat: '患*者1,患*者2,患者3a,患*者1,患*者2,患者3a,患者4a,患*者1,患*者2,患者3a,患*者1,患*者2,患者3a,患者4a患*者1,患*者2,患者3a,患*者1,患*者2,患者3a,患者4a',
  65. },
  66. {
  67. 'roomDesc': '诊室1', 'docName': '医生1', 'callMsg':
  68. {
  69. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  70. 'waitPat': [
  71. { 'patCallNo': '1', 'patName': '患*者1' },
  72. { 'patCallNo': '2', 'patName': '患*者2' },
  73. { 'patCallNo': '3', 'patName': '患*者3' },
  74. { 'patCallNo': '4', 'patName': '患*者4' },
  75. { 'patCallNo': '5', 'patName': '患*者5' },
  76. { 'patCallNo': '6', 'patName': '患*者6' },
  77. { 'patCallNo': '7', 'patName': '患*者7' },
  78. { 'patCallNo': '8', 'patName': '患*者8' },
  79. { 'patCallNo': '9', 'patName': '患*者9' },
  80. { 'patCallNo': '10', 'patName': '患*者10' },
  81. { 'patCallNo': '11', 'patName': '患*者11' },
  82. { 'patCallNo': '12', 'patName': '患*者12' }],
  83. 'reWaitPat': [
  84. { 'patCallNo': '复01', 'patName': '患*者1' },
  85. ],
  86. }
  87. },
  88. {
  89. 'roomDesc': '诊室2', 'docName': '医生1', 'callMsg':
  90. {
  91. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  92. 'waitPat': [
  93. { 'patCallNo': '复01', 'patName': '患*者1' },
  94. ],
  95. 'reWaitPat': [
  96. { 'patCallNo': '复01', 'patName': '患*者1' },
  97. ],
  98. }
  99. },
  100. {
  101. 'roomDesc': '诊室3', 'docName': '医生1', 'callMsg':
  102. {
  103. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  104. 'waitPat': [
  105. { 'patCallNo': '复01', 'patName': '患*者1' },
  106. { 'patCallNo': '复1', 'patName': '患*者2' },
  107. { 'patCallNo': '01', 'patName': '患*者3' },
  108. { 'patCallNo': '复1', 'patName': '患*者4' },
  109. ],
  110. 'reWaitPat': [
  111. { 'patCallNo': '复01', 'patName': '患*者1' },
  112. ],
  113. }
  114. },
  115. {
  116. 'roomDesc': '诊室4', 'docName': '医生1', 'callMsg':
  117. {
  118. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  119. 'waitPat': [
  120. { 'patCallNo': '复01', 'patName': '患*者1' },
  121. ],
  122. 'reWaitPat': [
  123. { 'patCallNo': '复01', 'patName': '患*者1' },
  124. ],
  125. }
  126. },
  127. {
  128. 'roomDesc': '诊室5', 'docName': '医生1', 'callMsg':
  129. {
  130. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  131. 'waitPat': [
  132. { 'patCallNo': '复01', 'patName': '患*者1' },
  133. ],
  134. 'reWaitPat': [
  135. { 'patCallNo': '复01', 'patName': '患*者1' },
  136. ],
  137. }
  138. },
  139. {
  140. 'roomDesc': '诊室6', 'docName': '医生1', 'callMsg':
  141. {
  142. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  143. 'waitPat': [
  144. { 'patCallNo': '复01', 'patName': '患*者1' },
  145. ],
  146. 'reWaitPat': [
  147. { 'patCallNo': '复01', 'patName': '患*者1' },
  148. ],
  149. }
  150. },
  151. {
  152. 'roomDesc': '诊室7', 'docName': '医生1', 'callMsg':
  153. {
  154. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  155. 'waitPat': [
  156. { 'patCallNo': '复01', 'patName': '患*者1' },
  157. ],
  158. 'reWaitPat': [
  159. { 'patCallNo': '复01', 'patName': '患*者1' },
  160. ],
  161. }
  162. },
  163. {
  164. 'roomDesc': '诊室8', 'docName': '医生1', 'callMsg':
  165. {
  166. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  167. 'waitPat': [
  168. { 'patCallNo': '复01', 'patName': '患*者1' },
  169. ],
  170. 'reWaitPat': [
  171. { 'patCallNo': '复01', 'patName': '患*者1' },
  172. ],
  173. }
  174. },
  175. {
  176. 'roomDesc': '诊室9', 'docName': '医生1', 'callMsg':
  177. {
  178. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  179. 'waitPat': [
  180. { 'patCallNo': '复01', 'patName': '患*者1' },
  181. ],
  182. 'reWaitPat': [
  183. { 'patCallNo': '复01', 'patName': '患*者1' },
  184. ],
  185. }
  186. },
  187. {
  188. 'roomDesc': '诊室10', 'docName': '医生1', 'callMsg':
  189. {
  190. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  191. 'waitPat': [
  192. { 'patCallNo': '复01', 'patName': '患*者1' },
  193. ],
  194. 'reWaitPat': [
  195. { 'patCallNo': '复01', 'patName': '患*者1' },
  196. ],
  197. }
  198. },
  199. {
  200. 'roomDesc': '诊室11', 'docName': '医生1', 'callMsg':
  201. {
  202. 'callPat': [{ 'patCallNo': '11号', 'patName': '患*者' }],
  203. 'waitPat': [
  204. { 'patCallNo': '1', 'patName': '患*者1' },
  205. { 'patCallNo': '2', 'patName': '患*者2' },
  206. { 'patCallNo': '3', 'patName': '患*者3' },
  207. { 'patCallNo': '4', 'patName': '患*者4' },
  208. { 'patCallNo': '5', 'patName': '患*者5' },
  209. { 'patCallNo': '6', 'patName': '患*者6' },
  210. { 'patCallNo': '7', 'patName': '患*者7' },
  211. { 'patCallNo': '8', 'patName': '患*者8' },
  212. { 'patCallNo': '9', 'patName': '患*者9' },
  213. { 'patCallNo': '10', 'patName': '患*者10' },
  214. { 'patCallNo': '11', 'patName': '患*者11' },
  215. { 'patCallNo': '12', 'patName': '患*者12' }],
  216. 'reWaitPat': [
  217. { 'patCallNo': '复01', 'patName': '患*者1' },
  218. { 'patCallNo': '复02', 'patName': '患*者2' },
  219. { 'patCallNo': '复03', 'patName': '患者3a' },
  220. { 'patCallNo': '复04', 'patName': '患者4a' }],
  221. }
  222. },
  223. {
  224. 'roomDesc': '诊室12', 'docName': '医生1', 'callMsg':
  225. {
  226. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  227. 'waitPat': [
  228. { 'patCallNo': '复01', 'patName': '患*者1' },
  229. ],
  230. 'reWaitPat': [
  231. { 'patCallNo': '复01', 'patName': '患*者1' },
  232. ],
  233. }
  234. },
  235. {
  236. 'roomDesc': '诊室13', 'docName': '医生1', 'callMsg':
  237. {
  238. 'callPat': [{ 'patCallNo': '1号', 'patName': '患*者' }],
  239. 'waitPat': [
  240. { 'patCallNo': '复01', 'patName': '患*者1' },
  241. ],
  242. 'reWaitPat': [
  243. { 'patCallNo': '复01', 'patName': '患*者1' },
  244. ],
  245. }
  246. },
  247. ],
  248. };
  249. }
  250. componentDidMount() {
  251. this.initDevice();
  252. this.initAndroidVoice();
  253. const test = () => {
  254. var start = 0;
  255. setInterval(() => {
  256. const data = this.state.tempList[start];
  257. const patList = [...data.callMsg.callPat, ...data.callMsg.waitPat.map(v => {
  258. return { ...v, status: 'waiting' };
  259. })];
  260. const { roomObj } = this.state;
  261. roomObj[data.roomDesc] = data;
  262. const newArray = Object.keys(roomObj).map(key => {
  263. return roomObj[key];
  264. });
  265. this.setState({
  266. userData: {
  267. ...data?.userData,
  268. areaDesc: data.locDesc, // 大屏诊区
  269. roomDesc: data.roomDesc, // 诊室
  270. },
  271. patList,
  272. waitPat: data.callMsg.waitPat,
  273. reWaitPat: data.callMsg.reWaitPat,
  274. patListArea: newArray,
  275. roomObj,
  276. delayPat: data.delayPat,
  277. });
  278. ++start;
  279. if (start > 13) {
  280. start = 0;
  281. }
  282. this.initVoice('/mp3.wav');
  283. }, 2950);
  284. };
  285. // test();
  286. }
  287. initAndroidVoice() {
  288. window.mediaPlayOver = (flag) => {
  289. if (flag == 'success') {
  290. this.state.voiceList.splice(0, 1);
  291. this.setState({
  292. voiceList: this.state.voiceList,
  293. }, () => {
  294. this.soundPaly();
  295. });
  296. Toast.show({
  297. duration: 10000,
  298. content: '播放完成',
  299. });
  300. }else {
  301. Toast.show({
  302. duration: 10000,
  303. content: '播放失败',
  304. });
  305. }
  306. };
  307. }
  308. soundPaly() {
  309. const isDev = import.meta.env.MODE == 'development';
  310. if (isDev || (this.state.voiceList.length > 0)) {
  311. this.setState({
  312. myStatus: true,
  313. }, () => {
  314. const ua = navigator.userAgent.toLowerCase();
  315. if (/android/.test(ua)) {
  316. const src = isDev ? 'https://np.h03.p0551.com/images/wav/eba7ea72748b33c07d55ca7c443d6146.wav' : this.state.voiceList[0];
  317. window.JavaClientCall && window.JavaClientCall.mediaFilePlay(src);
  318. }
  319. });
  320. } else {
  321. this.setState({
  322. myStatus: false
  323. });
  324. }
  325. }
  326. // 音频播放事件
  327. initVoice = (src) => {
  328. const { voiceSrc } = this.state;
  329. voiceSrc.push(src);
  330. this.setState({
  331. voiceSrc,
  332. }, () => {
  333. if (voiceSrc.length == 1) {
  334. playVioce(src);
  335. }
  336. });
  337. const playVioce = (audioSrc) => {
  338. if (this.state.isPlay) {
  339. return;
  340. }
  341. this.setState({
  342. isPlay: true,
  343. }, () => {
  344. const domAudio = document.querySelector('#audio');
  345. domAudio.src = audioSrc;
  346. domAudio.playbackRate = 1;
  347. domAudio.currentTime = 0;
  348. domAudio.load();
  349. domAudio.play();
  350. const mes = () => {
  351. Toast.show({
  352. duration: 10000,
  353. content: '播放完成',
  354. });
  355. const { voiceSrc } = this.state;
  356. voiceSrc.splice(0, 1);
  357. const newArr = voiceSrc;
  358. this.setState({
  359. isPlay: false,
  360. voiceSrc: newArr,
  361. }, () => {
  362. if (newArr.length > 0) {
  363. playVioce(newArr[0]);
  364. }
  365. domAudio.removeEventListener('ended', mes);
  366. });
  367. };
  368. domAudio.addEventListener('ended', mes);
  369. // 10s看是否播放结束
  370. // setTimeout(() => {
  371. // if (this.state.isPlay) {
  372. // mes();
  373. // }
  374. // }, 10000);
  375. });
  376. };
  377. };
  378. initDevice = async () => {
  379. //接收Android端身份证信息函数
  380. window.webGetDeviceId = (deviceId) => {
  381. this.setState({
  382. deviceID: deviceId,
  383. }, () => {
  384. this.loginInit();
  385. });
  386. };
  387. const ua = navigator.userAgent.toLowerCase();
  388. if (/android/.test(ua)) {
  389. window.JavaClientCall && window.JavaClientCall.getDeviceID();
  390. }
  391. // 测试环境无法从安卓获取数据
  392. const isDev = import.meta.env.MODE == 'development';
  393. if (isDev) {
  394. const fp = await FingerprintJS.load();
  395. const AndroidInfo = await fp.get();
  396. this.setState({
  397. deviceID: AndroidInfo.visitorId,
  398. }, () => {
  399. this.loginInit();
  400. });
  401. }
  402. };
  403. // 改变颜色
  404. changeSwitch = () => {
  405. let { colorName } = this.state;
  406. if (!colorName) {
  407. colorName = 'white-bg';
  408. } else if (colorName == 'white-bg') {
  409. colorName = 'dark-bg';
  410. } else {
  411. colorName = '';
  412. }
  413. this.setState({
  414. colorName,
  415. });
  416. localStorage.setItem('ZZJ-color', colorName);
  417. const ua = navigator.userAgent.toLowerCase();
  418. if (/android/.test(ua)) {
  419. window.JavaClientCall && window.JavaClientCall.mediaFilePlay('https://np.h03.p0551.com/images/wav/eba7ea72748b33c07d55ca7c443d6146.wav');
  420. }
  421. this.soundPaly('https://np.h03.p0551.com/images/wav/eba7ea72748b33c07d55ca7c443d6146.wav');
  422. };
  423. openLogin = (cache) => {
  424. if (!cache) {
  425. cache = {
  426. BASE_URL: 'http://10.1.?.29:8090',
  427. Address: '/bdhealth/',
  428. room: '',
  429. use: '',
  430. hospital: '',
  431. };
  432. }
  433. this.setState({
  434. cache,
  435. visibleLogin: true,
  436. });
  437. };
  438. hideLogin = () => {
  439. this.setState({
  440. visibleLogin: false,
  441. });
  442. };
  443. loginInit = async() => {
  444. let cache = localStorage.getItem('ZZJ-base');
  445. if (cache) {
  446. cache = JSON.parse(cache);
  447. }
  448. if (!cache || (cache && !cache.room)) {
  449. this.openLogin(cache);
  450. return;
  451. }
  452. const obj = await this.login(cache);
  453. if (!obj) {
  454. return;
  455. }
  456. obj.deviceID = this.state.deviceID;
  457. initSocket(obj, (data) => {
  458. // console.log('Room接收消息:',data );
  459. data = JSON.parse(data);
  460. if (data.callMsg) {
  461. const patList = [...data.callMsg.callPat, ...data.callMsg.waitPat.map(v => {
  462. return { ...v, status: 'waiting' };
  463. })];
  464. const { roomObj } = this.state;
  465. roomObj[data.roomDesc] = data;
  466. const newArray = Object.keys(roomObj).map(key => {
  467. return roomObj[key];
  468. });
  469. this.setState({
  470. userData: {
  471. ...data?.userData,
  472. areaDesc: data.locDesc, // 大屏诊区
  473. roomDesc: data.roomDesc, // 诊室
  474. },
  475. patList,
  476. waitPat: data.callMsg.waitPat,
  477. reWaitPat: data.callMsg.reWaitPat,
  478. patListArea: newArray,
  479. roomObj,
  480. delayPat: data.delayPat,
  481. });
  482. if (!data.path || !data.voiceFileName) {
  483. return;
  484. }
  485. this.state.voiceList.push(data.path + data.voiceFileName);
  486. this.setState({
  487. voiceList: this.state.voiceList,
  488. }, () => {
  489. if (!this.state.myStatus) {
  490. this.soundPaly();
  491. }
  492. });
  493. // this.initVoice(data.path + data.voiceFileName);
  494. }
  495. });
  496. };
  497. //登录事件
  498. login = async () => {
  499. let cache = localStorage.getItem('ZZJ-base');
  500. if (!cache) {
  501. return;
  502. }
  503. cache = JSON.parse(cache);
  504. return React.$fetchPost('04150020', {
  505. params: [{
  506. ip: cache.BASE_URL,
  507. identifyCode: this.state.deviceID,
  508. }],
  509. }, true).then((data) => {
  510. if (data) {
  511. const obj = {
  512. Loc: 'area',
  513. Room: 'doctor',
  514. OptomeRoom: 'doctor',
  515. OperLoc: 'operate',
  516. };
  517. this.setState({
  518. userData: data?.result[0] || {},
  519. // https://172.16.1.6/images/hoslogo/H02.png 医院logo
  520. hosLogo: `/images/hoslogo/${data?.result[0]?.hospCode}.png`
  521. });
  522. if (obj[data.code]) {
  523. this.setState({
  524. showType: obj[data.code], // Loc医生诊室 Room,OptomeRoom大屏 OperLoc 手术室
  525. });
  526. if (obj[data.code] == 'doctor') {
  527. document.querySelector('html').className = '';
  528. } else {
  529. document.querySelector('html').className = 'big';
  530. }
  531. return data?.result[0] || null;
  532. } else {
  533. this.openLogin();
  534. return null;
  535. }
  536. }
  537. });
  538. };
  539. render () {
  540. return (
  541. <>
  542. <div className={ this.state.colorName}>
  543. {/* 设备信息配置,选择医院 */}
  544. <Login
  545. visibleLogin={this.state.visibleLogin}
  546. formData={this.state.cache}
  547. hideLogin={this.hideLogin}
  548. loginInit={this.loginInit}
  549. deviceID={this.state.deviceID}
  550. />
  551. {/* 医生诊室呼叫 */}
  552. {this.state.showType == 'doctor'
  553. ? <DoctorScreen
  554. userData={this.state.userData}
  555. patList={this.state.patList}
  556. reWaitPat={this.state.reWaitPat}
  557. hosLogo={this.state.hosLogo}
  558. />
  559. : this.state.showType == 'operate'
  560. ? <OperateScreen
  561. patList={this.state.waitPat}
  562. userData={this.state.userData}
  563. hosLogo={this.state.hosLogo}
  564. />
  565. : < BigScreen
  566. userData={this.state.userData}
  567. patListArea={this.state.patListArea}
  568. delayPat={this.state.delayPat}
  569. hosLogo={this.state.hosLogo}
  570. />
  571. }
  572. </div>
  573. <span
  574. className='bottom-set'
  575. >
  576. <AntOutline
  577. style={{color: this.state.colorName == 'dark-bg' ? '#fff' : '#0D2764', marginLeft: '10px'}}
  578. onClick={this.changeSwitch}
  579. />
  580. <SetOutline
  581. onClick={this.openLogin}
  582. style={{color: this.state.colorName == 'dark-bg' ? '#fff' : '#0D2764', marginLeft: '10px'}}
  583. />
  584. </span>
  585. <audio controls id="audio"
  586. style={{ position: 'fixed', left: '-1000px', top: '100px' }}
  587. ></audio>
  588. </>
  589. );
  590. }
  591. }
  592. export default Home;