Index.jsx 18 KB

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