Browse Source

fix(merge): merge sc

lind 3 years ago
parent
commit
219c719d75

+ 1 - 0
package.json

@@ -81,6 +81,7 @@
     "braft-editor": "^2.3.9",
     "classnames": "^2.3.1",
     "dexie": "^3.0.3",
+    "echarts": "^5.3.2",
     "event-source-polyfill": "^1.0.25",
     "isomorphic-form-data": "^2.0.0",
     "jetlinks-store": "^0.0.3",

+ 2 - 0
src/pages/Northbound/AliCloud/Detail/index.tsx

@@ -422,6 +422,8 @@ const Detail = observer(() => {
                 <a
                   style={{ wordBreak: 'break-all' }}
                   href="https://help.aliyun.com/document_detail/87368.html"
+                  target={'_blank'}
+                  rel="noreferrer"
                 >
                   https://help.aliyun.com/document_detail/87368.html
                 </a>

+ 1 - 0
src/pages/account/NotificationSubscription/index.tsx

@@ -99,6 +99,7 @@ const NotificationSubscription = observer(() => {
         disabled={record?.state?.value !== 'disabled'}
         popConfirm={{
           title: '确认删除?',
+          disabled: record?.state?.value !== 'disabled',
           onConfirm: async () => {
             const resp: any = await service.remove(record.id);
             if (resp.status === 200) {

+ 64 - 0
src/pages/device/Instance/Detail/MetadataLog/Property/Charts.tsx

@@ -0,0 +1,64 @@
+import * as echarts from 'echarts';
+import _ from 'lodash';
+import { useEffect, useRef } from 'react';
+
+interface Props {
+  data: any[];
+  min: any;
+  max: any;
+}
+
+const Charts = (props: Props) => {
+  const myChart: any = useRef(null);
+
+  useEffect(() => {
+    if ((props?.data || []).length > 2) {
+      const dom = document.getElementById('charts');
+      if (dom) {
+        const option = {
+          dataZoom: [
+            {
+              type: 'inside',
+              start: 0,
+              end: 10,
+            },
+            {
+              start: 0,
+              end: 10,
+            },
+          ],
+          tooltip: {
+            trigger: 'axis',
+            position: function (pt: any) {
+              return [pt[0], '10%'];
+            },
+          },
+          xAxis: {
+            type: 'category',
+            data: _.map(props?.data, (item) => {
+              return echarts.format.formatTime('yyyy-MM-dd\nhh:mm:ss', item.year, false);
+            }),
+            name: '时间',
+          },
+          yAxis: {
+            type: 'value',
+            name: props?.data[0].type,
+          },
+          series: [
+            {
+              data: _.map(props?.data, 'value'),
+              type: 'line',
+              areaStyle: {},
+            },
+          ],
+        };
+        myChart.current = myChart.current || echarts.init(dom);
+        myChart.current.setOption(option);
+      }
+    }
+  }, [props.data]);
+
+  return <div id="charts" style={{ width: '100%', height: 500 }}></div>;
+};
+
+export default Charts;

+ 508 - 0
src/pages/device/Instance/Detail/MetadataLog/Property/index copy.tsx

@@ -0,0 +1,508 @@
+import { InstanceModel, service } from '@/pages/device/Instance';
+import { useParams } from 'umi';
+import { DatePicker, Modal, Radio, Select, Space, Table, Tabs, Tooltip as ATooltip } from 'antd';
+import type { PropertyMetadata } from '@/pages/device/Product/typings';
+import encodeQuery from '@/utils/encodeQuery';
+import { useEffect, useState } from 'react';
+import moment from 'moment';
+import { Axis, Chart, Legend, LineAdvance, Point, Slider, Tooltip } from 'bizcharts';
+import FileComponent from '../../Running/Property/FileComponent';
+import { DownloadOutlined, SearchOutlined } from '@ant-design/icons';
+import Detail from './Detail';
+import AMap from './AMap';
+
+interface Props {
+  close: () => void;
+  data: Partial<PropertyMetadata>;
+}
+
+const PropertyLog = (props: Props) => {
+  const params = useParams<{ id: string }>();
+  const { close, data } = props;
+  const list = ['int', 'float', 'double', 'long'];
+  const [dataSource, setDataSource] = useState<any>({});
+  const [start, setStart] = useState<number>(moment().startOf('day').valueOf());
+  const [end, setEnd] = useState<number>(new Date().getTime());
+  const [radioValue, setRadioValue] = useState<undefined | 'today' | 'week' | 'month'>('today');
+  const [dateValue, setDateValue] = useState<any>(undefined);
+  const [chartsList, setChartsList] = useState<any>([]);
+  const [cycle, setCycle] = useState<string>(
+    list.includes(data.valueType?.type || '') ? '*' : '1m',
+  );
+  const [agg, setAgg] = useState<string>('AVG');
+  const [tab, setTab] = useState<string>('table');
+  const [detailVisible, setDetailVisible] = useState<boolean>(false);
+  const [current, setCurrent] = useState<any>('');
+
+  const [geoList, setGeoList] = useState<any>({});
+
+  const columns = [
+    {
+      title: '时间',
+      dataIndex: 'timestamp',
+      key: 'timestamp',
+      ellipsis: true,
+      render: (text: any) => <span>{text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : ''}</span>,
+    },
+    {
+      title: <span>{data.valueType?.type !== 'file' ? '自定义属性' : '文件内容'}</span>,
+      dataIndex: 'value',
+      key: 'value',
+      ellipsis: true,
+      render: (text: any, record: any) => (
+        <FileComponent type="table" value={{ formatValue: record.value }} data={data} />
+      ),
+    },
+    {
+      title: '操作',
+      dataIndex: 'action',
+      key: 'action',
+      render: (text: any, record: any) => (
+        <a>
+          {data.valueType?.type === 'file' && data?.valueType?.fileType == 'url' ? (
+            <ATooltip title="下载">
+              <DownloadOutlined
+                onClick={() => {
+                  const type = (record?.value || '').split('.').pop();
+                  const downloadUrl = record.value;
+                  const downNode = document.createElement('a');
+                  downNode.href = downloadUrl;
+                  downNode.target = '_blank';
+                  downNode.download = `${InstanceModel.detail.name}-${data.name}${moment(
+                    new Date().getTime(),
+                  ).format('YYYY-MM-DD-HH-mm-ss')}.${type}`;
+                  downNode.style.display = 'none';
+                  document.body.appendChild(downNode);
+                  downNode.click();
+                  document.body.removeChild(downNode);
+                }}
+              />
+            </ATooltip>
+          ) : (
+            <SearchOutlined
+              onClick={() => {
+                setDetailVisible(true);
+                setCurrent(record.value);
+              }}
+            />
+          )}
+        </a>
+      ),
+    },
+  ];
+
+  const geoColumns = [
+    {
+      title: '时间',
+      dataIndex: 'timestamp',
+      key: 'timestamp',
+      render: (text: any) => <span>{text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : ''}</span>,
+    },
+    {
+      title: '位置',
+      dataIndex: 'value',
+      key: 'value',
+      render: (text: any, record: any) => (
+        <FileComponent type="table" value={{ formatValue: record.value }} data={data} />
+      ),
+    },
+  ];
+
+  const tabList = [
+    {
+      tab: '列表',
+      key: 'table',
+    },
+    {
+      tab: '图表',
+      key: 'charts',
+    },
+  ];
+
+  const handleSearch = (param: any, startTime?: number, endTime?: number) => {
+    service
+      .getPropertyData(
+        params.id,
+        encodeQuery({
+          ...param,
+          terms: {
+            property: data.id,
+            timestamp$BTW: startTime && endTime ? [startTime, endTime] : [],
+          },
+          sorts: { timestamp: 'desc' },
+        }),
+      )
+      .then((resp) => {
+        if (resp.status === 200) {
+          setDataSource(resp.result);
+        }
+      });
+  };
+
+  const queryChartsList = async (startTime?: number, endTime?: number) => {
+    const resp = await service.queryPropertieList(params.id, data.id || '', {
+      paging: false,
+      terms: [
+        {
+          column: 'timestamp$BTW',
+          value: startTime && endTime ? [startTime, endTime] : [],
+          type: 'and',
+        },
+      ],
+      sorts: [{ name: 'timestamp', order: 'asc' }],
+    });
+    if (resp.status === 200) {
+      const dataList: any[] = [];
+      resp.result.data.forEach((i: any) => {
+        dataList.push({
+          year: moment(i.timestamp).format('YYYY-MM-DD HH:mm:ss'),
+          value: i.value,
+          type: data?.name || '',
+        });
+      });
+      setChartsList(dataList);
+    }
+  };
+
+  const queryChartsAggList = async (datas: any) => {
+    const resp = await service.queryPropertieInfo(params.id, datas);
+    if (resp.status === 200) {
+      const dataList: any[] = [];
+      resp.result.forEach((i: any) => {
+        dataList.push({
+          ...i,
+          year: moment(i.time).format('YYYY-MM-DD HH:mm:ss'),
+          value: Number(i[data.id || '']),
+          type: data?.name || '',
+        });
+      });
+      setChartsList(dataList.reverse());
+    }
+  };
+
+  useEffect(() => {
+    setRadioValue('today');
+    setTab('table');
+    setStart(moment().startOf('day').valueOf());
+    setEnd(new Date().getTime());
+  }, []);
+
+  const scale = {
+    value: { min: 0 },
+    year: {
+      type: 'time',
+      mask: 'YYYY-MM-DD HH:mm:ss',
+      // max: end,
+      // min: start,
+    },
+  };
+
+  const renderComponent = (type: string) => {
+    switch (type) {
+      case 'table':
+        return (
+          <Table
+            size="small"
+            rowKey={'id'}
+            onChange={(page) => {
+              handleSearch(
+                {
+                  pageSize: page.pageSize,
+                  pageIndex: Number(page.current) - 1 || 0,
+                },
+                start,
+                end,
+              );
+            }}
+            dataSource={dataSource?.data || []}
+            columns={data?.valueType?.type === 'geoPoint' ? geoColumns : columns}
+            pagination={{
+              current: (dataSource?.pageIndex || 0) + 1,
+              pageSize: dataSource?.pageSize || 10,
+              showSizeChanger: true,
+              total: dataSource?.total || 0,
+            }}
+          />
+        );
+      case 'charts':
+        return (
+          <div>
+            <div style={{ margin: '10 0', display: 'flex' }}>
+              <div style={{ marginRight: 20 }}>
+                统计周期:
+                <Select
+                  value={cycle}
+                  style={{ width: 120 }}
+                  onChange={(value: string) => {
+                    setCycle(value);
+                    if (value === '*') {
+                      queryChartsList(start, end);
+                    } else {
+                      queryChartsAggList({
+                        columns: [
+                          {
+                            property: data.id,
+                            alias: data.id,
+                            agg: agg,
+                          },
+                        ],
+                        query: {
+                          interval: value,
+                          format: 'yyyy-MM-dd HH:mm:ss',
+                          from: start,
+                          to: end,
+                        },
+                      });
+                    }
+                  }}
+                >
+                  {list.includes(data.valueType?.type || '') && (
+                    <Select.Option value="*">实际值</Select.Option>
+                  )}
+                  <Select.Option value="1m">按分钟统计</Select.Option>
+                  <Select.Option value="1h">按小时统计</Select.Option>
+                  <Select.Option value="1d">按天统计</Select.Option>
+                  <Select.Option value="1w">按周统计</Select.Option>
+                  <Select.Option value="1M">按月统计</Select.Option>
+                </Select>
+              </div>
+              {cycle !== '*' && list.includes(data.valueType?.type || '') && (
+                <div>
+                  统计规则:
+                  <Select
+                    defaultValue="AVG"
+                    style={{ width: 120 }}
+                    onChange={(value: string) => {
+                      setAgg(value);
+                      queryChartsAggList({
+                        columns: [
+                          {
+                            property: data.id,
+                            alias: data.id,
+                            agg: value,
+                          },
+                        ],
+                        query: {
+                          interval: cycle,
+                          format: 'yyyy-MM-dd HH:mm:ss',
+                          from: start,
+                          to: end,
+                        },
+                      });
+                    }}
+                  >
+                    <Select.Option value="AVG">平均值</Select.Option>
+                    <Select.Option value="MAX">最大值</Select.Option>
+                    <Select.Option value="MIN">最小值</Select.Option>
+                    <Select.Option value="COUNT">总数</Select.Option>
+                  </Select>
+                </div>
+              )}
+            </div>
+            <div style={{ marginTop: 10 }}>
+              <Chart height={400} data={chartsList} scale={scale} padding="auto" autoFit>
+                <Legend />
+                <Axis name="year" />
+                <Axis
+                  name="value"
+                  label={{
+                    formatter: (val) => parseFloat(val).toLocaleString(),
+                  }}
+                />
+                <Tooltip shared />
+                <Point position="year*value" />
+                <LineAdvance position="year*value" shape="smooth" area />
+                <Slider />
+              </Chart>
+            </div>
+          </div>
+        );
+      default:
+        return null;
+    }
+  };
+
+  useEffect(() => {
+    if (tab === 'table') {
+      handleSearch(
+        {
+          pageSize: 10,
+          pageIndex: 0,
+        },
+        start,
+        end,
+      );
+    } else if (tab === 'charts') {
+      if (list.includes(data.valueType?.type || '')) {
+        queryChartsList(start, end);
+      } else {
+        queryChartsAggList({
+          columns: [
+            {
+              property: data.id,
+              alias: data.id,
+              agg,
+            },
+          ],
+          query: {
+            interval: cycle,
+            format: 'yyyy-MM-dd HH:mm:ss',
+            from: start,
+            to: end,
+          },
+        });
+      }
+    } else if (tab === 'geo') {
+      service
+        .getPropertyData(
+          params.id,
+          encodeQuery({
+            paging: false,
+            terms: { property: data?.id, timestamp$BTW: start && start ? [start, end] : [] },
+            sorts: { timestamp: 'asc' },
+          }),
+        )
+        .then((resp) => {
+          if (resp.status === 200) {
+            setGeoList(resp.result);
+          }
+        });
+    }
+    setDateValue([moment(start), moment(end)]);
+  }, [start, end]);
+
+  // @ts-ignore
+  return (
+    <Modal
+      maskClosable={false}
+      title="详情"
+      visible
+      onCancel={() => close()}
+      onOk={() => close()}
+      width="50vw"
+    >
+      <div style={{ marginBottom: '20px' }}>
+        <Space>
+          <Radio.Group
+            value={radioValue}
+            buttonStyle="solid"
+            onChange={(e) => {
+              const value = e.target.value;
+              setRadioValue(value);
+              let st: number = 0;
+              const et = new Date().getTime();
+              if (value === 'today') {
+                st = moment().startOf('day').valueOf();
+              } else if (value === 'week') {
+                st = moment().subtract(6, 'days').valueOf();
+              } else if (value === 'month') {
+                st = moment().subtract(29, 'days').valueOf();
+              }
+              setDateValue(undefined);
+              setStart(st);
+              setEnd(et);
+            }}
+            style={{ minWidth: 220 }}
+          >
+            <Radio.Button value="today">今日</Radio.Button>
+            <Radio.Button value="week">近一周</Radio.Button>
+            <Radio.Button value="month">近一月</Radio.Button>
+          </Radio.Group>
+          {
+            // @ts-ignore
+            <DatePicker.RangePicker
+              value={dateValue}
+              showTime
+              onChange={(dates: any) => {
+                if (dates) {
+                  setRadioValue(undefined);
+                  setDateValue(dates);
+                  const st = dates[0]?.valueOf();
+                  const et = dates[1]?.valueOf();
+                  setStart(st);
+                  setEnd(et);
+                }
+              }}
+            />
+          }
+        </Space>
+      </div>
+      <Tabs
+        activeKey={tab}
+        onChange={(key: string) => {
+          setTab(key);
+          if (key === 'charts' && !!data.valueType?.type) {
+            if (list.includes(data.valueType?.type)) {
+              queryChartsList(start, end);
+            } else {
+              setCycle('1m');
+              setAgg('COUNT');
+              queryChartsAggList({
+                columns: [
+                  {
+                    property: data.id,
+                    alias: data.id,
+                    agg: 'COUNT',
+                  },
+                ],
+                query: {
+                  interval: '1m',
+                  format: 'yyyy-MM-dd HH:mm:ss',
+                  from: start,
+                  to: end,
+                },
+              });
+            }
+          }
+          if (key === 'geo') {
+            service
+              .getPropertyData(
+                params.id,
+                encodeQuery({
+                  paging: false,
+                  terms: { property: data.id, timestamp$BTW: start && end ? [start, end] : [] },
+                  sorts: { timestamp: 'asc' },
+                }),
+              )
+              .then((resp) => {
+                if (resp.status === 200) {
+                  setGeoList(resp.result);
+                }
+              });
+          }
+          if (key === 'table') {
+            handleSearch(
+              {
+                pageSize: 10,
+                pageIndex: 0,
+              },
+              start,
+              end,
+            );
+          }
+        }}
+      >
+        {tabList.map((item) => (
+          <Tabs.TabPane tab={item.tab} key={item.key}>
+            {renderComponent(item.key)}
+          </Tabs.TabPane>
+        ))}
+        {data?.valueType?.type === 'geoPoint' && (
+          <Tabs.TabPane tab="轨迹" key="geo">
+            <AMap value={geoList} name={data?.name || ''} />
+          </Tabs.TabPane>
+        )}
+      </Tabs>
+      {detailVisible && (
+        <Detail
+          close={() => {
+            setDetailVisible(false);
+          }}
+          value={current}
+          type={data.valueType?.type || ''}
+        />
+      )}
+    </Modal>
+  );
+};
+export default PropertyLog;

+ 165 - 140
src/pages/device/Instance/Detail/MetadataLog/Property/index.tsx

@@ -1,15 +1,26 @@
 import { InstanceModel, service } from '@/pages/device/Instance';
 import { useParams } from 'umi';
-import { DatePicker, Modal, Radio, Select, Space, Table, Tabs, Tooltip as ATooltip } from 'antd';
+import {
+  DatePicker,
+  Modal,
+  Radio,
+  Select,
+  Space,
+  Spin,
+  Table,
+  Tabs,
+  Tooltip as ATooltip,
+} from 'antd';
 import type { PropertyMetadata } from '@/pages/device/Product/typings';
 import encodeQuery from '@/utils/encodeQuery';
 import { useEffect, useState } from 'react';
 import moment from 'moment';
-import { Axis, Chart, LineAdvance, Legend, Slider, Tooltip, Point } from 'bizcharts';
 import FileComponent from '../../Running/Property/FileComponent';
 import { DownloadOutlined, SearchOutlined } from '@ant-design/icons';
 import Detail from './Detail';
 import AMap from './AMap';
+import Charts from './Charts';
+
 interface Props {
   close: () => void;
   data: Partial<PropertyMetadata>;
@@ -34,6 +45,7 @@ const PropertyLog = (props: Props) => {
   const [current, setCurrent] = useState<any>('');
 
   const [geoList, setGeoList] = useState<any>({});
+  const [loading, setLoading] = useState<boolean>(true);
 
   const columns = [
     {
@@ -119,6 +131,7 @@ const PropertyLog = (props: Props) => {
   ];
 
   const handleSearch = (param: any, startTime?: number, endTime?: number) => {
+    setLoading(true);
     service
       .getPropertyData(
         params.id,
@@ -132,6 +145,7 @@ const PropertyLog = (props: Props) => {
         }),
       )
       .then((resp) => {
+        setLoading(false);
         if (resp.status === 200) {
           setDataSource(resp.result);
         }
@@ -139,6 +153,7 @@ const PropertyLog = (props: Props) => {
   };
 
   const queryChartsList = async (startTime?: number, endTime?: number) => {
+    setLoading(true);
     const resp = await service.queryPropertieList(params.id, data.id || '', {
       paging: false,
       terms: [
@@ -150,32 +165,59 @@ const PropertyLog = (props: Props) => {
       ],
       sorts: [{ name: 'timestamp', order: 'asc' }],
     });
+    setLoading(false);
     if (resp.status === 200) {
-      const dataList: any[] = [];
+      const dataList: any[] = [
+        {
+          year: start,
+          value: undefined,
+          type: data?.name || '',
+        },
+      ];
       resp.result.data.forEach((i: any) => {
         dataList.push({
-          year: moment(i.timestamp).format('YYYY-MM-DD HH:mm:ss'),
+          ...i,
+          year: i.timestamp, //moment(i.timestamp).format('YYYY-MM-DD HH:mm:ss'),
           value: i.value,
           type: data?.name || '',
         });
       });
-      setChartsList(dataList);
+      dataList.push({
+        year: end,
+        value: undefined,
+        type: data?.name || '',
+      });
+      console.log(dataList.length);
+      setChartsList(dataList || []);
     }
   };
 
   const queryChartsAggList = async (datas: any) => {
+    setLoading(true);
     const resp = await service.queryPropertieInfo(params.id, datas);
+    setLoading(false);
     if (resp.status === 200) {
-      const dataList: any[] = [];
+      const dataList: any[] = [
+        {
+          year: start,
+          value: undefined,
+          type: data?.name || '',
+        },
+      ];
       resp.result.forEach((i: any) => {
         dataList.push({
           ...i,
-          year: moment(i.time).format('YYYY-MM-DD HH:mm:ss'),
+          year: i.time, // moment(i.time).format('YYYY-MM-DD HH:mm:ss'),
           value: Number(i[data.id || '']),
           type: data?.name || '',
         });
       });
-      setChartsList(dataList.reverse());
+      dataList.push({
+        year: end,
+        value: undefined,
+        type: data?.name || '',
+      });
+      setChartsList((dataList || []).reverse());
     }
   };
 
@@ -186,16 +228,6 @@ const PropertyLog = (props: Props) => {
     setEnd(new Date().getTime());
   }, []);
 
-  const scale = {
-    value: { min: 0 },
-    year: {
-      type: 'time',
-      mask: 'YYYY-MM-DD HH:mm:ss',
-      max: end,
-      min: start,
-    },
-  };
-
   const renderComponent = (type: string) => {
     switch (type) {
       case 'table':
@@ -298,21 +330,8 @@ const PropertyLog = (props: Props) => {
                 </div>
               )}
             </div>
-            <div style={{ marginTop: 10 }}>
-              <Chart height={400} data={chartsList} scale={scale} padding="auto" autoFit>
-                <Legend />
-                <Axis name="year" />
-                <Axis
-                  name="value"
-                  label={{
-                    formatter: (val) => parseFloat(val).toLocaleString(),
-                  }}
-                />
-                <Tooltip shared />
-                <Point position="year*value" />
-                <LineAdvance position="year*value" shape="smooth" area />
-                <Slider />
-              </Chart>
+            <div>
+              <Charts data={chartsList} min={start} max={end} />
             </div>
           </div>
         );
@@ -352,6 +371,7 @@ const PropertyLog = (props: Props) => {
         });
       }
     } else if (tab === 'geo') {
+      setLoading(true);
       service
         .getPropertyData(
           params.id,
@@ -362,6 +382,7 @@ const PropertyLog = (props: Props) => {
           }),
         )
         .then((resp) => {
+          setLoading(false);
           if (resp.status === 200) {
             setGeoList(resp.result);
           }
@@ -380,118 +401,122 @@ const PropertyLog = (props: Props) => {
       onOk={() => close()}
       width="50vw"
     >
-      <div style={{ marginBottom: '20px' }}>
-        <Space>
-          <Radio.Group
-            value={radioValue}
-            buttonStyle="solid"
-            onChange={(e) => {
-              const value = e.target.value;
-              setRadioValue(value);
-              let st: number = 0;
-              const et = new Date().getTime();
-              if (value === 'today') {
-                st = moment().startOf('day').valueOf();
-              } else if (value === 'week') {
-                st = moment().subtract(6, 'days').valueOf();
-              } else if (value === 'month') {
-                st = moment().subtract(29, 'days').valueOf();
-              }
-              setDateValue(undefined);
-              setStart(st);
-              setEnd(et);
-            }}
-            style={{ minWidth: 220 }}
-          >
-            <Radio.Button value="today">今日</Radio.Button>
-            <Radio.Button value="week">近一周</Radio.Button>
-            <Radio.Button value="month">近一月</Radio.Button>
-          </Radio.Group>
-          {
-            // @ts-ignore
-            <DatePicker.RangePicker
-              value={dateValue}
-              showTime
-              onChange={(dates: any) => {
-                if (dates) {
-                  setRadioValue(undefined);
-                  setDateValue(dates);
-                  const st = dates[0]?.valueOf();
-                  const et = dates[1]?.valueOf();
-                  setStart(st);
-                  setEnd(et);
+      <Spin spinning={loading}>
+        <div style={{ marginBottom: '20px' }}>
+          <Space>
+            <Radio.Group
+              value={radioValue}
+              buttonStyle="solid"
+              onChange={(e) => {
+                const value = e.target.value;
+                setRadioValue(value);
+                let st: number = 0;
+                const et = new Date().getTime();
+                if (value === 'today') {
+                  st = moment().startOf('day').valueOf();
+                } else if (value === 'week') {
+                  st = moment().subtract(6, 'days').valueOf();
+                } else if (value === 'month') {
+                  st = moment().subtract(29, 'days').valueOf();
                 }
+                setDateValue(undefined);
+                setStart(st);
+                setEnd(et);
               }}
-            />
-          }
-        </Space>
-      </div>
-      <Tabs
-        activeKey={tab}
-        onChange={(key: string) => {
-          setTab(key);
-          if (key === 'charts' && !!data.valueType?.type) {
-            if (list.includes(data.valueType?.type)) {
-              queryChartsList(start, end);
-            } else {
-              setCycle('1m');
-              setAgg('COUNT');
-              queryChartsAggList({
-                columns: [
-                  {
-                    property: data.id,
-                    alias: data.id,
-                    agg: 'COUNT',
+              style={{ minWidth: 220 }}
+            >
+              <Radio.Button value="today">今日</Radio.Button>
+              <Radio.Button value="week">近一周</Radio.Button>
+              <Radio.Button value="month">近一月</Radio.Button>
+            </Radio.Group>
+            {
+              // @ts-ignore
+              <DatePicker.RangePicker
+                value={dateValue}
+                showTime
+                onChange={(dates: any) => {
+                  if (dates) {
+                    setRadioValue(undefined);
+                    setDateValue(dates);
+                    const st = dates[0]?.valueOf();
+                    const et = dates[1]?.valueOf();
+                    setStart(st);
+                    setEnd(et);
+                  }
+                }}
+              />
+            }
+          </Space>
+        </div>
+        <Tabs
+          activeKey={tab}
+          onChange={(key: string) => {
+            setTab(key);
+            if (key === 'charts' && !!data.valueType?.type) {
+              if (list.includes(data.valueType?.type)) {
+                queryChartsList(start, end);
+              } else {
+                setCycle('1m');
+                setAgg('COUNT');
+                queryChartsAggList({
+                  columns: [
+                    {
+                      property: data.id,
+                      alias: data.id,
+                      agg: 'COUNT',
+                    },
+                  ],
+                  query: {
+                    interval: '1m',
+                    format: 'yyyy-MM-dd HH:mm:ss',
+                    from: start,
+                    to: end,
                   },
-                ],
-                query: {
-                  interval: '1m',
-                  format: 'yyyy-MM-dd HH:mm:ss',
-                  from: start,
-                  to: end,
+                });
+              }
+            }
+            if (key === 'geo') {
+              setLoading(true);
+              service
+                .getPropertyData(
+                  params.id,
+                  encodeQuery({
+                    paging: false,
+                    terms: { property: data.id, timestamp$BTW: start && end ? [start, end] : [] },
+                    sorts: { timestamp: 'asc' },
+                  }),
+                )
+                .then((resp) => {
+                  setLoading(false);
+                  if (resp.status === 200) {
+                    setGeoList(resp.result);
+                  }
+                });
+            }
+            if (key === 'table') {
+              handleSearch(
+                {
+                  pageSize: 10,
+                  pageIndex: 0,
                 },
-              });
+                start,
+                end,
+              );
             }
-          }
-          if (key === 'geo') {
-            service
-              .getPropertyData(
-                params.id,
-                encodeQuery({
-                  paging: false,
-                  terms: { property: data.id, timestamp$BTW: start && end ? [start, end] : [] },
-                  sorts: { timestamp: 'asc' },
-                }),
-              )
-              .then((resp) => {
-                if (resp.status === 200) {
-                  setGeoList(resp.result);
-                }
-              });
-          }
-          if (key === 'table') {
-            handleSearch(
-              {
-                pageSize: 10,
-                pageIndex: 0,
-              },
-              start,
-              end,
-            );
-          }
-        }}
-      >
-        {tabList.map((item) => (
-          <Tabs.TabPane tab={item.tab} key={item.key}>
-            {renderComponent(item.key)}
-          </Tabs.TabPane>
-        ))}
-        {data?.valueType?.type === 'geoPoint' && (
-          <Tabs.TabPane tab="轨迹" key="geo">
-            <AMap value={geoList} name={data?.name || ''} />
-          </Tabs.TabPane>
-        )}
-      </Tabs>
+          }}
+        >
+          {tabList.map((item) => (
+            <Tabs.TabPane tab={item.tab} key={item.key}>
+              {renderComponent(item.key)}
+            </Tabs.TabPane>
+          ))}
+          {data?.valueType?.type === 'geoPoint' && (
+            <Tabs.TabPane tab="轨迹" key="geo">
+              <AMap value={geoList} name={data?.name || ''} />
+            </Tabs.TabPane>
+          )}
+        </Tabs>
+      </Spin>
       {detailVisible && (
         <Detail
           close={() => {

+ 2 - 2
src/pages/rule-engine/Alarm/Config/index.tsx

@@ -314,7 +314,7 @@ const Config = () => {
           username: {
             title: '用户名',
             type: 'string',
-            required: true,
+            // required: true,
             'x-decorator': 'FormItem',
             'x-component': 'Input',
             'x-component-props': {
@@ -327,7 +327,7 @@ const Config = () => {
           password: {
             title: '密码',
             type: 'string',
-            required: true,
+            // required: true,
             'x-decorator': 'FormItem',
             'x-component': 'Input',
             'x-decorator-props': {

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

@@ -78,6 +78,7 @@ export default () => {
 
         setTriggerValue({ trigger: _data.terms || [] });
         setTriggerDatas(_data.trigger);
+        setActionParams({ trigger: _data.trigger });
         if (_data.trigger?.shakeLimit) {
           setShakeLimit(_data.trigger?.shakeLimit || DefaultShakeLimit);
         }
@@ -224,7 +225,7 @@ export default () => {
                   setTriggerDatas(allValues.trigger);
                 }
               } else if (['timer', 'manual'].includes(changeValue.trigger.type)) {
-                setActionParams({ trigger: allValues.trigger });
+                setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
               }
             }
 

+ 0 - 1
src/pages/system/Platforms/Api/base.tsx

@@ -33,7 +33,6 @@ export default observer((props: ApiPageProps) => {
 
   const initModel = () => {
     ApiModel.data = [];
-    ApiModel.baseUrl = '';
     ApiModel.showTable = true;
     ApiModel.components = {};
     ApiModel.swagger = {};

+ 0 - 1
src/pages/system/Platforms/Api/leftTree.tsx

@@ -71,7 +71,6 @@ export default (props: LeftTreeType) => {
       const resp = await service.getApiNextLevel(name);
       if (resp) {
         ApiModel.components = resp.components;
-        ApiModel.baseUrl = resp.servers[0].url;
         const handleData = handleTreeData(resp);
         setTreeData((origin) => {
           const data = updateTreeData(origin, key, handleData);

+ 5 - 5
src/pages/system/Platforms/Api/swagger-ui/debugging.tsx

@@ -3,13 +3,13 @@ import ReactJson from 'react-json-view';
 import { request } from 'umi';
 import MonacoEditor from 'react-monaco-editor';
 import { Button, Input } from 'antd';
-import { useCallback, useEffect, useMemo, useState, useRef } from 'react';
-import { observer } from '@formily/react';
+import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { createSchemaField, FormProvider, observer } from '@formily/react';
 import { ApiModel } from '@/pages/system/Platforms/Api/base';
 import { createForm } from '@formily/core';
-import { createSchemaField, FormProvider } from '@formily/react';
-import { FormItem, Input as FormilyInput, ArrayTable, Editable } from '@formily/antd';
+import { ArrayTable, Editable, FormItem, Input as FormilyInput } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
+import SystemConst from '@/utils/const';
 import classNames from 'classnames';
 
 export default observer(() => {
@@ -76,7 +76,7 @@ export default observer(() => {
       };
     }
 
-    request(`${ApiModel.baseUrl}${newUrl}`, options).then((resp) => {
+    request(`/${SystemConst.API_BASE}${newUrl}`, options).then((resp) => {
       if (resp.status === 200) {
         setResult(resp);
       } else {

+ 7 - 7
src/pages/system/Platforms/save.tsx

@@ -1,5 +1,5 @@
-import { createForm, onFieldValueChange } from '@formily/core';
 import type { Field } from '@formily/core';
+import { createForm, onFieldValueChange } from '@formily/core';
 import { createSchemaField } from '@formily/react';
 import {
   Checkbox,
@@ -78,11 +78,10 @@ export default (props: SaveProps) => {
   const form = useMemo(
     () =>
       createForm({
-        validateFirst: false,
         effects() {
           onFieldValueChange('enableOAuth2', (field) => {
             form.setFieldState('redirectUrl', (state) => {
-              state.display = field.value ? 'visible' : 'none';
+              state.visible = field.value;
             });
           });
         },
@@ -93,7 +92,7 @@ export default (props: SaveProps) => {
   const getDetail = async (id: string) => {
     const resp = await service.getDetail(id);
     if (resp.status === 200) {
-      form.setValues({
+      form.setInitialValues({
         ...resp.result,
         confirm_password: resp.result.password,
       });
@@ -105,7 +104,7 @@ export default (props: SaveProps) => {
       if (props.type === 'edit') {
         getDetail(props.data.id);
       } else {
-        form.setValues({
+        form.setInitialValues({
           enableOAuth2: false,
           id: randomString(16),
           secureKey: randomString(),
@@ -378,7 +377,8 @@ export default (props: SaveProps) => {
             'x-component-props': {
               placeholder: '请输入redirectUrl',
             },
-            'x-hidden': true,
+            // 'x-hidden': true,
+            'x-visible': false,
             'x-decorator-props': {
               gridSpan: 2,
               tooltip: '授权后自动跳转的页面地址',
@@ -439,9 +439,9 @@ export default (props: SaveProps) => {
   };
 
   const saveData = useCallback(async () => {
-    // setLoading(true)
     const data: any = await form.submit();
     if (data) {
+      console.log(data);
       setLoading(true);
       const resp: any = props.type === 'edit' ? await service.edit(data) : await service.save(data);
       setLoading(false);

+ 20 - 0
yarn.lock

@@ -8682,6 +8682,14 @@ ecc-jsbn@~0.1.1:
     jsbn "~0.1.0"
     safer-buffer "^2.1.0"
 
+echarts@^5.3.2:
+  version "5.3.2"
+  resolved "https://registry.npmmirror.com/echarts/-/echarts-5.3.2.tgz#0a7b3be8c48a48b2e7cb1b82121df0c208d42d2c"
+  integrity sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==
+  dependencies:
+    tslib "2.3.0"
+    zrender "5.3.1"
+
 ee-first@1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -19858,6 +19866,11 @@ ts-easing@^0.2.0:
   resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec"
   integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==
 
+tslib@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
+  integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
+
 tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
   version "1.14.1"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@@ -21157,6 +21170,13 @@ zenscroll@^4.0.2:
   resolved "https://registry.yarnpkg.com/zenscroll/-/zenscroll-4.0.2.tgz#e8d5774d1c0738a47bcfa8729f3712e2deddeb25"
   integrity sha1-6NV3TRwHOKR7z6hynzcS4t7d6yU=
 
+zrender@5.3.1:
+  version "5.3.1"
+  resolved "https://registry.npmmirror.com/zrender/-/zrender-5.3.1.tgz#fa8e63ac7e719cfd563831fe8c42a9756c5af384"
+  integrity sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==
+  dependencies:
+    tslib "2.3.0"
+
 zscroller@~0.4.0:
   version "0.4.8"
   resolved "https://registry.yarnpkg.com/zscroller/-/zscroller-0.4.8.tgz#69eed68690808eedf81f9714014356b36cdd20f4"