index.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. import ModuleTitle from '@/components/ManagementPage/moduleTitle';
  2. import PageContent from '@/components/PageContent';
  3. import { queryWorkReport } from '@/services/smartReport';
  4. import { LeftOutlined } from '@ant-design/icons';
  5. import { useNavigate, useParams, useRequest } from '@umijs/max';
  6. import { ConfigProvider, DatePicker, Select, Spin } from 'antd';
  7. import zhCN from 'antd/es/locale/zh_CN';
  8. import dayjs from 'dayjs';
  9. import * as echarts from 'echarts';
  10. import { useEffect, useRef, useState } from 'react';
  11. import styles from './index.less';
  12. const { RangePicker } = DatePicker;
  13. const SmartReport = () => {
  14. const navigate = useNavigate();
  15. const { projectId } = useParams();
  16. const FORMAT = 'YYYY-MM-DD';
  17. const [showRange, setShowRange] = useState(false);
  18. const [date, setDate] = useState({
  19. stime: dayjs().subtract(1, 'week').format(FORMAT),
  20. etime: dayjs().format(FORMAT),
  21. });
  22. const eqDomRef = useRef(null);
  23. const eqChartRef = useRef(null);
  24. const taskDomRef = useRef(null);
  25. const taskChartRef = useRef(null);
  26. const workDomRef = useRef(null);
  27. const workChartRef = useRef(null);
  28. const workScoreDomRef = useRef(null);
  29. const workScoreChartRef = useRef(null);
  30. // const defaultData = {
  31. // electricity: '1111',
  32. // in_water: '22222',
  33. // maintain_record: '333',
  34. // medicine: '444',
  35. // out_water: '666',
  36. // push_complete_task: '777',
  37. // push_complete_task_per: '888',
  38. // push_task: '555',
  39. // repair_record: '999',
  40. // self_inspection_abnormal_task: '1212',
  41. // self_inspection_normal_task: '13123',
  42. // self_inspection_task: '1414',
  43. // water_electricity: '1515',
  44. // water_medicine: '1616',
  45. // work_order_complete_task: '1717',
  46. // work_order_complete_task_per: '80',
  47. // work_order_task: '123',
  48. // patrol_safe: 2,
  49. // patrol_section: 3,
  50. // push_optimize_task: 6,
  51. // push_complete_task: 4,
  52. // eqData: [
  53. // { name: '安全隐患', value: 2 },
  54. // { name: '工艺异常', value: 3 },
  55. // { name: '设备异常', value: 4 },
  56. // ],
  57. // mandate_type_con: 1,
  58. // mandate_type_group: 2,
  59. // mandate_type_pat: 3,
  60. // mandate_type_pro: 4,
  61. // taskData: [
  62. // { name: '工况任务', value: 2 },
  63. // { name: '集团任务', value: 3 },
  64. // { name: '系统自检', value: 4 },
  65. // { name: '生产任务', value: 5 },
  66. // ],
  67. // chart_check: 1,
  68. // chart_part: 2,
  69. // chart_section: 3,
  70. // repair_record: 4,
  71. // maintain_record: 5,
  72. // patrol_mandate_record: 6,
  73. // reagent_record: 7,
  74. // workOrderData: [
  75. // { name: '盘点', value: 2 },
  76. // { name: '备品备件', value: 3 },
  77. // { name: '工艺工单', value: 4 },
  78. // { name: '维修工单', value: 5 },
  79. // { name: '保养工单', value: 5 },
  80. // { name: '巡检工单', value: 5 },
  81. // { name: '加药工单', value: 5 },
  82. // ],
  83. // con_level_five: 6, //较差
  84. // con_level_four: 1, //一般
  85. // con_level_one: 2, //优秀
  86. // con_level_three: 3, //较好
  87. // con_level_two: 4, //良好
  88. // workScoreData: [
  89. // { name: '较差', value: 2 },
  90. // { name: '一般', value: 3 },
  91. // { name: '优秀', value: 4 },
  92. // { name: '较好', value: 5 },
  93. // { name: '良好', value: 4 },
  94. // ],
  95. // };
  96. const {
  97. data = {},
  98. run,
  99. loading,
  100. } = useRequest(
  101. (date) =>
  102. queryWorkReport({
  103. project_id: projectId,
  104. ...date,
  105. }),
  106. {
  107. defaultParams: [{ project_id: projectId, ...date }],
  108. formatResult: (res) => {
  109. const data = res.data;
  110. return {
  111. ...data,
  112. eqData: [
  113. { name: '安全隐患', value: data.patrol_safe },
  114. { name: '工艺异常', value: data.patrol_section },
  115. { name: '设备异常', value: data.push_complete_task },
  116. ],
  117. taskData: [
  118. { name: '工况任务', value: data.mandate_type_con },
  119. { name: '集团任务', value: data.mandate_type_group },
  120. { name: '系统自检', value: data.mandate_type_pat },
  121. { name: '生产任务', value: data.mandate_type_pro },
  122. ],
  123. workOrderData: [
  124. { name: '盘点', value: data.chart_check },
  125. { name: '备品备件', value: data.chart_part },
  126. { name: '工艺工单', value: data.chart_section },
  127. { name: '维修工单', value: data.repair_record },
  128. { name: '保养工单', value: data.maintain_record },
  129. { name: '巡检工单', value: data.patrol_mandate_record },
  130. { name: '加药工单', value: data.reagent_record },
  131. ],
  132. workScoreData: [
  133. { name: '较差', value: data.con_level_five },
  134. { name: '一般', value: data.con_level_four },
  135. { name: '优秀', value: data.con_level_one },
  136. { name: '较好', value: data.con_level_three },
  137. { name: '良好', value: data.con_level_two },
  138. ],
  139. };
  140. },
  141. },
  142. );
  143. const handleChange = (value) => {
  144. const date = { ...date };
  145. switch (value) {
  146. case '1':
  147. date.stime = dayjs().subtract(1, 'week').format(FORMAT);
  148. date.etime = dayjs().format(FORMAT);
  149. setDate(date);
  150. setShowRange(false);
  151. run(date);
  152. break;
  153. case '2':
  154. date.stime = dayjs().subtract(1, 'month').format(FORMAT);
  155. date.etime = dayjs().format(FORMAT);
  156. setDate(date);
  157. setShowRange(false);
  158. run(date);
  159. break;
  160. case '3':
  161. setShowRange(true);
  162. break;
  163. }
  164. };
  165. const {
  166. ele_65,
  167. ele_66,
  168. electricity,
  169. in_water,
  170. maintain_record,
  171. medicine,
  172. out_water,
  173. push_optimize_task,
  174. push_complete_task,
  175. push_complete_task_per,
  176. push_task,
  177. repair_record,
  178. self_inspection_abnormal_task,
  179. self_inspection_normal_task,
  180. self_inspection_task,
  181. water_electricity,
  182. water_medicine,
  183. work_order_complete_task,
  184. work_order_complete_task_per,
  185. work_order_task,
  186. } = data;
  187. useEffect(() => {
  188. initData();
  189. }, [data]);
  190. useEffect(() => {
  191. eqChartRef.current = echarts.init(eqDomRef.current);
  192. taskChartRef.current = echarts.init(taskDomRef.current);
  193. workChartRef.current = echarts.init(workDomRef.current);
  194. workScoreChartRef.current = echarts.init(workScoreDomRef.current);
  195. return () => {
  196. eqChartRef.current.dispose();
  197. taskChartRef.current.dispose();
  198. workChartRef.current.dispose();
  199. workScoreChartRef.current.dispose();
  200. };
  201. }, []);
  202. const initData = () => {
  203. const eqOption = getPieOption(data.eqData, '异常类型统计');
  204. if (eqChartRef.current) eqChartRef.current.setOption(eqOption);
  205. const taskOption = getPieOption(data.taskData, '任务类型统计');
  206. if (taskChartRef.current) taskChartRef.current.setOption(taskOption);
  207. const workOption = getPieOption(data.workOrderData, '工单类型统计');
  208. if (workChartRef.current) workChartRef.current.setOption(workOption);
  209. const workScoreOption = getPieOption(data.workScoreData, '工单类型统计');
  210. if (workScoreChartRef.current)
  211. workScoreChartRef.current.setOption(workScoreOption);
  212. };
  213. const onChange = (value) => {
  214. if (!value) return;
  215. const date = { ...date };
  216. date.stime = value[0].format(FORMAT);
  217. date.etime = value[1].format(FORMAT);
  218. run(date);
  219. setDate(date);
  220. };
  221. const handleOnClick = () => {
  222. history.back();
  223. };
  224. return (
  225. <PageContent closeable={false}>
  226. <ConfigProvider locale={zhCN}>
  227. <div className={styles.head}>
  228. <div>
  229. <div className={styles.name}>
  230. <LeftOutlined
  231. onClick={handleOnClick}
  232. style={{ fontSize: 36, cursor: 'pointer', marginRight: '20px' }}
  233. />
  234. 智慧运营报告
  235. </div>
  236. <div className={styles.photo}>
  237. {dayjs(date.stime).format('MM月DD日')}-
  238. {dayjs(date.etime).format('MM月DD日')}
  239. </div>
  240. </div>
  241. <div className={styles.headRight}>
  242. <div>
  243. 时间:
  244. <Select
  245. className={styles.headRightSelect}
  246. defaultValue="1"
  247. style={{ width: 180 }}
  248. onChange={handleChange}
  249. popupClassName={styles.headRightSelect}
  250. options={[
  251. {
  252. value: '1',
  253. label: '近7天',
  254. },
  255. {
  256. value: '2',
  257. label: '近30天',
  258. },
  259. {
  260. value: '3',
  261. label: '自定义时间',
  262. },
  263. ]}
  264. />
  265. </div>
  266. <div>{showRange && <RangePicker onChange={onChange} />}</div>
  267. </div>
  268. </div>
  269. <Spin spinning={loading}>
  270. <div className={styles.box}>
  271. <div className={styles.left}>概览</div>
  272. <div className={styles.title}>无锡锡山水厂</div>
  273. <div className={styles.content}>
  274. {/* <div className={styles.item}>智慧运营天数:{}天</div>
  275. <div className={styles.item}>智慧运营节省金额:{}元</div> */}
  276. <div className={styles.item}>累积进水:{in_water}</div>
  277. <div className={styles.item}>累积出水:{out_water}</div>
  278. <div className={styles.item}>吨水能耗:{water_electricity}</div>
  279. <div className={styles.item}>吨水药耗:{water_medicine}元</div>
  280. <div className={styles.item}>
  281. 系统自检次数:{self_inspection_task}次
  282. </div>
  283. <div className={styles.item}>
  284. 优化建议: {push_optimize_task}条
  285. </div>
  286. <div className={styles.item}>
  287. 任务完成:{push_complete_task}个
  288. </div>
  289. <div className={styles.item}>
  290. 工单完成:{work_order_complete_task}个
  291. </div>
  292. <div className={styles.item}>设备维修:{repair_record}个</div>
  293. <div className={styles.item}>设备保养:{maintain_record}个</div>
  294. </div>
  295. </div>
  296. <div className={styles.box}>
  297. <ModuleTitle title="水量" />
  298. <div className={styles.content}>
  299. <div className={styles.item}>累积进水:{in_water}</div>
  300. <div className={styles.item}>累积出水:{out_water}</div>
  301. </div>
  302. </div>
  303. <div className={styles.box}>
  304. <ModuleTitle title="能耗" />
  305. <div className={styles.content}>
  306. <div className={styles.item}>吨水能耗:{water_electricity}</div>
  307. <div className={styles.item}>累积耗能量:{electricity}</div>
  308. </div>
  309. </div>
  310. <div className={styles.box}>
  311. <ModuleTitle title="药耗" />
  312. <div className={styles.content}>
  313. <div className={styles.item}>吨水药耗:{water_medicine}</div>
  314. <div className={styles.item}>累积用药量:{medicine}</div>
  315. </div>
  316. </div>
  317. <div className={styles.box}>
  318. <ModuleTitle title="系统自检" />
  319. <div className={styles.threeContent}>
  320. <div className={styles.numItem}>
  321. <div>{self_inspection_task}</div>
  322. <div>自检次数</div>
  323. </div>
  324. <div className={styles.numItem}>
  325. <div>{self_inspection_abnormal_task}</div>
  326. <div>异常次数</div>
  327. </div>
  328. <div className={styles.numItem}>
  329. <div>{self_inspection_normal_task}</div>
  330. <div>正常次数</div>
  331. </div>
  332. </div>
  333. <div
  334. ref={eqDomRef}
  335. style={{ height: '340px', margin: '10px 0 10px 0' }}
  336. ></div>
  337. {/* <div>异常类型统计(设备异常、工艺异常、安全隐患异常)</div> */}
  338. </div>
  339. <div className={styles.box}>
  340. <ModuleTitle title="智慧运营" />
  341. <div style={{ padding: '20px 20px 0 20px' }}>
  342. <div className={styles.smartText}>
  343. 优化条数:{push_optimize_task}条
  344. </div>
  345. <div className={styles.smartText}>超滤能耗:{ele_65}</div>
  346. <div className={styles.smartText}>反渗透能耗:{ele_66}</div>
  347. </div>
  348. <div
  349. ref={workScoreDomRef}
  350. style={{ height: '340px', margin: '10px 0 10px 0' }}
  351. ></div>
  352. </div>
  353. <div className={styles.box}>
  354. <ModuleTitle title="任务工单" />
  355. <div className={styles.content}>
  356. <div className={styles.item}>任务数量:{push_task}</div>
  357. <div className={styles.item}>工单数量:{work_order_task}</div>
  358. <div className={styles.item}>
  359. 任务完成数量:{push_complete_task}
  360. </div>
  361. <div className={styles.item}>
  362. 工单完成数量:{work_order_complete_task}
  363. </div>
  364. <div className={styles.item}>
  365. 任务完成率:{push_complete_task_per}%
  366. </div>
  367. <div className={styles.item}>
  368. 工单完成率:{work_order_complete_task_per}%
  369. </div>
  370. <div className={styles.item}>
  371. <div ref={taskDomRef} style={{ height: '300px' }}></div>
  372. </div>
  373. <div className={styles.item}>
  374. <div ref={workDomRef} style={{ height: '300px' }}></div>
  375. </div>
  376. </div>
  377. </div>
  378. <div className={styles.box}>
  379. <ModuleTitle title="设备维修保养" />
  380. <div className={styles.content}>
  381. <div className={styles.item}>维修数量:{repair_record}</div>
  382. <div className={styles.item}>保养数量:{maintain_record}</div>
  383. </div>
  384. </div>
  385. </Spin>
  386. </ConfigProvider>
  387. </PageContent>
  388. );
  389. };
  390. export default SmartReport;
  391. const getPieOption = (chartData, name) => {
  392. const option = {
  393. title: {
  394. text: name,
  395. top: '92%',
  396. left: '50%',
  397. textAlign: 'center',
  398. textStyle: {
  399. color: '#000000',
  400. fontWeight: 'normal',
  401. fontSize: 18,
  402. },
  403. },
  404. color: [
  405. '#5470c6',
  406. '#91cc75',
  407. '#fac858',
  408. '#ee6666',
  409. '#73c0de',
  410. '#3ba272',
  411. '#fc8452',
  412. '#9a60b4',
  413. '#ea7ccc',
  414. ],
  415. tooltip: {
  416. trigger: 'item',
  417. },
  418. legend: {
  419. orient: 'horizontal',
  420. // left: 'left',
  421. textStyle: {
  422. color: '#000000',
  423. fontSize: 18,
  424. },
  425. },
  426. series: [
  427. {
  428. type: 'pie',
  429. radius: '50%',
  430. data: chartData,
  431. emphasis: {
  432. itemStyle: {
  433. shadowBlur: 10,
  434. shadowOffsetX: 0,
  435. shadowColor: 'rgba(0, 0, 0, 0.5)',
  436. },
  437. },
  438. },
  439. ],
  440. };
  441. return option;
  442. };