index.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import { PageContainer } from '@ant-design/pro-layout';
  2. import DashBoard, { DashBoardTopCard } from '@/components/DashBoard';
  3. import { useRequest } from 'umi';
  4. import { useEffect, useState } from 'react';
  5. import Service from './service';
  6. import './index.less';
  7. import encodeQuery from '@/utils/encodeQuery';
  8. import type { EChartsOption } from 'echarts';
  9. import moment from 'moment';
  10. import { Tooltip } from 'antd';
  11. import { QuestionCircleOutlined } from '@ant-design/icons';
  12. const service = new Service('media');
  13. export default () => {
  14. const [deviceOnline, setDeviceOnline] = useState(0);
  15. const [deviceOffline, setDeviceOffline] = useState(0);
  16. const [channelOnline, setChannelOnline] = useState(0);
  17. const [channelOffline, setChannelOffline] = useState(0);
  18. const [options, setOptions] = useState<EChartsOption>({});
  19. const { data: deviceTotal } = useRequest(service.deviceCount, {
  20. formatResult: (res) => res.result,
  21. });
  22. const { data: playObject } = useRequest(service.playingAgg, {
  23. formatResult: (res) => res.result,
  24. });
  25. const { data: fileObject } = useRequest(service.fileAgg, {
  26. formatResult: (res) => res.result,
  27. });
  28. const { data: channelTotal } = useRequest<any, any>(service.channelCount, {
  29. formatResult: (res) => res.result,
  30. defaultParams: {},
  31. });
  32. /**
  33. * 通道数量
  34. */
  35. const channelStatus = async () => {
  36. const onlineRes = await service.channelCount({
  37. terms: [{ column: 'status', value: 'online' }],
  38. });
  39. if (onlineRes.status === 200) {
  40. setChannelOnline(onlineRes.result);
  41. }
  42. const offlineRes = await service.channelCount({
  43. terms: [{ column: 'status$not', value: 'online' }],
  44. });
  45. if (offlineRes.status === 200) {
  46. setChannelOffline(offlineRes.result);
  47. }
  48. };
  49. /**
  50. * 设备数量
  51. */
  52. const deviceStatus = async () => {
  53. const onlineRes = await service.deviceCount(encodeQuery({ terms: { state: 'online' } }));
  54. if (onlineRes.status === 200) {
  55. setDeviceOnline(onlineRes.result);
  56. }
  57. const offlineRes = await service.deviceCount(encodeQuery({ terms: { state: 'offline' } }));
  58. if (offlineRes.status === 200) {
  59. setDeviceOffline(offlineRes.result);
  60. }
  61. };
  62. const getInterval = (type: string) => {
  63. switch (type) {
  64. case 'year':
  65. return '30d';
  66. case 'month':
  67. case 'week':
  68. return '1d';
  69. case 'hour':
  70. return '1m';
  71. default:
  72. return '1h';
  73. }
  74. };
  75. const getEcharts = async (params: any) => {
  76. const resp = await service.getMulti([
  77. {
  78. dashboard: 'media_stream',
  79. object: 'play_count',
  80. measurement: 'quantity',
  81. dimension: 'agg',
  82. group: 'playCount',
  83. params: {
  84. time: getInterval(params.time.type),
  85. from: moment(params.time.start).format('YYYY-MM-DD HH:mm:ss'),
  86. to: moment(params.time.end).format('YYYY-MM-DD HH:mm:ss'),
  87. limit: 30,
  88. },
  89. },
  90. ]);
  91. if (resp.status === 200) {
  92. const xData: string[] = [];
  93. const sData: number[] = [];
  94. resp.result
  95. .sort((a: any, b: any) => b.data.timestamp - a.data.timestamp)
  96. .forEach((item: any) => {
  97. xData.push(item.data.timeString);
  98. sData.push(item.data.value);
  99. });
  100. setOptions({
  101. xAxis: {
  102. type: 'category',
  103. data: xData,
  104. },
  105. tooltip: {
  106. trigger: 'axis',
  107. },
  108. yAxis: {
  109. type: 'value',
  110. },
  111. grid: {
  112. left: '4%',
  113. right: '2%',
  114. top: '2%',
  115. },
  116. color: ['#2F54EB'],
  117. series: [
  118. {
  119. data: sData,
  120. type: 'bar',
  121. barWidth: 16,
  122. },
  123. ],
  124. });
  125. }
  126. };
  127. const handleTimeFormat = (time: number) => {
  128. let hour = 0;
  129. let min = 0;
  130. let sec = 0;
  131. const timeStr = 'hh小时mm分钟ss秒';
  132. if (time) {
  133. if (time >= 60 * 60 * 1000) {
  134. hour = Math.trunc(time / (60 * 60 * 1000));
  135. }
  136. if (time >= 60 * 1000) {
  137. min = Math.trunc((time - hour * 60 * 60 * 1000) / (60 * 1000));
  138. }
  139. sec = Math.trunc((time - hour * (60 * 60 * 1000) - min * 60 * 1000) / 1000);
  140. }
  141. return timeStr
  142. .replace('hh', hour.toString())
  143. .replace('mm', min.toString())
  144. .replace('ss', sec.toString());
  145. };
  146. useEffect(() => {
  147. deviceStatus();
  148. channelStatus();
  149. }, []);
  150. return (
  151. <PageContainer>
  152. <div className={'media-dash-board'}>
  153. <DashBoardTopCard>
  154. <DashBoardTopCard.Item
  155. title={'设备数量'}
  156. value={deviceTotal}
  157. footer={[
  158. {
  159. title: '在线',
  160. value: deviceOnline,
  161. status: 'success',
  162. },
  163. {
  164. title: '离线',
  165. value: deviceOffline,
  166. status: 'error',
  167. },
  168. ]}
  169. span={6}
  170. >
  171. <img src={require('/public/images/media/dashboard-1.png')} />
  172. </DashBoardTopCard.Item>
  173. <DashBoardTopCard.Item
  174. title={'通道数量'}
  175. value={channelTotal}
  176. footer={[
  177. {
  178. title: '已连接',
  179. value: channelOnline,
  180. status: 'success',
  181. },
  182. {
  183. title: '未连接',
  184. value: channelOffline,
  185. status: 'error',
  186. },
  187. ]}
  188. span={6}
  189. >
  190. <img src={require('/public/images/media/dashboard-2.png')} />
  191. </DashBoardTopCard.Item>
  192. <DashBoardTopCard.Item
  193. title={'录像数量'}
  194. value={fileObject ? fileObject.total : 0}
  195. footer={[
  196. {
  197. title: '总时长',
  198. value: handleTimeFormat(fileObject ? fileObject.duration : 0),
  199. },
  200. ]}
  201. span={6}
  202. >
  203. <img src={require('/public/images/media/dashboard-3.png')} />
  204. </DashBoardTopCard.Item>
  205. <DashBoardTopCard.Item
  206. title={
  207. <span>
  208. 播放中数量
  209. <Tooltip title={'当前正在播放的通道数量之和'}>
  210. <QuestionCircleOutlined style={{ marginLeft: 12 }} />
  211. </Tooltip>
  212. </span>
  213. }
  214. value={playObject ? playObject.playerTotal : 0}
  215. footer={[
  216. {
  217. title: '播放人数',
  218. value: playObject ? playObject.playingTotal : 0,
  219. },
  220. ]}
  221. span={6}
  222. >
  223. <img src={require('/public/images/media/dashboard-4.png')} />
  224. </DashBoardTopCard.Item>
  225. </DashBoardTopCard>
  226. <DashBoard
  227. showTimeTool={true}
  228. className={'media-dash-board-body'}
  229. title={'播放数量(人次)'}
  230. options={options}
  231. height={500}
  232. defaultTime={'week'}
  233. onParamsChange={getEcharts}
  234. />
  235. </div>
  236. </PageContainer>
  237. );
  238. };