Browse Source

feat(merge): merge xyh

Next xyh
Lind 3 years ago
parent
commit
74a1b6006e

+ 30 - 0
src/components/DashBoard/baseCard.tsx

@@ -0,0 +1,30 @@
+import Header from './header';
+import type { HeaderProps } from './header';
+import Echarts from './echarts';
+import type { EchartsProps } from './echarts';
+import Style from './index.less';
+import classNames from 'classnames';
+
+interface BaseCardProps extends HeaderProps, EchartsProps {
+  height: number;
+  classNames?: string;
+}
+
+export default (props: BaseCardProps) => {
+  return (
+    <div
+      className={classNames(Style['dash-board-echarts'], props.classNames)}
+      style={{
+        height: props.height || 200,
+      }}
+    >
+      <Header
+        title={props.title}
+        onParamsChange={props.onParamsChange}
+        extraParams={props.extraParams}
+        initialValues={props.initialValues}
+      />
+      <Echarts options={props.options} />
+    </div>
+  );
+};

+ 106 - 0
src/components/DashBoard/echarts.tsx

@@ -0,0 +1,106 @@
+import { useEffect, useRef } from 'react';
+import * as echarts from 'echarts/core';
+import type { ECharts } from 'echarts';
+import {
+  TitleComponent,
+  ToolboxComponent,
+  TooltipComponent,
+  GridComponent,
+  LegendComponent,
+  MarkLineComponent,
+} from 'echarts/components';
+
+import { LineChart } from 'echarts/charts';
+import { PieChart } from 'echarts/charts';
+import { BarChart } from 'echarts/charts';
+
+import { UniversalTransition } from 'echarts/features';
+import { CanvasRenderer } from 'echarts/renderers';
+
+import Style from './index.less';
+import type { EChartsOption } from 'echarts';
+
+export interface EchartsProps {
+  options?: EChartsOption;
+}
+
+echarts.use([
+  TitleComponent,
+  ToolboxComponent,
+  TooltipComponent,
+  GridComponent,
+  LegendComponent,
+  LineChart,
+  CanvasRenderer,
+  UniversalTransition,
+  BarChart,
+  MarkLineComponent,
+  PieChart,
+]);
+
+const DefaultOptions = {
+  xAxis: {
+    type: 'category',
+    data: [0],
+  },
+  yAxis: {
+    type: 'value',
+  },
+  series: [
+    {
+      data: [],
+      type: 'line',
+    },
+  ],
+};
+
+export default (props: EchartsProps) => {
+  const chartsRef = useRef<any>(null);
+
+  const initEcharts = (dom: HTMLDivElement) => {
+    chartsRef.current = echarts.init(dom);
+    if (props.options) {
+      chartsRef.current.setOption(props.options);
+    } else {
+      chartsRef.current.setOption(DefaultOptions);
+    }
+  };
+
+  const updateSize = () => {
+    if (chartsRef.current) {
+      // 自适应屏幕变化
+      (chartsRef.current as ECharts).resize();
+    }
+  };
+
+  const updateOptions = () => {
+    if (chartsRef.current && props.options) {
+      chartsRef.current.setOption(props.options);
+    }
+  };
+
+  useEffect(() => {
+    (window as Window).addEventListener('resize', updateSize);
+
+    return () => {
+      (window as Window).removeEventListener('resize', updateSize);
+    };
+  }, []);
+
+  useEffect(() => {
+    updateOptions();
+  }, [props.options, chartsRef.current]);
+
+  return (
+    <div
+      className={Style.content}
+      ref={(ref) => {
+        if (ref) {
+          setTimeout(() => {
+            initEcharts(ref);
+          }, 100);
+        }
+      }}
+    />
+  );
+};

+ 114 - 0
src/components/DashBoard/header.tsx

@@ -0,0 +1,114 @@
+import React, { useEffect, useState } from 'react';
+import Style from './index.less';
+import { Col, DatePicker, Form, Input, Radio, Row } from 'antd';
+import moment from 'moment';
+
+export interface HeaderProps {
+  title: string;
+  /**
+   * 参数发生变化时的回调
+   * @param data
+   */
+  onParamsChange: (data: any) => void;
+  extraParams?: {
+    key: string;
+    Children: React.ReactNode;
+  };
+  initialValues?: any;
+}
+
+export default (props: HeaderProps) => {
+  const [form] = Form.useForm();
+  const [radioValue, setRadioValue] = useState<string | undefined>('today');
+
+  const change = async () => {
+    const data = await form.getFieldsValue();
+    data.time = [data.time[0].valueOf(), data.time[1].valueOf()];
+    if (props.onParamsChange) {
+      props.onParamsChange(data);
+    }
+  };
+  const setTime = (sTime: number, eTime: number) => {
+    form.setFieldsValue({ time: [moment(sTime), moment(eTime)] });
+  };
+
+  useEffect(() => {
+    setTime(moment().startOf('day').valueOf(), new Date().getTime());
+    setRadioValue('today');
+    change();
+  }, []);
+
+  return (
+    <div className={Style.header}>
+      <div className={Style.title}>{props.title}</div>
+      <div className={Style.form}>
+        <Form
+          form={form}
+          colon={false}
+          layout={'inline'}
+          preserve={false}
+          initialValues={props.initialValues}
+          onValuesChange={() => {
+            change();
+          }}
+        >
+          <Row style={{ width: '100%' }}>
+            {props.extraParams && (
+              <Col span={6}>
+                <Form.Item name={props.extraParams.key}>{props.extraParams.Children}</Form.Item>
+              </Col>
+            )}
+            <Col span={props.extraParams ? 18 : 24}>
+              <Form.Item noStyle>
+                <Input.Group compact>
+                  <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
+                    <Radio.Group
+                      defaultValue="day"
+                      buttonStyle="solid"
+                      value={radioValue}
+                      onChange={(e) => {
+                        let startTime: any = 0;
+                        const endTime = moment(new Date());
+                        const value = e.target.value;
+                        if (value === 'today') {
+                          startTime = moment().startOf('day').valueOf();
+                        } else if (value === 'week') {
+                          startTime = moment().subtract(6, 'days').valueOf();
+                        } else if (value === 'month') {
+                          startTime = moment().subtract(29, 'days').valueOf();
+                        } else {
+                          startTime = moment().subtract(365, 'days').valueOf();
+                        }
+                        setRadioValue(value);
+                        form.setFieldsValue({ time: [moment(startTime), moment(endTime)] });
+                        change();
+                      }}
+                    >
+                      <Radio.Button value="today">当天</Radio.Button>
+                      <Radio.Button value="week">近一周</Radio.Button>
+                      <Radio.Button value="month">近一月</Radio.Button>
+                      <Radio.Button value="year">近一年</Radio.Button>
+                    </Radio.Group>
+                    <Form.Item name={'time'} noStyle>
+                      {
+                        // @ts-ignore
+                        <DatePicker.RangePicker
+                          showTime
+                          onChange={(date: any) => {
+                            if (date) {
+                              setRadioValue(undefined);
+                            }
+                          }}
+                        />
+                      }
+                    </Form.Item>
+                  </div>
+                </Input.Group>
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    </div>
+  );
+};

+ 30 - 0
src/components/DashBoard/index.less

@@ -0,0 +1,30 @@
+.dash-board-echarts {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  padding: 24px;
+  background-color: #fff;
+  border: 1px solid #f0f0f0;
+  border-radius: 2px;
+}
+.header {
+  display: flex;
+  gap: 20px;
+  padding: 8px 0;
+}
+
+.title {
+  font-weight: bold;
+  font-size: 16px;
+}
+
+.form {
+  flex: 1;
+}
+
+.content {
+  flex-grow: 1;
+  width: 100%;
+  height: 0;
+  margin: 12px;
+}

+ 6 - 0
src/components/DashBoard/index.tsx

@@ -0,0 +1,6 @@
+import BaseCard from './baseCard';
+
+export { default as DashBoardEcharts } from './echarts';
+export { default as DashBoardHeader } from './header';
+
+export default BaseCard;

+ 3 - 0
src/components/DashBoard/topCard.tsx

@@ -0,0 +1,3 @@
+export default () => {
+  return <div></div>;
+};

+ 34 - 0
src/pages/media/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;
+      }
+    }
+  }
+}

+ 147 - 0
src/pages/media/DashBoard/index.tsx

@@ -0,0 +1,147 @@
+import { PageContainer } from '@ant-design/pro-layout';
+import { Badge, Card, Select } from 'antd';
+import DashBoard from '@/components/DashBoard';
+import { useRequest } from 'umi';
+import React, { useEffect, useState } from 'react';
+import Service from './service';
+import './index.less';
+import encodeQuery from '@/utils/encodeQuery';
+import { EChartsOption } from 'echarts';
+
+interface TopCardProps {
+  url: string;
+  title: string;
+  total: number | string;
+  bottomRender: () => React.ReactNode;
+}
+
+const service = new Service('media/device');
+
+const TopCard = (props: TopCardProps) => {
+  return (
+    <div className={'top-card-item'}>
+      <div className={'top-card-top'}>
+        <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>
+  );
+};
+
+export default () => {
+  const [deviceOnline, setDeviceOnline] = useState(0);
+  const [deviceOffline, setDeviceOffline] = useState(0);
+  const [options, setOptions] = useState<EChartsOption>({});
+
+  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);
+    }
+  };
+
+  const getEcharts = async (params: any) => {
+    // 请求数据
+    console.log(params);
+
+    setOptions({
+      xAxis: {
+        type: 'category',
+        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+      },
+      yAxis: {
+        type: 'value',
+      },
+      series: [
+        {
+          data: [150, 230, 224, 218, 135, 147, 260],
+          type: 'line',
+        },
+      ],
+    });
+  };
+
+  useEffect(() => {
+    deviceStatus();
+  }, []);
+
+  return (
+    <PageContainer>
+      <div className={'media-dash-board'}>
+        <Card className={'top-card-items'} bodyStyle={{ display: 'flex', gap: 12 }}>
+          <TopCard
+            title={'设备数量'}
+            total={deviceTotal}
+            url={''}
+            bottomRender={() => (
+              <>
+                <Badge status="error" text="在线" />{' '}
+                <span style={{ padding: '0 4px' }}>{deviceOnline}</span>
+                <Badge status="success" text="离线" />{' '}
+                <span style={{ padding: '0 4px' }}>{deviceOffline}</span>
+              </>
+            )}
+          />
+          <TopCard
+            title={'通道数量'}
+            total={12}
+            url={''}
+            bottomRender={() => (
+              <>
+                <Badge status="error" text="在线" /> <span style={{ padding: '0 4px' }}>12</span>
+                <Badge status="success" text="离线" /> <span style={{ padding: '0 4px' }}>12</span>
+              </>
+            )}
+          />
+          <TopCard
+            title={'录像数量'}
+            total={12}
+            url={''}
+            bottomRender={() => <div>总时长: </div>}
+          />
+          <TopCard
+            title={'播放中数量'}
+            total={12}
+            url={''}
+            bottomRender={() => <div>播放人数: </div>}
+          />
+        </Card>
+        <DashBoard
+          title={'播放数量(人次)'}
+          options={options}
+          height={500}
+          initialValues={{
+            test: '2',
+          }}
+          extraParams={{
+            key: 'test',
+            Children: (
+              <Select
+                options={[
+                  { label: '1', value: '1' },
+                  { label: '2', value: '2' },
+                ]}
+              ></Select>
+            ),
+          }}
+          onParamsChange={getEcharts}
+        />
+      </div>
+    </PageContainer>
+  );
+};

+ 12 - 0
src/pages/media/DashBoard/service.ts

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

+ 2 - 2
src/pages/media/Device/Channel/Live/index.tsx

@@ -58,7 +58,7 @@ const LiveFC = (props: LiveProps) => {
               onClick={async () => {
                 if (isRecord === 0) {
                   setIsRecord(1);
-                  const resp = await service.recordStop(props.deviceId, props.channelId, {
+                  const resp = await service.recordStart(props.deviceId, props.channelId, {
                     local: false,
                   });
                   if (resp.status === 200) {
@@ -67,7 +67,7 @@ const LiveFC = (props: LiveProps) => {
                     setIsRecord(0);
                   }
                 } else if (isRecord === 2) {
-                  const resp = await service.recordStart(props.deviceId, props.channelId, {
+                  const resp = await service.recordStop(props.deviceId, props.channelId, {
                     local: false,
                   });
                   if (resp.status === 200) {

+ 0 - 1
src/pages/rule-engine/Scene/Save/index.tsx

@@ -217,7 +217,6 @@ export default () => {
           preserve={false}
           className={'scene-save'}
           onValuesChange={(changeValue, allValues) => {
-            console.log(changeValue, allValues);
             if (changeValue.trigger) {
               if (changeValue.trigger.device) {
                 if (

+ 0 - 1
src/pages/system/Department/index.tsx

@@ -368,7 +368,6 @@ export default observer(() => {
       />
       <Save<DepartmentItem>
         parentChange={(pId) => {
-          console.log(getSortIndex(treeData, pId));
           return getSortIndex(treeData, pId);
         }}
         title={

+ 2 - 1
src/pages/system/Department/save.tsx

@@ -73,7 +73,8 @@ const Save = <T extends object>(props: SaveModalProps<T>) => {
     initialValues: data || {},
     effects: () => {
       onFieldReact('sortIndex', (field) => {
-        if (props.parentChange) {
+        const value = (field as Field).value;
+        if (props.parentChange && !value) {
           const sortIndex = props.parentChange(field.query('parentId').value());
           (field as Field).value = !!sortIndex ? sortIndex : sortIndex + 1;
         }

+ 3 - 0
src/pages/system/Platforms/index.tsx

@@ -46,10 +46,12 @@ export default () => {
     {
       dataIndex: 'name',
       title: '名称',
+      ellipsis: true,
     },
     {
       dataIndex: 'username',
       title: '用户名',
+      ellipsis: true,
     },
     // {
     //   dataIndex: 'roleIdList',
@@ -98,6 +100,7 @@ export default () => {
         defaultMessage: '说明',
       }),
       hideInSearch: true,
+      ellipsis: true,
     },
     {
       title: intl.formatMessage({

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

@@ -55,6 +55,7 @@ export enum MENUS_CODE {
   'media/Reveal' = 'media/Reveal',
   'media/Stream' = 'media/Stream',
   'media/Stream/Detail' = 'media/Stream/Detail',
+  'media/DashBoard' = 'media/DashBoard',
   'notice/Type' = 'notice/Type',
   'notice/Config' = 'notice/Config',
   'media/SplitScreen' = 'media/SplitScreen',