Index.jsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  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. };
  418. openLogin = (cache) => {
  419. if (!cache) {
  420. cache = {
  421. BASE_URL: 'http://10.1.?.29:8090',
  422. Address: '/bdhealth/',
  423. room: '',
  424. use: '',
  425. hospital: '',
  426. };
  427. }
  428. this.setState({
  429. cache,
  430. visibleLogin: true,
  431. });
  432. };
  433. hideLogin = () => {
  434. this.setState({
  435. visibleLogin: false,
  436. });
  437. };
  438. loginInit = async() => {
  439. let cache = localStorage.getItem('ZZJ-base');
  440. if (cache) {
  441. cache = JSON.parse(cache);
  442. }
  443. if (!cache || (cache && !cache.room)) {
  444. this.openLogin(cache);
  445. return;
  446. }
  447. const obj = await this.login(cache);
  448. if (!obj) {
  449. return;
  450. }
  451. obj.deviceID = this.state.deviceID;
  452. initSocket(obj, (data) => {
  453. // console.log('Room接收消息:',data );
  454. data = JSON.parse(data);
  455. if (data.callMsg) {
  456. const patList = [...data.callMsg.callPat, ...data.callMsg.waitPat.map(v => {
  457. return { ...v, status: 'waiting' };
  458. })];
  459. const { roomObj } = this.state;
  460. roomObj[data.roomDesc] = data;
  461. const newArray = Object.keys(roomObj).map(key => {
  462. return roomObj[key];
  463. });
  464. this.setState({
  465. userData: {
  466. ...data?.userData,
  467. areaDesc: data.locDesc, // 大屏诊区
  468. roomDesc: data.roomDesc, // 诊室
  469. },
  470. patList,
  471. waitPat: data.callMsg.waitPat,
  472. reWaitPat: data.callMsg.reWaitPat,
  473. patListArea: newArray,
  474. roomObj,
  475. delayPat: data.delayPat,
  476. });
  477. if (!data.path || !data.voiceFileName) {
  478. return;
  479. }
  480. this.state.voiceList.push(data.path + data.voiceFileName);
  481. this.setState({
  482. voiceList: this.state.voiceList,
  483. }, () => {
  484. if (!this.state.myStatus) {
  485. this.soundPaly();
  486. }
  487. });
  488. // this.initVoice(data.path + data.voiceFileName);
  489. }
  490. });
  491. };
  492. //登录事件
  493. login = async () => {
  494. let cache = localStorage.getItem('ZZJ-base');
  495. if (!cache) {
  496. return;
  497. }
  498. cache = JSON.parse(cache);
  499. return React.$fetchPost('04150020', {
  500. params: [{
  501. ip: cache.BASE_URL,
  502. identifyCode: this.state.deviceID,
  503. }],
  504. }, true).then((data) => {
  505. if (data) {
  506. const obj = {
  507. Loc: 'area',
  508. Room: 'doctor',
  509. OptomeRoom: 'doctor',
  510. OperLoc: 'operate',
  511. };
  512. this.setState({
  513. userData: data?.result[0] || {},
  514. // https://172.16.1.6/images/hoslogo/H02.png 医院logo
  515. hosLogo: `/images/hoslogo/${data?.result[0]?.hospCode}.png`
  516. });
  517. if (obj[data.code]) {
  518. this.setState({
  519. showType: obj[data.code], // Loc医生诊室 Room,OptomeRoom大屏 OperLoc 手术室
  520. });
  521. if (obj[data.code] == 'doctor') {
  522. document.querySelector('html').className = '';
  523. } else {
  524. document.querySelector('html').className = 'big';
  525. }
  526. return data?.result[0] || null;
  527. } else {
  528. this.openLogin();
  529. return null;
  530. }
  531. }
  532. });
  533. };
  534. render () {
  535. return (
  536. <>
  537. <div className={ this.state.colorName}>
  538. {/* 设备信息配置,选择医院 */}
  539. <Login
  540. visibleLogin={this.state.visibleLogin}
  541. formData={this.state.cache}
  542. hideLogin={this.hideLogin}
  543. loginInit={this.loginInit}
  544. deviceID={this.state.deviceID}
  545. />
  546. {/* 医生诊室呼叫 */}
  547. {this.state.showType == 'doctor'
  548. ? <DoctorScreen
  549. userData={this.state.userData}
  550. patList={this.state.patList}
  551. reWaitPat={this.state.reWaitPat}
  552. hosLogo={this.state.hosLogo}
  553. />
  554. : this.state.showType == 'operate'
  555. ? <OperateScreen
  556. patList={this.state.waitPat}
  557. userData={this.state.userData}
  558. hosLogo={this.state.hosLogo}
  559. />
  560. : < BigScreen
  561. userData={this.state.userData}
  562. patListArea={this.state.patListArea}
  563. delayPat={this.state.delayPat}
  564. hosLogo={this.state.hosLogo}
  565. />
  566. }
  567. </div>
  568. <span
  569. className='bottom-set'
  570. >
  571. <AntOutline
  572. style={{color: this.state.colorName == 'dark-bg' ? '#fff' : '#0D2764', marginLeft: '10px'}}
  573. onClick={this.changeSwitch}
  574. />
  575. <SetOutline
  576. onClick={this.openLogin}
  577. style={{color: this.state.colorName == 'dark-bg' ? '#fff' : '#0D2764', marginLeft: '10px'}}
  578. />
  579. </span>
  580. <audio controls id="audio"
  581. style={{ position: 'fixed', left: '-1000px', top: '100px' }}
  582. ></audio>
  583. </>
  584. );
  585. }
  586. }
  587. export default Home;