Просмотр исходного кода

feat(analysis): add DeviceMessageChart

Lind 4 лет назад
Родитель
Сommit
5d0d12175f

+ 165 - 2
src/pages/Analysis/DeviceChart/index.tsx

@@ -1,4 +1,167 @@
-const DeviceChart = () => {
-  return <div>DeviceChart</div>;
+import { StatisticCard } from '@ant-design/pro-card';
+import { service } from '@/pages/Analysis';
+import { useEffect } from 'react';
+import { groupBy, map } from 'rxjs/operators';
+import { mergeMap, of, toArray, zip } from 'rxjs';
+import moment from 'moment';
+import { model } from '@formily/reactive';
+import { observer } from '@formily/react';
+import { Column } from '@ant-design/charts';
+import { Badge, Col, Row } from 'antd';
+import { SyncOutlined } from '@ant-design/icons';
+
+type DeviceChartType = {
+  deviceOnline: number;
+  aggOnline: Record<string, any>[];
+  deviceCount: number;
+  deviceNotActive: number;
 };
+const DeviceChartModel = model<DeviceChartType>({
+  deviceCount: 0,
+  aggOnline: [],
+  deviceOnline: 0,
+  deviceNotActive: 0,
+});
+const DeviceChart = observer(() => {
+  const getDeviceData = () => {
+    const requestParams = [
+      // 设备状态信息-在线
+      {
+        dashboard: 'device',
+        object: 'status',
+        measurement: 'record',
+        dimension: 'current',
+        group: 'deviceOnline',
+        params: {
+          state: 'online',
+        },
+      }, // 设备状态信息-总数
+      {
+        dashboard: 'device',
+        object: 'status',
+        measurement: 'record',
+        dimension: 'current',
+        group: 'deviceCount',
+      }, // 设备状态信息-未激活
+      {
+        dashboard: 'device',
+        object: 'status',
+        measurement: 'record',
+        dimension: 'current',
+        group: 'deviceNotActive',
+        params: {
+          state: 'notActive',
+        },
+      }, // 设备状态信息-历史在线
+      {
+        dashboard: 'device',
+        object: 'status',
+        measurement: 'record',
+        dimension: 'aggOnline',
+        group: 'aggOnline',
+        params: {
+          limit: 20,
+          time: '1d',
+          format: 'yyyy-MM-dd',
+        },
+      },
+    ];
+    service
+      .getMulti(requestParams)
+      .pipe(
+        mergeMap(
+          (item) =>
+            item.result as {
+              group: string;
+              data: Record<string, any>;
+              formatData?: { x: unknown; y: unknown };
+            }[],
+        ),
+        groupBy((item) => item.group),
+        mergeMap((group$) =>
+          zip(
+            of(group$.key),
+            group$.pipe(
+              map((item) =>
+                item.group === 'aggOnline'
+                  ? {
+                      x: moment(new Date(item.data.timeString)).format('YYYY-MM-DD'),
+                      y: Number(item.data.value),
+                    }
+                  : item.data.value,
+              ),
+              toArray(),
+            ),
+          ),
+        ),
+        map((item) =>
+          item[0] === 'aggOnline' ? [item[0], item[1].reverse()] : [item[0], ...item[1]],
+        ),
+      )
+      .subscribe((data) => {
+        // eslint-disable-next-line prefer-destructuring
+        DeviceChartModel[data[0]] = data[1];
+      });
+  };
+
+  useEffect(() => {
+    getDeviceData();
+  }, []);
+
+  return (
+    <StatisticCard
+      title="设备统计"
+      extra={<SyncOutlined onClick={() => getDeviceData()} />}
+      chart={
+        <Column
+          width={200}
+          height={180}
+          xField="x"
+          yField="y"
+          label={{
+            position: 'middle',
+            style: {
+              fill: '#FFFFFF',
+              opacity: 0.6,
+            },
+          }}
+          xAxis={{
+            label: {
+              autoHide: true,
+              autoRotate: false,
+            },
+          }}
+          meta={{
+            x: { alias: '日期' },
+            y: { alias: '数量' },
+          }}
+          data={DeviceChartModel.aggOnline}
+        />
+      }
+      footer={
+        <Row>
+          <Col span={8}>
+            <>
+              {' '}
+              <Badge status="warning" text="未激活" />
+              {DeviceChartModel.deviceNotActive}
+            </>
+          </Col>
+          <Col span={8}>
+            <>
+              {' '}
+              <Badge status="processing" text="总数" />· {DeviceChartModel.deviceCount}
+            </>
+          </Col>
+          <Col span={8}>
+            <>
+              <Badge status="success" text="在线" /> {DeviceChartModel.deviceOnline}
+            </>
+          </Col>
+        </Row>
+      }
+    />
+  );
+});
+
 export default DeviceChart;

+ 136 - 15
src/pages/Analysis/DeviceMessage/index.tsx

@@ -1,25 +1,126 @@
-import { useEffect, useState } from 'react';
 import { Area } from '@ant-design/charts';
+import { service } from '@/pages/Analysis';
+import { useEffect } from 'react';
+import { groupBy, map, mergeMap } from 'rxjs/operators';
+import { of, toArray, zip } from 'rxjs';
+import { model } from '@formily/reactive';
+import { observer } from '@formily/react';
+import { StatisticCard } from '@ant-design/pro-card';
+import { Radio } from 'antd';
+import type { DurationInputArg1, DurationInputArg2 } from 'moment';
+import moment from 'moment';
 
-const DeviceMessageChart = () => {
-  const [data, setData] = useState([]);
+type DeviceMessage = {
+  chartData: any[];
+  startDate: string;
+  endDate: string;
+  timeType: string;
+  dateType: '1d' | '1h' | '7d' | '30d';
+};
+const DateFormat = 'YYYY-MM-DD HH:mm:ss';
+
+const DeviceMessageModel = model<DeviceMessage>({
+  chartData: [],
+  startDate: moment(new Date()).format(DateFormat),
+  endDate: moment(new Date()).format(DateFormat),
+  timeType: '1m',
+  dateType: '1h',
+});
 
-  const asyncFetch = () => {
-    fetch('https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38ccf184.json')
-      .then((response) => response.json())
-      .then((json) => setData(json))
-      .catch((error) => {
-        console.log('fetch data failed', error);
+const DeviceMessageChart = observer(() => {
+  const gatewayMonitor = (from: string, to: string, time: string) => {
+    const params = [
+      {
+        dashboard: 'gatewayMonitor',
+        object: 'deviceGateway',
+        measurement: 'received_message',
+        dimension: 'agg',
+        group: 'sameDay',
+        params: {
+          time,
+          limit: 60,
+          format: 'HH时mm分',
+          from,
+          to,
+        },
+      },
+    ];
+
+    service
+      .getMulti(params)
+      .pipe(
+        mergeMap(
+          (item) =>
+            item.result as {
+              group: string;
+              data: {
+                value: number;
+                timeString: string;
+                timestamp: number;
+              };
+            }[],
+        ),
+        groupBy((item) => item.group),
+        mergeMap((group$) =>
+          zip(
+            of(group$.key),
+            group$.pipe(
+              map((item) => ({
+                type: '消息量',
+                year: item.data.timeString,
+                value: item.data.value,
+              })),
+              toArray(),
+            ),
+          ),
+        ),
+      )
+      .subscribe((data) => {
+        // eslint-disable-next-line prefer-destructuring
+        DeviceMessageModel.chartData = data[1];
       });
   };
+
+  const SubtractDate = (startDate: string, amount: DurationInputArg1, unit: DurationInputArg2) =>
+    moment(startDate).subtract(amount, unit).format(DateFormat);
+
+  const onDateTypeChange = (type: '1d' | '1h' | '7d' | '30d') => {
+    DeviceMessageModel.dateType = type;
+    const to = moment(new Date()).format(DateFormat);
+    switch (type) {
+      case '1h':
+        DeviceMessageModel.startDate = SubtractDate(to, 1, 'hours');
+        DeviceMessageModel.timeType = '1m';
+        break;
+      case '1d':
+        DeviceMessageModel.startDate = SubtractDate(to, 1, 'days');
+        DeviceMessageModel.timeType = '24m';
+        break;
+      case '7d':
+        DeviceMessageModel.startDate = SubtractDate(to, 7, 'days');
+        DeviceMessageModel.timeType = '168m';
+        break;
+      case '30d':
+        DeviceMessageModel.startDate = SubtractDate(to, 30, 'days');
+        DeviceMessageModel.timeType = '12h';
+        break;
+      default:
+        break;
+    }
+    gatewayMonitor(
+      DeviceMessageModel.startDate,
+      DeviceMessageModel.endDate,
+      DeviceMessageModel.timeType,
+    );
+  };
   useEffect(() => {
-    asyncFetch();
+    onDateTypeChange('1h');
   }, []);
 
   const config = {
-    data,
-    xField: 'Date',
-    yField: 'scales',
+    data: DeviceMessageModel.chartData,
+    xField: 'year',
+    yField: 'value',
     xAxis: {
       range: [0, 1],
       tickCount: 5,
@@ -33,6 +134,26 @@ const DeviceMessageChart = () => {
       return { fill: 'l(270) 0:#ffffff 0.5:#7ec2f3 1:#1890ff' };
     },
   };
-  return <Area {...config} />;
-};
+  const options = [
+    { label: '1小时', value: '1h' },
+    { label: '1天', value: '1d' },
+    { label: '7天', value: '7d' },
+    { label: '30天', value: '30d' },
+  ];
+  return (
+    <StatisticCard
+      title="设备消息"
+      extra={
+        <Radio.Group
+          options={options}
+          optionType="button"
+          size="small"
+          value={DeviceMessageModel.dateType}
+          onChange={(e) => onDateTypeChange(e.target.value)}
+        />
+      }
+      chart={<Area {...config} />}
+    />
+  );
+});
 export default DeviceMessageChart;

+ 2 - 7
src/pages/Analysis/index.tsx

@@ -45,13 +45,8 @@ const Analysis = () => {
         <DeviceChart />
       </StatisticCard.Group>
       <Divider type={responsive ? 'horizontal' : 'vertical'} />
-      <StatisticCard
-        statistic={{
-          title: '设备消息',
-        }}
-      >
-        <DeviceMessageChart />
-      </StatisticCard>
+
+      <DeviceMessageChart />
     </RcResizeObserver>
   );
 };