index.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. import { getPendingList } from '@/services/message';
  2. import { getComparisonData } from '@/services/OperationManagement';
  3. import { queryConditionSnapshot } from '@/services/SmartOps';
  4. import { getToken, UnityAction } from '@/utils/utils';
  5. import { LoadingOutlined } from '@ant-design/icons';
  6. import { connect, useParams, useRequest } from '@umijs/max';
  7. import { Popover } from 'antd';
  8. import dayjs from 'dayjs';
  9. import { useEffect, useState } from 'react';
  10. import { getScadaPage } from '../../services/OperationManagement';
  11. import styles from './index.less';
  12. const HomePage = (props) => {
  13. const { projectId } = useParams();
  14. const { data } = useRequest(queryConditionSnapshot, {
  15. defaultParams: [{ project_id: projectId }],
  16. pollingInterval: 10 * 1000,
  17. });
  18. const getPositionPst = (e) => {
  19. const width = document.body.clientWidth;
  20. const height = document.body.clientHeight;
  21. const xPst = (e.clientX / width).toFixed(2);
  22. const yPst = (e.clientY / height).toFixed(2);
  23. return xPst + '-' + yPst;
  24. };
  25. const webMouseEvent = {
  26. onMouseUp: (e) => {
  27. UnityAction.sendMsg('PointerOut', getPositionPst(e));
  28. },
  29. onMouseDown: (e) => {
  30. UnityAction.sendMsg('PointerIn', getPositionPst(e));
  31. },
  32. };
  33. useEffect(() => {
  34. localStorage.width = document.documentElement.getBoundingClientRect().width;
  35. window.refreshRem();
  36. document.body.style.backgroundColor = 'transparent';
  37. }, []);
  38. return (
  39. <div className={styles.content} {...webMouseEvent}>
  40. <CenterContent data={data} />
  41. <LeftContent data={data} />
  42. <RightContent data={data} />
  43. </div>
  44. );
  45. };
  46. const LeftContent = (props) => {
  47. const { data } = props;
  48. return (
  49. <div className={styles.left}>
  50. {/* <SmartWork data={data} /> */}
  51. <WaterAmt data={data} />
  52. <WaterQuality data={data} />
  53. <Backlog />
  54. {/* <Backlog /> */}
  55. </div>
  56. );
  57. };
  58. const CenterContent = (props) => {
  59. const { data } = props;
  60. return (
  61. <div className={styles.centerBox}>
  62. <SmartWork data={data} />
  63. <SelfInspection />
  64. {/* <Backlog />
  65. <Scada /> */}
  66. </div>
  67. );
  68. };
  69. const RightContent = (props) => {
  70. const { data } = props;
  71. return (
  72. <div className={styles.right}>
  73. {/* <SelfInspection /> */}
  74. <Electric data={data} />
  75. <Medicine />
  76. <Scada />
  77. {/* <Scada /> */}
  78. </div>
  79. );
  80. };
  81. const getValue = (str) => {
  82. const result = str?.match(/.*?(\d+(?:\.\d+)?)\D*$/);
  83. if (result && result[1]) return result[1];
  84. return 0;
  85. };
  86. // 水厂工况
  87. const SmartWork = (props) => {
  88. const { data } = props;
  89. return (
  90. <div
  91. className={styles.smartWork}
  92. onClick={() => UnityAction.sendMsg('menuItem', '工况管理')}
  93. >
  94. <Title title="水厂工况" />
  95. <div className={styles.scoreBox}>
  96. <div className={styles.circle}>
  97. <div className={styles.score}>{data?.score}</div>
  98. <div className={styles.grade}>{data?.grade}</div>
  99. </div>
  100. <div className={styles.scoreTitle}>
  101. 当前运行{data?.grade},可继续优化
  102. </div>
  103. </div>
  104. <div className={styles.time}>
  105. {dayjs(data?.clac_time).format('YYYY-MM-DD HH:mm')}
  106. </div>
  107. </div>
  108. );
  109. };
  110. // 水量监测
  111. const WaterAmt = (props) => {
  112. const { data } = props;
  113. const { projectId } = useParams();
  114. return (
  115. <div
  116. className={styles.waterAmt}
  117. onClick={() => UnityAction.sendMsg('menuItem', '水量监测')}
  118. >
  119. <Title title="水量监测" />
  120. <div className={styles.boxTip}>当前进水稳定,出水稳定</div>
  121. <ul>
  122. <li>
  123. <div className={styles.value}>{getValue(data?.fwa)}</div>
  124. <div className={styles.btn1}>进水量(m³/h)</div>
  125. </li>
  126. <li>
  127. <div className={styles.value}>{getValue(data?.dwa)}</div>
  128. <div className={styles.btn2}>产水量(m³/h)</div>
  129. </li>
  130. </ul>
  131. </div>
  132. );
  133. };
  134. // 水质监测
  135. const WaterQuality = (props) => {
  136. const { data } = props;
  137. const { projectId } = useParams();
  138. return (
  139. <div
  140. className={styles.waterQuality}
  141. onClick={() => UnityAction.sendMsg('menuItem', '水质监测')}
  142. >
  143. <Title title="水质监测" />
  144. <div className={styles.boxTip}>水质监测较好</div>
  145. <ul>
  146. <li style={{ width: '60%' }}>
  147. <div className={styles.valueLong}>{getValue(data?.dtds)}</div>
  148. <div className={styles.btn1}>外供水电导率(µs/cm)</div>
  149. </li>
  150. <li style={{ width: '40%' }}>
  151. <div className={styles.valueLong}>{data?.dph || 0}</div>
  152. <div className={styles.btn2}>外供水(PH)</div>
  153. </li>
  154. </ul>
  155. </div>
  156. );
  157. };
  158. // 系统自检
  159. const SelfInspection = connect(({ eqSelfInspection, loading }) => ({
  160. autoReport: eqSelfInspection.autoReport,
  161. loading: loading.models['eqSelfInspection'],
  162. }))((props) => {
  163. const { autoReport, dispatch, loading } = props;
  164. const { projectId } = useParams();
  165. const renderStatus = () => {
  166. if (loading) return <LoadingOutlined />;
  167. if (autoReport.Status > 0) {
  168. return (
  169. <span className={styles.text} style={{ color: '#FE5850' }}>
  170. 异常
  171. </span>
  172. );
  173. }
  174. return (
  175. <span className={styles.text} style={{ color: '' }}>
  176. 正常
  177. </span>
  178. );
  179. };
  180. useEffect(() => {
  181. dispatch({
  182. type: 'eqSelfInspection/getAutoPatrol',
  183. payload: {
  184. projectId,
  185. },
  186. });
  187. }, []);
  188. return (
  189. <div
  190. className={styles.selfInspection}
  191. onClick={() => UnityAction.sendMsg('menuItem', '系统自检')}
  192. >
  193. <Title title="系统自检" />
  194. <div className={styles.selfCon}>
  195. <div className={styles.circle}>{renderStatus()}</div>
  196. <div className={styles.texting}>自检中</div>
  197. </div>
  198. <div className={styles.time}>
  199. {dayjs(autoReport.CreatedTime).format('YYYY-MM-DD HH:mm')}
  200. </div>
  201. {/* <div className={styles.insTag}>自检中</div> */}
  202. {/* <div className={styles.insStatus}>{renderStatus()}</div>
  203. <div className={styles.time} style={{ marginBottom: 30 }}>
  204. {dayjs(autoReport.CreatedTime).format('YYYY-MM-DD HH:mm')}
  205. </div> */}
  206. </div>
  207. );
  208. });
  209. // 能耗监测
  210. const Electric = (props) => {
  211. const { data } = props;
  212. const [open, setOpen] = useState(false);
  213. const content = (
  214. <div className={styles.popoverContent}>
  215. <p>理论值规则:</p>
  216. <p>分为高/中/低温3档,</p>
  217. <p>高温为≥25℃,低温为<20℃,中温为≥20且<25℃</p>
  218. <p>当前温度为近一天平均温度</p>
  219. </div>
  220. );
  221. return (
  222. <div
  223. className={styles.electric}
  224. onClick={() => UnityAction.sendMsg('menuItem', '能耗监测')}
  225. >
  226. <Title title={'能耗监测'} />
  227. <div
  228. className={`password-eye ${styles.eye} ${open ? 'open' : ''}`}
  229. onClick={(e) => {
  230. e.stopPropagation();
  231. setOpen(!open);
  232. }}
  233. ></div>
  234. <ul>
  235. <li>
  236. <div className={styles.value}>
  237. {open ? getValue(data?.elec_unit) : '*****'}
  238. </div>
  239. <div className={styles.btn1}>吨水电耗</div>
  240. </li>
  241. <li>
  242. <div className={styles.value}>
  243. {/* {open ? getValue(data?.elec) : '*****'} */}
  244. 12312312
  245. </div>
  246. <Popover title={content}>
  247. <div className={styles.btn1} onClick={(e) => e.stopPropagation()}>
  248. 理论值(KWh/m³)
  249. <i className={styles.iconAlert}></i>
  250. </div>
  251. </Popover>
  252. </li>
  253. </ul>
  254. </div>
  255. );
  256. };
  257. // 药耗监测
  258. const Medicine = () => {
  259. const { projectId } = useParams();
  260. const time = dayjs().format('YYYY-MM');
  261. const [open, setOpen] = useState(false);
  262. const { data } = useRequest(getComparisonData, {
  263. defaultParams: [
  264. {
  265. project_id: projectId,
  266. start: time,
  267. end: time,
  268. type: 1,
  269. flag: 1,
  270. },
  271. ],
  272. formatResult(res) {
  273. return res[0];
  274. },
  275. });
  276. const content = (
  277. <div className={styles.popoverContent}>
  278. <p>理论值规则:</p>
  279. <p>分为高/中/低温3档,</p>
  280. <p>高温为≥25℃,低温为<20℃,中温为≥20且<25℃</p>
  281. <p>当前温度为近一天平均温度</p>
  282. </div>
  283. );
  284. return (
  285. <div
  286. className={styles.medicine}
  287. onClick={() => UnityAction.sendMsg('menuItem', '药耗监测')}
  288. >
  289. <Title title={'药耗监测'} />
  290. <div
  291. className={`password-eye ${styles.eye} ${open ? 'open' : ''}`}
  292. onClick={(e) => {
  293. e.stopPropagation();
  294. setOpen(!open);
  295. }}
  296. ></div>
  297. <ul>
  298. <li>
  299. <div className={styles.valueLong}>
  300. {open ? data?.value?.toFixed(2) : '*****'}
  301. </div>
  302. <Popover title={content}>
  303. <div className={styles.btn1} onClick={(e) => e.stopPropagation()}>
  304. 当月吨水药成本(元)
  305. <i className={styles.iconAlert}></i>
  306. </div>
  307. </Popover>
  308. </li>
  309. </ul>
  310. </div>
  311. );
  312. };
  313. // 工艺监控
  314. const Scada = () => {
  315. const { projectId } = useParams();
  316. const { data } = useRequest(getScadaPage, {
  317. defaultParams: [{ project_id: projectId }],
  318. formatResult: (res) => {
  319. let domain = location.host.includes('pad.greentech.com.cn')
  320. ? 'https://metawant.greentech.com.cn/'
  321. : 'http://47.96.12.136:8788/';
  322. const token = getToken();
  323. const pageList = res?.filter((item) => item.hide);
  324. const urls = pageList.map(
  325. (item) =>
  326. `${domain}smart-water/scada/index.html#/3dview/${projectId}/${item.id}?JWT-TOKEN=${token}&hideTitle=true&pauseLoadRealTimeData=true`,
  327. );
  328. return urls.splice(0, 1);
  329. },
  330. });
  331. return (
  332. <div
  333. className={styles.scadaMain}
  334. onClick={() => UnityAction.sendMsg('menuItem', '工艺监控')}
  335. >
  336. <Title title="工艺监控" />
  337. <div style={{ width: '707px', height: '279px' }}>
  338. {data?.map((url) => (
  339. <iframe
  340. key={url}
  341. style={{
  342. width: '707px',
  343. height: '279px',
  344. borderRadius: '0 0 44px 0',
  345. }}
  346. frameborder="0"
  347. src={url}
  348. />
  349. ))}
  350. <div className={styles.mask}></div>
  351. </div>
  352. </div>
  353. );
  354. };
  355. // 待办事项
  356. const Backlog = (props) => {
  357. const { projectId } = useParams();
  358. const { data, loading } = useRequest(getPendingList, {
  359. defaultParams: [{ project_id: projectId }],
  360. });
  361. const handleClick = (item) => {
  362. if (item.type === 0) {
  363. // task
  364. UnityAction.sendMsg('OpenTaskModal', `mandate_id=${item.origin_id}`);
  365. } else {
  366. // order
  367. UnityAction.sendMsg(
  368. 'OpenWorkOrderModal',
  369. `order_id=${item.origin_id}&order_type=${item.origin_type}`,
  370. );
  371. }
  372. };
  373. return (
  374. <div
  375. className={styles.backlogMain}
  376. onClick={() => UnityAction.sendMsg('menuItem', '待办事项')}
  377. >
  378. <Title title={<div style={{ display: 'flex' }}>待办事项</div>} />
  379. <div className={styles.backlog}>
  380. <div>
  381. {data?.map((item) => (
  382. <div
  383. key={item.connect}
  384. className={styles.item}
  385. onClick={(e) => {
  386. e.stopPropagation();
  387. handleClick(item);
  388. }}
  389. >
  390. <div className={styles.createTime}>
  391. {dayjs(item.time).format('MM-DD HH:mm')}
  392. </div>
  393. <div className={styles.titleCon}>
  394. <div className={styles.point} />
  395. <div className={styles.titleText}>{item.title}</div>
  396. </div>
  397. <div className={styles.bottomCon}>{item.content}</div>
  398. </div>
  399. ))}
  400. </div>
  401. </div>
  402. </div>
  403. );
  404. };
  405. const Title = ({ title }) => {
  406. return (
  407. <div className={styles.titleContent}>
  408. <div className={styles.line} />
  409. <div className={styles.boxTitle}>{title}</div>
  410. </div>
  411. );
  412. };
  413. const Box = ({ title, children, onClick, small }) => {
  414. return (
  415. <div
  416. className={`${styles.box} ${small ? '' : styles.boxH}`}
  417. onClick={onClick}
  418. >
  419. <div className={styles.titleContent}>
  420. <div className={styles.line} />
  421. <div className={styles.boxTitle}>{title}</div>
  422. </div>
  423. {/* <span className={styles.boxTitle}>
  424. <div className={styles.line}></div>
  425. {title}
  426. </span> */}
  427. {children}
  428. </div>
  429. );
  430. };
  431. export default HomePage;