index.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. import React, { useEffect, useState } from 'react';
  2. import styles from './index.less';
  3. import * as datav from '@jiaminghi/data-view-react';
  4. import dataBoardTitle from '../../../public/assets/dataBoardTitle.png';
  5. import decoration_two from '../../../public/assets/decoration_two.png';
  6. import decoration_three from '../../../public/assets/decoration_three.png';
  7. import decoration_five from '../../../public/assets/decoration_five.png';
  8. import MapComponent from '@/pages/DataBoard/mapComponent';
  9. import border from '../../../public/assets/border.png';
  10. import dataBoardBg_two from '../../../public/assets/dataBoardBg_two.png';
  11. import LineChartsCommon from '@/pages/DataBoard/lineChartsCommon';
  12. import Slider from 'react-slick';
  13. import SliderData from '@/pages/DataBoard/sliderData';
  14. import AreaDeviceData from '@/pages/DataBoard/areaDeviceData';
  15. import 'slick-carousel/slick/slick.css';
  16. import 'slick-carousel/slick/slick-theme.css';
  17. import {
  18. queryAreaData,
  19. queryDeviceChart,
  20. queryDeviceData,
  21. queryDeviceRunTime,
  22. queryHomeInfo,
  23. queryUserChart,
  24. queryUserData,
  25. } from '@/services/dataBoardService';
  26. import PreloadImage from '@/components/PreloadImage';
  27. // 数据大屏
  28. const DataBoard: React.FC = () => {
  29. const [deviceTypeValue, setDeviceTypeValue] = useState(1);
  30. const [userTypeValue, setUserTypeValue] = useState(1);
  31. const [userNum, setUserNum] = useState({
  32. number: [0],
  33. content: '{nt}',
  34. style: {
  35. fontSize: 28,
  36. fill: '#2ff8ff',
  37. },
  38. });
  39. const [homeNum, setHomeNum] = useState({
  40. number: [0],
  41. content: '{nt}',
  42. style: {
  43. fontSize: 28,
  44. fill: '#2ff8ff',
  45. },
  46. });
  47. const [onlineDeviceNum, setOnlineDeviceNum] = useState({
  48. number: [0],
  49. content: '{nt}',
  50. style: {
  51. fontSize: 20,
  52. fill: '#2ff8ff',
  53. },
  54. });
  55. const [offlineDeviceNum, setOfflineDeviceNum] = useState({
  56. number: [0],
  57. content: '{nt}',
  58. style: {
  59. fontSize: 20,
  60. fill: '#2ff8ff',
  61. },
  62. });
  63. const [deviceNum, setDeviceNum] = useState({
  64. number: [0],
  65. content: '{nt}',
  66. style: {
  67. fontSize: 20,
  68. fill: '#2ff8ff',
  69. },
  70. });
  71. const [errorDeviceNum, setErrorDeviceNum] = useState({
  72. number: [0],
  73. content: '{nt}',
  74. style: {
  75. fontSize: 20,
  76. fill: '#2ff8ff',
  77. },
  78. });
  79. const [masterControlNum, setMasterControlNum] = useState({
  80. number: [0],
  81. content: '{nt}',
  82. style: {
  83. fontSize: 20,
  84. fill: '#2ff8ff',
  85. },
  86. });
  87. const [subControlNum, setSubControlNum] = useState({
  88. number: [0],
  89. content: '{nt}',
  90. style: {
  91. fontSize: 20,
  92. fill: '#2ff8ff',
  93. },
  94. });
  95. const [deviceStatistics, setDeviceStatistics] = useState({
  96. number: [0],
  97. content: '{nt}',
  98. style: {
  99. fontSize: 33,
  100. fill: '#08c7f1',
  101. },
  102. });
  103. const [allRunTime, setAllRunTime] = useState({
  104. number: [0],
  105. content: '{nt}',
  106. toFixed: 2,
  107. style: {
  108. fontSize: 33,
  109. fill: '#ffb026',
  110. },
  111. });
  112. const [todayRunTime, setTodayRunTime] = useState({
  113. number: [0],
  114. content: '{nt}',
  115. toFixed: 2,
  116. style: {
  117. fontSize: 33,
  118. fill: '#0dde79',
  119. },
  120. });
  121. const [homeInfo, setHomeInfo] = useState([]);
  122. const [userChartsData, setUserChartsData] = useState([]);
  123. const [deviceChartsData, setDeviceChartsData] = useState([]);
  124. const [areaDeviceList, setAreaDeviceList] = useState([]);
  125. const settings = {
  126. dots: false, //圆点显示(false隐藏)
  127. infinite: true, //无限的环绕内容
  128. autoplay: true, //自动播放,速度默认为(3000毫秒)
  129. speed: 3000, //自动播放速度(毫秒)
  130. slidesToShow: 2, //在一帧中显示2张卡片
  131. slidesToScroll: 1, //一次滚动2张卡片
  132. variableWidth: true,
  133. };
  134. // 设备统计
  135. const getDeviceData = () => {
  136. queryDeviceData().then((res) => {
  137. if (res?.code === 0) {
  138. // 设备数
  139. setDeviceNum((data) => {
  140. data.number = [res.data.device_count * 15]; // 暂时乘以15
  141. return { ...data };
  142. });
  143. // 故障设备数
  144. setErrorDeviceNum((data) => {
  145. data.number = [res.data.failure_device];
  146. return { ...data };
  147. });
  148. // 主控数量
  149. setMasterControlNum((data) => {
  150. // data.number = [res.data.master_count];
  151. data.number = [150]; // 假数据 回头删
  152. return { ...data };
  153. });
  154. // 分控数量
  155. setSubControlNum((data) => {
  156. // data.number = [res.data.sub_count];
  157. data.number = [150 * 3]; // 假数据 回头删
  158. return { ...data };
  159. });
  160. // 设备数统计
  161. setDeviceStatistics((data) => {
  162. data.number = [res.data.device_count * 15]; // 假数据 回头删
  163. return { ...data };
  164. });
  165. }
  166. });
  167. };
  168. // 用户数据统计
  169. const userNumData = () => {
  170. queryUserData().then((res) => {
  171. if (res?.code === 0) {
  172. // 注册用户数
  173. setUserNum((data) => {
  174. data.number = [res.data.user_count * 15]; // 暂时乘以15
  175. return { ...data };
  176. });
  177. // 家庭数量
  178. setHomeNum((data) => {
  179. data.number = [res.data.home_count * 15]; // 假数据 回头删
  180. return { ...data };
  181. });
  182. // 在线设备数
  183. setOnlineDeviceNum((data) => {
  184. // data.number = [res.data.device_online];
  185. data.number = [150];
  186. return { ...data };
  187. });
  188. // 离线设备数
  189. setOfflineDeviceNum((data) => {
  190. // data.number = [res.data.device_offline];
  191. data.number = [0];
  192. return { ...data };
  193. });
  194. }
  195. });
  196. };
  197. // 设备运行时长统计
  198. const getRunTime = () => {
  199. queryDeviceRunTime().then((res) => {
  200. if (res.code === 0) {
  201. setAllRunTime((data) => {
  202. data.number = [res.data.total_run_time];
  203. return { ...data };
  204. });
  205. setTodayRunTime((data) => {
  206. data.number = [res.data.day_run_time];
  207. return { ...data };
  208. });
  209. }
  210. });
  211. };
  212. //地区设备数量Top5
  213. const getAreaData = () => {
  214. queryAreaData({ region_type: '1' }).then((res) => {
  215. if (res?.code === 0) {
  216. // 假数据 回头删
  217. const arr: any = [
  218. {
  219. name: '济南',
  220. value: 27,
  221. },
  222. {
  223. name: '菏泽',
  224. value: 19,
  225. },
  226. {
  227. name: '泰安',
  228. value: 16,
  229. },
  230. {
  231. name: '济宁',
  232. value: 10,
  233. },
  234. {
  235. name: '潍坊',
  236. value: 10,
  237. },
  238. ];
  239. setAreaDeviceList(arr);
  240. }
  241. });
  242. };
  243. // 设备增长趋势
  244. const deviceCharts = () => {
  245. queryDeviceChart({ time_type: deviceTypeValue }).then((res) => {
  246. if (res?.code === 0) {
  247. // 假数据 回头删
  248. const arr = res.data;
  249. for (let i = 0; i < arr.length; i++) {
  250. arr[i].value = arr[i].value * 15;
  251. }
  252. setDeviceChartsData(res.data);
  253. }
  254. });
  255. };
  256. // 用户增长趋势
  257. const userCharts = () => {
  258. queryUserChart({ time_type: userTypeValue }).then((res) => {
  259. if (res?.code === 0) {
  260. // 假数据 回头删
  261. const arr = res.data;
  262. for (let i = 0; i < arr.length; i++) {
  263. arr[i].value = arr[i].value * 15;
  264. }
  265. setUserChartsData(res.data);
  266. }
  267. });
  268. };
  269. // 查询家列表
  270. const getHomeListInfo = () => {
  271. queryHomeInfo().then((res) => {
  272. if (res.code === 0) {
  273. setHomeInfo(res.data);
  274. }
  275. });
  276. };
  277. useEffect(() => {
  278. // 组件挂载时立即获取一次数据
  279. getAreaData();
  280. userNumData();
  281. getDeviceData();
  282. getRunTime();
  283. deviceCharts();
  284. userCharts();
  285. getHomeListInfo();
  286. // 定义一个函数,用于设置定时器
  287. const timer = setInterval(() => {
  288. getAreaData();
  289. userNumData();
  290. getDeviceData();
  291. }, 10 * 60 * 1000); // 10分钟,单位为毫秒
  292. // 两秒刷新一次顶部的时长数据
  293. const timer_two = setInterval(() => {
  294. getRunTime();
  295. }, 1000 * 2);
  296. // 组件卸载时清除定时器
  297. return () => {
  298. clearInterval(timer);
  299. clearInterval(timer_two);
  300. };
  301. }, []); // 传入一个空数组作为第二个参数,确保只在组件挂载和卸载时执行一次
  302. // 设备增长趋势切换
  303. useEffect(() => {
  304. deviceCharts();
  305. const interval = setInterval(() => {
  306. setDeviceTypeValue((prevParam) => (prevParam === 1 ? 2 : 1));
  307. }, 1000 * 10);
  308. return () => clearInterval(interval);
  309. }, [deviceTypeValue]);
  310. // 用户增长趋势切换
  311. useEffect(() => {
  312. userCharts();
  313. const interval = setInterval(() => {
  314. setUserTypeValue((prevParam) => (prevParam === 1 ? 2 : 1));
  315. }, 1000 * 10);
  316. return () => clearInterval(interval);
  317. }, [userTypeValue]);
  318. return (
  319. <div className={styles.container}>
  320. <PreloadImage
  321. src={dataBoardBg_two}
  322. alt="背景边框"
  323. style={{ position: 'absolute', bottom: 0 }}
  324. />
  325. {/* 顶部 */}
  326. <div className={styles.dataTitleItem}>
  327. <PreloadImage src={dataBoardTitle} alt="顶部标题背景" />
  328. <img src={decoration_three} style={{ width: '50%' }} alt="顶部标题背景装饰" />
  329. <div className={styles.title}>山东永续绿建五恒环境科技有限公司</div>
  330. </div>
  331. {/* 中间内容 */}
  332. <div className={styles.dataBoardContent}>
  333. {/* 中间内容-----左侧 */}
  334. {/* 中间内容-----左侧--统计数据 */}
  335. <div className={styles.decoration_left_1}>
  336. <PreloadImage src={border} alt="边框" />
  337. <div className={styles.title_text}>统计数据</div>
  338. <div className={styles.statistics}>
  339. <div className={styles.user_data}>
  340. <div className={styles.statistics_title_text}>用户统计</div>
  341. <div className={styles.user_content}>
  342. <div className={styles.user_item}>
  343. <div className={styles.item_title}>注册用户数</div>
  344. <datav.DigitalFlop config={userNum} style={{ width: '200px', height: '50px' }} />
  345. </div>
  346. <div className={styles.user_item}>
  347. <div className={styles.item_title}>家庭数量</div>
  348. <datav.DigitalFlop
  349. config={homeNum}
  350. className={styles.item_content}
  351. style={{ width: '200px', height: '50px' }}
  352. />
  353. </div>
  354. </div>
  355. </div>
  356. <div className={styles.device_data}>
  357. <div className={styles.statistics_title_text}>设备统计</div>
  358. <div className={styles.device_content}>
  359. <div className={styles.device_item}>
  360. <datav.DigitalFlop
  361. config={deviceNum}
  362. className={styles.device_num}
  363. style={{ width: '200px', height: '50px' }}
  364. />
  365. <img src={decoration_two} className={styles.device_bg} alt="装饰背景" />
  366. <div className={styles.device_title}>设备数</div>
  367. </div>
  368. <div className={styles.device_item}>
  369. <datav.DigitalFlop
  370. config={onlineDeviceNum}
  371. className={styles.device_num}
  372. style={{ width: '200px', height: '50px' }}
  373. />
  374. <img src={decoration_two} className={styles.device_bg} alt="装饰背景" />
  375. <div className={styles.device_title}>在线设备数</div>
  376. </div>
  377. <div className={styles.device_item}>
  378. <datav.DigitalFlop
  379. config={offlineDeviceNum}
  380. className={styles.device_num}
  381. style={{ width: '200px', height: '50px' }}
  382. />
  383. <img src={decoration_two} className={styles.device_bg} alt="装饰背景" />
  384. <div className={styles.device_title}>离线设备数</div>
  385. </div>
  386. </div>
  387. <div className={styles.device_content}>
  388. <div className={styles.device_item}>
  389. <datav.DigitalFlop
  390. config={errorDeviceNum}
  391. className={styles.device_num}
  392. style={{ width: '200px', height: '50px' }}
  393. />
  394. <img src={decoration_two} className={styles.device_bg} alt="装饰背景" />
  395. <div className={styles.device_title}>故障设备数</div>
  396. </div>
  397. <div className={styles.device_item}>
  398. <datav.DigitalFlop
  399. config={masterControlNum}
  400. className={styles.device_num}
  401. style={{ width: '200px', height: '50px' }}
  402. />
  403. <img src={decoration_two} className={styles.device_bg} alt="装饰背景" />
  404. <div className={styles.device_title}>主控数量</div>
  405. </div>
  406. <div className={styles.device_item}>
  407. <datav.DigitalFlop
  408. config={subControlNum}
  409. className={styles.device_num}
  410. style={{ width: '200px', height: '50px' }}
  411. />
  412. <img src={decoration_two} className={styles.device_bg} alt="装饰背景" />
  413. <div className={styles.device_title}>分控数量</div>
  414. </div>
  415. </div>
  416. </div>
  417. </div>
  418. </div>
  419. {/* 中间内容-----左侧--用户增长趋势*/}
  420. <div className={styles.decoration_left_2}>
  421. <PreloadImage src={border} alt="边框" />
  422. <div className={styles.title_text}>用户增长趋势</div>
  423. <div className={styles.user_charts}>
  424. {userChartsData && userChartsData.length ? (
  425. <LineChartsCommon width={450} height={250} data={userChartsData} />
  426. ) : (
  427. <datav.Loading style={{ position: 'absolute' }}>Loading...</datav.Loading>
  428. )}
  429. </div>
  430. </div>
  431. {/* 中间内容-----地图 */}
  432. <div className={styles.decoration_map}>
  433. {/* 数据统计 */}
  434. <div style={{ display: 'flex', justifyContent: 'space-around' }}>
  435. <div className={styles.data_show}>
  436. <PreloadImage src={decoration_five} alt="背景边框" />
  437. <datav.DigitalFlop
  438. config={deviceStatistics}
  439. className={styles.data_show_num}
  440. style={{ width: '200px', height: '50px' }}
  441. />
  442. <div className={styles.data_show_title} style={{ color: '#08c7f1' }}>
  443. 设备数
  444. </div>
  445. </div>
  446. <div className={styles.data_show}>
  447. <PreloadImage src={decoration_five} alt="背景边框" />
  448. <datav.DigitalFlop
  449. config={allRunTime}
  450. className={styles.data_show_num}
  451. style={{ width: '200px', height: '50px' }}
  452. />
  453. <div className={styles.data_show_title} style={{ color: '#ffb026' }}>
  454. 总运行时长(小时)
  455. </div>
  456. </div>
  457. <div className={styles.data_show}>
  458. <PreloadImage src={decoration_five} alt="背景边框" />
  459. <datav.DigitalFlop
  460. config={todayRunTime}
  461. className={styles.data_show_num}
  462. style={{ width: '200px', height: '50px' }}
  463. />
  464. <div className={styles.data_show_title} style={{ color: '#0dde79' }}>
  465. 今日运行时长(小时)
  466. </div>
  467. </div>
  468. </div>
  469. {areaDeviceList && areaDeviceList.length ? (
  470. <MapComponent userData={userNum} areaList={areaDeviceList} />
  471. ) : (
  472. <datav.Loading style={{ position: 'absolute' }}>Loading...</datav.Loading>
  473. )}
  474. </div>
  475. {/* 中间内容-----右侧 */}
  476. {/* 中间内容-----右侧--地区设备数量统计 */}
  477. <div className={styles.decoration_right_3}>
  478. <PreloadImage src={border} alt="边框" />
  479. <div className={styles.title_text}>地区设备数量统计</div>
  480. {areaDeviceList && areaDeviceList.length && <AreaDeviceData data={areaDeviceList} />}
  481. </div>
  482. {/* 中间内容-----右侧--设备增长趋势*/}
  483. <div className={styles.decoration_right_4}>
  484. <PreloadImage src={border} alt="边框" />
  485. <div className={styles.title_text}>设备增长趋势</div>
  486. {deviceChartsData && deviceChartsData.length ? (
  487. <LineChartsCommon width={450} height={250} data={deviceChartsData} />
  488. ) : (
  489. <datav.Loading style={{ position: 'absolute' }}>Loading...</datav.Loading>
  490. )}
  491. </div>
  492. </div>
  493. {/* 底部轮播 */}
  494. <div className={styles.dataBottom}>
  495. <div className="swiper-content">
  496. {homeInfo && homeInfo.length ? (
  497. <Slider {...settings} className="swiper-container">
  498. {homeInfo.map((res) => {
  499. return <SliderData key={res} data={res} />;
  500. })}
  501. </Slider>
  502. ) : (
  503. <datav.Loading style={{ position: 'absolute' }}>Loading...</datav.Loading>
  504. )}
  505. </div>
  506. </div>
  507. </div>
  508. );
  509. };
  510. export default DataBoard;