Pārlūkot izejas kodu

feat: 设备管理仪表盘

wzyyy 3 gadi atpakaļ
vecāks
revīzija
fdf5cdca66

+ 34 - 0
src/pages/device/DashBoard/index.less

@@ -0,0 +1,34 @@
+.media-dash-board {
+  .top-card-items {
+    margin-bottom: 12px;
+
+    .top-card-item {
+      width: 25%;
+      padding: 6px 24px;
+      border: 1px solid #e3e3e3;
+
+      .top-card-top {
+        display: flex;
+        padding: 12px 0;
+
+        .top-card-top-left {
+          width: 80px;
+        }
+
+        .top-card-top-right {
+          .top-card-total {
+            font-weight: bold;
+            font-size: 20px;
+          }
+        }
+      }
+
+      .top-card-bottom {
+        display: flex;
+        justify-content: space-between;
+        padding: 12px 0;
+        border-top: 1px solid #e3e3e3;
+      }
+    }
+  }
+}

+ 101 - 0
src/pages/device/DashBoard/index.tsx

@@ -0,0 +1,101 @@
+import { PageContainer } from '@ant-design/pro-layout';
+import { Card, Badge } from 'antd';
+import { useEffect, useState } from 'react';
+import './index.less';
+import Service from './service';
+import encodeQuery from '@/utils/encodeQuery';
+import { useRequest } from 'umi';
+
+interface TopCardProps {
+  url?: string;
+  isEcharts: boolean;
+  title: string;
+  total: number | string;
+  bottomRender: () => React.ReactNode;
+}
+const service = new Service('device/instance');
+const TopCard = (props: TopCardProps) => {
+  return (
+    <div className={'top-card-item'}>
+      <div className={'top-card-top'}>
+        {!props.isEcharts && <div className={'top-card-top-left'}></div>}
+        <div className={'top-card-top-right'}>
+          <div className={'top-card-title'}>{props.title}</div>
+          <div className={'top-card-total'}>{props.total}</div>
+        </div>
+      </div>
+      <div className={'top-card-bottom'}>{props.bottomRender()}</div>
+    </div>
+  );
+};
+
+const DashBoard = () => {
+  const [deviceOnline, setDeviceOnline] = useState(0);
+  const [deviceOffline, setDeviceOffline] = useState(0);
+
+  const { data: deviceTotal } = useRequest(service.deviceCount, {
+    formatResult: (res) => res.result,
+  });
+
+  //设备数量
+  const deviceStatus = async () => {
+    const onlineRes = await service.deviceCount(encodeQuery({ terms: { state: 'online' } }));
+    if (onlineRes.status === 200) {
+      setDeviceOnline(onlineRes.result);
+    }
+    const offlineRes = await service.deviceCount(encodeQuery({ terms: { state: 'offline' } }));
+    if (offlineRes.status === 200) {
+      setDeviceOffline(offlineRes.result);
+    }
+  };
+  useEffect(() => {
+    deviceStatus();
+  }, []);
+
+  return (
+    <PageContainer>
+      <div className={'media-dash-board'}>
+        <Card className={'top-card-items'} bodyStyle={{ display: 'flex', gap: 12 }}>
+          <TopCard
+            title={'产品数量'}
+            total={1}
+            isEcharts={false}
+            bottomRender={() => (
+              <>
+                <Badge status="success" text="未发布" />{' '}
+                <span style={{ padding: '0 4px' }}>{1}</span>
+                <Badge status="error" text="已发布" /> <span style={{ padding: '0 4px' }}>{1}</span>
+              </>
+            )}
+          />
+          <TopCard
+            title={'设备数量'}
+            total={deviceTotal}
+            isEcharts={false}
+            bottomRender={() => (
+              <>
+                <Badge status="success" text="在线" />{' '}
+                <span style={{ padding: '0 4px' }}>{deviceOnline}</span>
+                <Badge status="error" text="离线" />{' '}
+                <span style={{ padding: '0 4px' }}>{deviceOffline}</span>
+              </>
+            )}
+          />
+          <TopCard
+            title={'当前在线'}
+            total={1}
+            isEcharts={true}
+            bottomRender={() => <>昨日在线: </>}
+          />
+          <TopCard
+            title={'今日设备消息量'}
+            total={1}
+            isEcharts={true}
+            bottomRender={() => <>当月设备消息量: </>}
+          />
+        </Card>
+      </div>
+    </PageContainer>
+  );
+};
+export default DashBoard;

+ 9 - 0
src/pages/device/DashBoard/service.ts

@@ -0,0 +1,9 @@
+import BaseService from '@/utils/BaseService';
+import { request } from 'umi';
+import type { DeviceInstance } from '@/pages/device/Instance/typings';
+
+class Service extends BaseService<DeviceInstance> {
+  deviceCount = (data?: any) => request(`${this.uri}/_count`, { methods: 'GET', params: data });
+}
+
+export default Service;

+ 82 - 75
src/pages/system/Basis/index.tsx

@@ -8,6 +8,7 @@ import Token from '@/utils/token';
 import SystemConst from '@/utils/const';
 import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
 import styles from './index.less';
+import { PageContainer } from '@ant-design/pro-layout';
 
 const Basis = () => {
   const [form] = Form.useForm();
@@ -53,84 +54,90 @@ const Basis = () => {
   }, []);
 
   return (
-    <Card>
-      <div
-        style={{
-          display: 'flex',
-          alignItems: 'flex-start',
-          justifyContent: 'flex-start',
-        }}
-      >
-        <div style={{ width: 400 }}>
-          <Form layout="vertical" form={form}>
-            <Form.Item
-              label="系统名称"
-              name="title"
-              rules={[{ required: true, message: '请输入系统名称' }]}
-            >
-              <Input />
-            </Form.Item>
-            <Form.Item
-              label="主题色"
-              name="navTheme"
-              rules={[{ required: true, message: '请选择主题色' }]}
-            >
-              <Select
-                onChange={() => {
-                  // setInitialState({
-                  //     ...initialState,
-                  //     settings:{
-                  //         navTheme:e,
-                  //         headerTheme:e,
-                  //         title:'hahahah'
-                  //     }
-                  // })
-                }}
+    <PageContainer>
+      <Card>
+        <div
+          style={{
+            display: 'flex',
+            alignItems: 'flex-start',
+            justifyContent: 'flex-start',
+          }}
+        >
+          <div style={{ width: 400 }}>
+            <Form layout="vertical" form={form}>
+              <Form.Item
+                label="系统名称"
+                name="title"
+                rules={[{ required: true, message: '请输入系统名称' }]}
               >
-                <Select.Option value="light">light</Select.Option>
-                <Select.Option value="dark">dark</Select.Option>
-              </Select>
-            </Form.Item>
-            <Form.Item label="高德API Key" name="apikey" tooltip="配置后平台可调用高德地图GIS服务">
-              <Input />
-            </Form.Item>
-          </Form>
-        </div>
-        <div className={styles.content}>
-          <div style={{ marginBottom: 8 }}>系统logo</div>
-          <Upload {...uploadProps}>
-            {imageUrl ? (
-              <img src={imageUrl} alt="avatar" style={{ width: '100%' }} />
-            ) : (
-              uploadButton
-            )}
-          </Upload>
+                <Input />
+              </Form.Item>
+              <Form.Item
+                label="主题色"
+                name="navTheme"
+                rules={[{ required: true, message: '请选择主题色' }]}
+              >
+                <Select
+                  onChange={() => {
+                    // setInitialState({
+                    //     ...initialState,
+                    //     settings:{
+                    //         navTheme:e,
+                    //         headerTheme:e,
+                    //         title:'hahahah'
+                    //     }
+                    // })
+                  }}
+                >
+                  <Select.Option value="light">light</Select.Option>
+                  <Select.Option value="dark">dark</Select.Option>
+                </Select>
+              </Form.Item>
+              <Form.Item
+                label="高德API Key"
+                name="apikey"
+                tooltip="配置后平台可调用高德地图GIS服务"
+              >
+                <Input />
+              </Form.Item>
+            </Form>
+          </div>
+          <div className={styles.content}>
+            <div style={{ marginBottom: 8 }}>系统logo</div>
+            <Upload {...uploadProps}>
+              {imageUrl ? (
+                <img src={imageUrl} alt="avatar" style={{ width: '100%' }} />
+              ) : (
+                uploadButton
+              )}
+            </Upload>
+          </div>
         </div>
-      </div>
-      <div>
-        <PermissionButton
-          type="primary"
-          key="basis"
-          onClick={async () => {
-            // setPassword(true);
-            const data = await form.validateFields();
-            if (data) {
-              if (imageUrl !== '') {
-                console.log({
-                  ...data,
-                  imageUrl,
-                });
-              } else {
-                message.error('请上传图片');
+        <div>
+          <PermissionButton
+            type="primary"
+            key="basis"
+            onClick={async () => {
+              // setPassword(true);
+              const data = await form.validateFields();
+              if (data) {
+                if (imageUrl !== '') {
+                  console.log({
+                    ...data,
+                    imageUrl,
+                  });
+                } else {
+                  message.error('请上传图片');
+                }
               }
-            }
-          }}
-          isPermission={userPermission.update}
-        >
-          保存
-        </PermissionButton>
-      </div>
-    </Card>
+            }}
+            isPermission={userPermission.update}
+          >
+            保存
+          </PermissionButton>
+        </div>
+      </Card>
+    </PageContainer>
   );
 };
 

+ 1 - 0
src/utils/menu/router.ts

@@ -21,6 +21,7 @@ export enum MENUS_CODE {
   'device/Location' = 'device/Location',
   'device/Product/Save' = 'device/Product/Save',
   'device/Product' = 'device/Product',
+  'device/DashBoard' = 'device/DashBoard',
   'device/components/Alarm/Edit' = 'device/components/Alarm/Edit',
   'device/components/Alarm/Record' = 'device/components/Alarm/Record',
   'device/components/Alarm/Setting' = 'device/components/Alarm/Setting',