Statistics.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. import PageContent from '@/components/PageContent';
  2. import PageTitle from '@/components/PageTitle';
  3. import {
  4. patrolOverview,
  5. patrolOverviewLine,
  6. patrolOverviewPie,
  7. } from '@/services/eqSelfInspection';
  8. import { useParams, useRequest } from '@umijs/max';
  9. import { Spin } from 'antd';
  10. import dayjs from 'dayjs';
  11. import * as echarts from 'echarts';
  12. import { useEffect, useRef } from 'react';
  13. import styles from './index.less';
  14. const defaultTime = {
  15. s_time: dayjs().subtract(7, 'days').format('YYYY-MM-DD'),
  16. e_time: dayjs().format('YYYY-MM-DD'),
  17. };
  18. const Statistics = (props) => {
  19. const { projectId } = useParams();
  20. const lineDomRef = useRef(null);
  21. const LineChartRef = useRef(null);
  22. const pieDomRef = useRef(null);
  23. const pieChartRef = useRef(null);
  24. const renderChart = () => {
  25. if (!LineChartRef.current || !pieChartRef.current) return;
  26. if (!lineData || !pieData) return;
  27. LineChartRef.current.clear();
  28. const lineOptions = getLineOption(
  29. lineData?.time,
  30. lineData?.data,
  31. '系统自测异常统计',
  32. );
  33. // 设置图表配置项
  34. LineChartRef.current.setOption(lineOptions);
  35. pieChartRef.current.clear();
  36. const pieOptions = getPieOption(pieData, '异常类型统计');
  37. // 设置图表配置项
  38. pieChartRef.current.setOption(pieOptions);
  39. // 构建图表的配置项
  40. };
  41. const {
  42. data: lineData,
  43. run,
  44. loading,
  45. } = useRequest(patrolOverviewLine, {
  46. defaultParams: [
  47. {
  48. projectId: Number(projectId),
  49. ...defaultTime,
  50. },
  51. ],
  52. formatResult(resData) {
  53. let data = [];
  54. let time = [];
  55. resData?.data?.forEach((item) => {
  56. data.push(item.val);
  57. time.push(dayjs(item.key).format('MM-DD'));
  58. });
  59. return { data, time };
  60. },
  61. });
  62. const {
  63. data: pieData,
  64. run: pieRun,
  65. loading: pieLoading,
  66. } = useRequest(patrolOverviewPie, {
  67. defaultParams: [
  68. {
  69. projectId: Number(projectId),
  70. ...defaultTime,
  71. },
  72. ],
  73. formatResult(resData) {
  74. return resData?.data?.map((item) => {
  75. return { name: item.key, value: item.val };
  76. });
  77. },
  78. });
  79. const { data: overviewData, loading: overviewLoading } = useRequest(
  80. patrolOverview,
  81. {
  82. defaultParams: [
  83. {
  84. projectId: Number(projectId),
  85. },
  86. ],
  87. formatResult(resData) {
  88. return [
  89. { num: resData?.data?.today_check_num, label: '今日自检次数' },
  90. { num: resData?.data?.today_exception_num, label: '今日异常次数' },
  91. { num: resData?.data?.all_check_num, label: '累计自检次数' },
  92. { num: resData?.data?.all_check_day, label: '累计自检天数' },
  93. ];
  94. },
  95. },
  96. );
  97. const getChartData = ({ s_time, e_time }) => {
  98. run({ projectId: Number(projectId), s_time, e_time });
  99. pieRun({ projectId: Number(projectId), s_time, e_time });
  100. };
  101. const onRadioChange = (e) => {
  102. console.log(e);
  103. let params = { s_time: defaultTime.s_time, e_time: defaultTime.e_time };
  104. if (e == 'month')
  105. params = {
  106. s_time: dayjs().subtract(1, 'month').format('YYYY-MM-DD'),
  107. e_time: dayjs().format('YYYY-MM-DD'),
  108. };
  109. else if (e == 'year')
  110. params = {
  111. s_time: dayjs().subtract(1, 'year').format('YYYY-MM-DD'),
  112. e_time: dayjs().format('YYYY-MM-DD'),
  113. };
  114. getChartData(params);
  115. };
  116. useEffect(() => {
  117. renderChart();
  118. }, [lineData, pieData]);
  119. useEffect(() => {
  120. LineChartRef.current = echarts.init(lineDomRef.current);
  121. pieChartRef.current = echarts.init(pieDomRef.current);
  122. return () => {
  123. LineChartRef.current.dispose();
  124. pieChartRef.current.dispose();
  125. };
  126. }, []);
  127. return (
  128. <PageContent closeable={false}>
  129. <PageTitle returnable>系统自检统计</PageTitle>
  130. <div
  131. className={`${styles.itemMain2} card-box`}
  132. style={{ padding: '0.44rem 0' }}
  133. >
  134. <div style={{ display: 'flex' }}>
  135. {overviewData?.map((item) => (
  136. <Text num={item.num} label={item.label} />
  137. ))}
  138. </div>
  139. </div>
  140. <div className={`${styles.itemMain2} card-box`}>
  141. <div className={styles.tabs}>近一周数据统计</div>
  142. <Spin spinning={loading}>
  143. <div
  144. ref={lineDomRef}
  145. style={{ height: '4rem', margin: '0.1rem 0 0.1rem 0' }}
  146. />
  147. </Spin>
  148. </div>
  149. <div className={`${styles.itemMain2} card-box`}>
  150. <Spin spinning={pieLoading}>
  151. <div
  152. ref={pieDomRef}
  153. style={{ height: '4rem', margin: '0.1rem 0 0.1rem 0' }}
  154. />
  155. </Spin>
  156. </div>
  157. </PageContent>
  158. );
  159. };
  160. export default Statistics;
  161. const Text = (props) => {
  162. const { num, label } = props;
  163. return (
  164. <div className={styles.statisticsText}>
  165. <div className={styles.num}>{num}</div>
  166. <div className={styles.label} style={{ fontSize: '0.22rem' }}>
  167. {label}
  168. </div>
  169. </div>
  170. );
  171. };
  172. const getLineOption = (time, chartData, name) => {
  173. const y1Max = getMax(chartData);
  174. const dataType = 'line';
  175. const option = {
  176. color: [
  177. '#5470c6',
  178. '#91cc75',
  179. '#fac858',
  180. '#ee6666',
  181. '#73c0de',
  182. '#3ba272',
  183. '#fc8452',
  184. '#9a60b4',
  185. '#ea7ccc',
  186. ],
  187. tooltip: {
  188. trigger: 'axis',
  189. axisPointer: {
  190. type: 'cross',
  191. crossStyle: {
  192. color: '#333',
  193. },
  194. },
  195. textStyle: {
  196. fontSize: 18,
  197. },
  198. },
  199. // grid: {
  200. // bottom: 30,
  201. // left: 60,
  202. // right: 30,
  203. // },
  204. xAxis: {
  205. type: 'category',
  206. axisPointer: {
  207. type: 'shadow',
  208. },
  209. axisLine: {
  210. lineStyle: {
  211. color: '#555',
  212. },
  213. },
  214. axisLabel: {
  215. fontSize: 12,
  216. },
  217. data: time,
  218. },
  219. yAxis: [
  220. {
  221. type: 'value',
  222. top: 20,
  223. // max: y1Max,
  224. // interval: y1Max / 5,
  225. // splitNumber: 5,
  226. // nameTextStyle: {
  227. // color: '#fff',
  228. // fontSize: 16,
  229. // padding: [0, 0, 20, 0],
  230. // },
  231. axisLabel: {
  232. color: '#555',
  233. },
  234. axisLabel: {
  235. fontSize: 12,
  236. color: '#555',
  237. },
  238. axisLine: {
  239. show: false,
  240. },
  241. splitLine: {
  242. lineStyle: {
  243. type: 'dashed',
  244. },
  245. },
  246. },
  247. ],
  248. series: [
  249. {
  250. data: chartData,
  251. type: dataType,
  252. name: '次数',
  253. yAxisIndex: 0,
  254. smooth: true,
  255. },
  256. ],
  257. legend: {
  258. textStyle: {
  259. color: '#555',
  260. fontSize: 14,
  261. },
  262. lineStyle: {},
  263. },
  264. title: {
  265. text: name,
  266. top: '88%',
  267. left: '50%',
  268. textAlign: 'center',
  269. textStyle: {
  270. color: '#555',
  271. fontWeight: 'normal',
  272. fontSize: 14,
  273. },
  274. },
  275. // textStyle: {
  276. // fontSize: 50
  277. // }
  278. };
  279. // if (chartData2) {
  280. // const y2Max = getMax(chartData2);
  281. // option.yAxis.push({
  282. // type: 'value',
  283. // max: y2Max,
  284. // interval: y2Max / 5,
  285. // splitNumber: 5,
  286. // top: 20,
  287. // position: 'right',
  288. // nameTextStyle: {
  289. // color: '#fff',
  290. // fontSize: 16,
  291. // // align: 'left',
  292. // padding: [0, 0, 20, 0],
  293. // },
  294. // axisLabel: {
  295. // color: '#fff',
  296. // },
  297. // axisLine: {
  298. // show: false,
  299. // },
  300. // splitLine: {
  301. // lineStyle: {
  302. // type: 'dashed',
  303. // },
  304. // },
  305. // });
  306. // option.series.push({
  307. // data: chartData2,
  308. // type: 'line',
  309. // name: active,
  310. // yAxisIndex: 1,
  311. // });
  312. // }
  313. return option;
  314. };
  315. const getPieOption = (chartData, name) => {
  316. const option = {
  317. title: {
  318. text: name,
  319. top: '88%',
  320. left: '50%',
  321. textAlign: 'center',
  322. textStyle: {
  323. color: '#555',
  324. fontWeight: 'normal',
  325. fontSize: 14,
  326. },
  327. },
  328. color: [
  329. '#5470c6',
  330. '#91cc75',
  331. '#fac858',
  332. '#ee6666',
  333. '#73c0de',
  334. '#3ba272',
  335. '#fc8452',
  336. '#9a60b4',
  337. '#ea7ccc',
  338. ],
  339. tooltip: {
  340. trigger: 'item',
  341. textStyle: {
  342. fontSize: 18,
  343. },
  344. },
  345. legend: {
  346. orient: 'horizontal',
  347. // left: 'left',
  348. textStyle: {
  349. color: '#555',
  350. fontSize: 14,
  351. },
  352. },
  353. series: [
  354. {
  355. type: 'pie',
  356. radius: '50%',
  357. data: chartData,
  358. emphasis: {
  359. itemStyle: {
  360. shadowBlur: 10,
  361. shadowOffsetX: 0,
  362. shadowColor: 'rgba(0, 0, 0, 0.5)',
  363. },
  364. },
  365. },
  366. ],
  367. };
  368. return option;
  369. };
  370. function getMax(arr) {
  371. const max = Math.max(...arr);
  372. if (max == 100) return 100;
  373. const exponent = Math.floor(Math.log10(max));
  374. const base = Math.pow(10, exponent);
  375. const remainder = max % base;
  376. const maxRoundUp = max - remainder + base;
  377. const maxFixed = maxRoundUp.toFixed(1); // 将最大值的小数位数限制为 1
  378. return Number(maxFixed); // 将字符串转换为数字并返回
  379. }