wzyyy 3 лет назад
Родитель
Сommit
3463a5dbfd
31 измененных файлов с 739 добавлено и 2162 удалено
  1. 2 2
      config/proxy.ts
  2. BIN
      public/images/diagnose copy/back.png
  3. BIN
      public/images/diagnose copy/message-error.png
  4. BIN
      public/images/diagnose copy/status-error.png
  5. BIN
      public/images/diagnose copy/status-success-active.png
  6. BIN
      public/images/diagnose copy/status-success.png
  7. BIN
      public/images/diagnose copy/status/error.png
  8. BIN
      public/images/diagnose copy/status/loading.png
  9. BIN
      public/images/diagnose copy/status/success.png
  10. BIN
      public/images/diagnose copy/status/warning.png
  11. BIN
      public/images/diagnose copy/waiting.png
  12. 2 2
      src/components/FUpload/index.tsx
  13. 31 20
      src/pages/device/Firmware/Task/Detail/index.tsx
  14. 16 12
      src/pages/device/Firmware/Task/index.tsx
  15. 9 3
      src/pages/device/Firmware/service.ts
  16. 6 6
      src/pages/device/Instance/Detail/Diagnose/Status/index.tsx
  17. 1 1
      src/pages/device/Instance/Detail/Diagnose/Status/model.ts
  18. 263 1891
      src/pages/init-home/components/data/RoleData.ts
  19. 8 13
      src/pages/link/Type/Detail/index.tsx
  20. 1 1
      src/pages/notice/Template/Detail/doc/DingTalkRebot.tsx
  21. 63 43
      src/pages/rule-engine/DashBoard/index.tsx
  22. 17 1
      src/pages/rule-engine/Scene/Save/action/action.tsx
  23. 17 6
      src/pages/rule-engine/Scene/Save/action/device/ConditionalFiltering.tsx
  24. 2 0
      src/pages/rule-engine/Scene/Save/action/device/WriteProperty/index.tsx
  25. 11 1
      src/pages/rule-engine/Scene/Save/action/device/deviceModal.tsx
  26. 6 1
      src/pages/rule-engine/Scene/Save/action/device/index.tsx
  27. 2 0
      src/pages/rule-engine/Scene/Save/action/device/readProperty.tsx
  28. 202 120
      src/pages/rule-engine/Scene/Save/components/TimingTrigger/refactor.tsx
  29. 9 11
      src/pages/rule-engine/Scene/Save/trigger/index.tsx
  30. 17 1
      src/pages/rule-engine/Scene/TriggerTerm/index.tsx
  31. 54 27
      src/pages/system/Menu/Setting/tree.tsx

+ 2 - 2
config/proxy.ts

@@ -12,8 +12,8 @@ export default {
       target: 'http://192.168.32.28:8844/',
       ws: 'ws://192.168.32.28:8844/',
       // 开发环境
-      // target: 'http://120.79.18.123:8844/',
-      // ws: 'ws://120.79.18.123:8844/',
+      target: 'http://120.79.18.123:8844/',
+      ws: 'ws://120.79.18.123:8844/',
       // 测试环境
       // target: 'http://120.77.179.54:8844/',
       // ws: 'ws://120.77.179.54:8844/',

BIN
public/images/diagnose copy/back.png


BIN
public/images/diagnose copy/message-error.png


BIN
public/images/diagnose copy/status-error.png


BIN
public/images/diagnose copy/status-success-active.png


BIN
public/images/diagnose copy/status-success.png


BIN
public/images/diagnose copy/status/error.png


BIN
public/images/diagnose copy/status/loading.png


BIN
public/images/diagnose copy/status/success.png


BIN
public/images/diagnose copy/status/warning.png


BIN
public/images/diagnose copy/waiting.png


+ 2 - 2
src/components/FUpload/index.tsx

@@ -20,10 +20,10 @@ const FUpload = connect((props: Props) => {
   const handleChange = async (info: UploadChangeParam) => {
     if (info.file.status === 'done') {
       const result = info.file.response?.result;
-      const api = await service.querySystemApi();
+      const api = await service.querySystemApi(['basePath']);
       const f = {
         ...result,
-        url: `${api?.result?.basePath}file/${result?.id}?accessKey=${result?.others?.accessKey}`,
+        url: `${api?.result[0]?.properties?.basePath}file/${result?.id}?accessKey=${result?.others?.accessKey}`,
       };
       setUrl(f.url);
       props.onChange(f);

+ 31 - 20
src/pages/device/Firmware/Task/Detail/index.tsx

@@ -29,12 +29,14 @@ const state = model<{
   finish: number;
   error: number;
   canceled: number;
+  info: any;
 }>({
   waiting: 0,
   loading: 0,
   finish: 0,
   error: 0,
   canceled: 0,
+  info: {},
 });
 
 const Detail = observer(() => {
@@ -173,6 +175,11 @@ const Detail = observer(() => {
   };
 
   useEffect(() => {
+    service.taskById(params.id).then((resp) => {
+      if (resp.status === 200) {
+        state.info = resp.result;
+      }
+    });
     handleSearch();
   }, [params.id]);
 
@@ -248,7 +255,7 @@ const Detail = observer(() => {
           status: 'success',
         },
         canceled: {
-          text: '已取消',
+          text: '已停止',
           status: 'canceled',
         },
       },
@@ -281,24 +288,28 @@ const Detail = observer(() => {
                   <SearchOutlined />
                 </Tooltip>
               </a>,
-              <Popconfirm
-                key="refresh"
-                onConfirm={async () => {
-                  const resp = await service.startOneTask([record.id]);
-                  if (resp.status === 200) {
-                    message.success('操作成功!');
-                    handleSearch();
-                    actionRef.current?.reload?.();
-                  }
-                }}
-                title={'确认重试'}
-              >
-                <a>
-                  <Tooltip title={'重试'} key={'refresh'}>
-                    <RedoOutlined />
-                  </Tooltip>
-                </a>
-              </Popconfirm>,
+              <>
+                {state.info?.mode?.value === 'push' ? (
+                  <Popconfirm
+                    key="refresh"
+                    onConfirm={async () => {
+                      const resp = await service.startOneTask([record.id]);
+                      if (resp.status === 200) {
+                        message.success('操作成功!');
+                        handleSearch();
+                        actionRef.current?.reload?.();
+                      }
+                    }}
+                    title={'确认重试'}
+                  >
+                    <a>
+                      <Tooltip title={'重试'} key={'refresh'}>
+                        <RedoOutlined />
+                      </Tooltip>
+                    </a>
+                  </Popconfirm>
+                ) : null}
+              </>,
             ]
           : [],
     },
@@ -317,7 +328,7 @@ const Detail = observer(() => {
                     {item.name}
                   </div>
                   <div className={styles.firmwareDetailCardRight}>
-                    {item.key === 'error' && (
+                    {item.key === 'error' && state.info?.mode?.value === 'push' && (
                       <Popconfirm
                         title="确认批量重试"
                         onConfirm={async () => {

+ 16 - 12
src/pages/device/Firmware/Task/index.tsx

@@ -26,13 +26,10 @@ import { service } from '@/pages/device/Firmware';
 
 const UpgradeBtn = (props: { data: any; actions: any }) => {
   const { data, actions } = props;
-  if (data.progress === 100) {
-    return null;
-  }
-  return (
-    <a>
-      <Tooltip title={data.waiting ? '停止' : '继续升级'}>
-        {data.waiting ? (
+  if (data.waiting && data?.state?.value === 'processing') {
+    return (
+      <a>
+        <Tooltip title={'停止'}>
           <StopOutlined
             onClick={async () => {
               const resp = await service.stopTask(data.id);
@@ -42,7 +39,13 @@ const UpgradeBtn = (props: { data: any; actions: any }) => {
               }
             }}
           />
-        ) : (
+        </Tooltip>
+      </a>
+    );
+  } else if (data?.state?.value === 'canceled') {
+    return (
+      <a>
+        <Tooltip title={'继续升级'}>
           <ControlOutlined
             onClick={async () => {
               const resp = await service.startTask(data.id, ['canceled']);
@@ -52,10 +55,11 @@ const UpgradeBtn = (props: { data: any; actions: any }) => {
               }
             }}
           />
-        )}
-      </Tooltip>
-    </a>
-  );
+        </Tooltip>
+      </a>
+    );
+  }
+  return null;
 };
 
 export const state = model<{

+ 9 - 3
src/pages/device/Firmware/service.ts

@@ -4,9 +4,10 @@ import SystemConst from '@/utils/const';
 import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 
 class Service extends BaseService<FirmwareItem> {
-  querySystemApi = () =>
-    request(`/${SystemConst.API_BASE}/system/apis`, {
-      method: 'GET',
+  querySystemApi = (data?: any) =>
+    request(`/${SystemConst.API_BASE}/system/config/scopes`, {
+      method: 'POST',
+      data,
     });
 
   task = (params: Record<string, unknown>) =>
@@ -15,6 +16,11 @@ class Service extends BaseService<FirmwareItem> {
       data: params,
     });
 
+  taskById = (id: string) =>
+    request(`/${SystemConst.API_BASE}/firmware/upgrade/task/${id}`, {
+      method: 'GET',
+    });
+
   saveTask = (data: Record<string, unknown>) =>
     request(`/${SystemConst.API_BASE}/firmware/upgrade/task`, {
       method: 'POST',

+ 6 - 6
src/pages/device/Instance/Detail/Diagnose/Status/index.tsx

@@ -285,7 +285,7 @@ const Status = observer((props: Props) => {
                     key: 'gateway',
                     name: '设备接入网关',
                     desc: desc,
-                    status: 'error',
+                    status: 'warning',
                     text: '可能存在异常',
                     info: (
                       <div>
@@ -416,7 +416,7 @@ const Status = observer((props: Props) => {
                 key: 'gateway',
                 name: '设备接入网关',
                 desc: desc,
-                status: 'error',
+                status: 'warning',
                 text: '可能存在异常',
                 info: (
                   <div>
@@ -965,7 +965,7 @@ const Status = observer((props: Props) => {
                   key: `product-auth${i}`,
                   name: `产品-${item?.name}`,
                   desc: '诊断产品MQTT认证配置是否正确,错误的配置将导致连接失败',
-                  status: 'error',
+                  status: 'warning',
                   text: '可能存在异常',
                   info: (
                     <div>
@@ -1129,7 +1129,7 @@ const Status = observer((props: Props) => {
                   key: `device-auth${i}`,
                   name: `设备-${item?.name}`,
                   desc: '诊断设备MQTT认证配置是否正确,错误的配置将导致连接失败',
-                  status: 'error',
+                  status: 'warning',
                   text: '可能存在异常',
                   info: (
                     <div>
@@ -1409,7 +1409,7 @@ const Status = observer((props: Props) => {
             key: `onenet`,
             name: `设备-OneNet配置`,
             desc: '诊断设备OneNet是否已配置,未配置将导致连接失败',
-            status: 'error',
+            status: 'warning',
             text: '可能存在异常',
             info: (
               <div>
@@ -1524,7 +1524,7 @@ const Status = observer((props: Props) => {
             key: `ctwing`,
             name: `设备-CTWing配置`,
             desc: '诊断设备CTWing是否已配置,未配置将导致连接失败',
-            status: 'error',
+            status: 'warning',
             text: '可能存在异常',
             info: (
               <div>

+ 1 - 1
src/pages/device/Instance/Detail/Diagnose/Status/model.ts

@@ -13,7 +13,7 @@ export const TextColorMap = new Map();
 TextColorMap.set('loading', 'black');
 TextColorMap.set('error', 'red');
 TextColorMap.set('success', 'green');
-TextColorMap.set('warning', 'red');
+TextColorMap.set('warning', '#FAB247');
 
 export type ListProps = {
   key: string;

Разница между файлами не показана из-за своего большого размера
+ 263 - 1891
src/pages/init-home/components/data/RoleData.ts


+ 8 - 13
src/pages/link/Type/Detail/index.tsx

@@ -14,8 +14,9 @@ import {
   Select,
 } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
-import { useEffect, useMemo, useRef } from 'react';
-import { Field, FieldDataSource, onFormInit } from '@formily/core';
+import { useMemo, useRef } from 'react';
+import type { Field, FieldDataSource } from '@formily/core';
+import { onFormInit } from '@formily/core';
 import { createForm, onFieldReact, onFieldValueChange } from '@formily/core';
 import { Card, Col, Row } from 'antd';
 import styles from './index.less';
@@ -58,16 +59,6 @@ const Save = observer(() => {
 
   const configRef = useRef([]);
 
-  useEffect(() => {
-    service.getResourcesCurrent().then((resp) => {
-      if (resp.status === 200) {
-        // setConfig(resp.result);
-        // console.log('test', resp);
-        configRef.current = resp.result;
-      }
-    });
-  }, []);
-
   const useAsyncData = (services: (arg0: Field) => Promise<FieldDataSource>) => (field: Field) => {
     field.loading = true;
     services(field).then(
@@ -122,6 +113,10 @@ const Save = observer(() => {
         // initialValues: {},
         effects() {
           onFormInit(async (form1) => {
+            const response = await service.getResourcesCurrent();
+            if (response.status === 200) {
+              configRef.current = response.result;
+            }
             if (param?.id && param.id !== ':id') {
               const resp = await service.detail(param.id);
               const data = resp?.result || {};
@@ -156,7 +151,7 @@ const Save = observer(() => {
             f.setFieldState('grid.configuration.panel1.layout2.host', (state) => {
               state.dataSource = _host.map((item) => ({ label: item.host, value: item.host }));
             });
-            f.setFieldState('cluster.config.*.host', (state) => {
+            f.setFieldState('grid.cluster.cluster.*.layout2.host', (state) => {
               state.dataSource = _host.map((item) => ({ label: item.host, value: item.host }));
             });
           });

+ 1 - 1
src/pages/notice/Template/Detail/doc/DingTalkRebot.tsx

@@ -5,7 +5,7 @@ const DingTalkRebot = () => {
   return (
     <div className="doc">
       <div className="url">
-        钉钉管理后台:
+        钉钉开放平台:
         <a href="https://open-dev.dingtalk.com" target="_blank" rel="noopener noreferrer">
           https://open-dev.dingtalk.com
         </a>

+ 63 - 43
src/pages/rule-engine/DashBoard/index.tsx

@@ -13,6 +13,7 @@ import Echarts from '@/components/DashBoard/echarts';
 import encodeQuery from '@/utils/encodeQuery';
 import useHistory from '@/hooks/route/useHistory';
 import { getMenuPathByCode } from '@/utils/menu';
+import { Empty } from '@/components';
 
 const service = new Service();
 export const state = model<{
@@ -102,7 +103,10 @@ const Dashboard = observer(() => {
       state.today = _data.find((item) => item.group === 'today')?.data.value;
       state.thisMonth = _data.find((item) => item.group === 'thisMonth')?.data.value;
 
-      const fifteenData = _data.filter((item) => item.group === '15day').map((item) => item.data);
+      const fifteenData = _data
+        .filter((item) => item.group === '15day')
+        .map((item) => item.data)
+        .sort((a, b) => b.timestamp - a.timestamp);
       state.fifteenOptions = {
         xAxis: {
           type: 'category',
@@ -126,7 +130,7 @@ const Dashboard = observer(() => {
         series: [
           {
             name: '告警数',
-            data: fifteenData.sort((a, b) => b.timestamp - a.timestamp).map((item) => item.value),
+            data: fifteenData.map((item) => item.value),
             type: 'bar',
             itemStyle: {
               color: '#2F54EB',
@@ -239,6 +243,16 @@ const Dashboard = observer(() => {
     // 请求数据
     const resp = await service.dashboard([chartData, order]);
 
+    let tip = '其它';
+
+    if (params.targetType === 'device') {
+      tip = '设备';
+    } else if (params.targetType === 'product') {
+      tip = '产品';
+    } else if (params.targetType === 'org') {
+      tip = '部门';
+    }
+
     if (resp?.status === 200) {
       const xData: string[] = [];
       const sData: number[] = [];
@@ -278,7 +292,7 @@ const Dashboard = observer(() => {
         ],
         series: [
           {
-            name: 'Direct',
+            name: tip,
             type: 'bar',
             barWidth: '30%',
             itemStyle: {
@@ -327,48 +341,54 @@ const Dashboard = observer(() => {
                 <div className={'content-left-title'}>最新告警</div>
                 <div className={'new-alarm-items'}>
                   <ul>
-                    {state.alarmList.slice(0, 3).map((item) => (
-                      <li key={item.id}>
-                        <div className={'new-alarm-item'}>
-                          <div className={'new-alarm-item-time'}>
-                            <img src={require('/public/images/alarm/bashboard.png')} alt="" />
-                            {moment(item.alarmTime).format('YYYY-MM-DD HH:mm:ss')}
-                          </div>
-                          <div className={'new-alarm-item-content ellipsis'}>
-                            <Tooltip title={item.alarmName} placement="topLeft">
-                              <a
-                                onClick={() => {
-                                  console.log(item);
-                                  const url = getMenuPathByCode('rule-engine/Alarm/Log');
-                                  history.push(`${url}/detail/${item.id}`, {
-                                    param: {
-                                      detail: true,
-                                    },
-                                  });
-                                }}
-                              >
-                                {item.alarmName}
-                              </a>
-                            </Tooltip>
-                          </div>
-                          <div className={'new-alarm-item-state'}>
-                            <Badge
-                              status={item.state?.value === 'warning' ? 'error' : 'default'}
-                              text={
-                                <span
-                                  className={item.state?.value === 'warning' ? 'error' : 'default'}
+                    {state.alarmList.length ? (
+                      state.alarmList.slice(0, 3).map((item) => (
+                        <li key={item.id}>
+                          <div className={'new-alarm-item'}>
+                            <div className={'new-alarm-item-time'}>
+                              <img src={require('/public/images/alarm/bashboard.png')} alt="" />
+                              {moment(item.alarmTime).format('YYYY-MM-DD HH:mm:ss')}
+                            </div>
+                            <div className={'new-alarm-item-content ellipsis'}>
+                              <Tooltip title={item.alarmName} placement="topLeft">
+                                <a
+                                  onClick={() => {
+                                    console.log(item);
+                                    const url = getMenuPathByCode('rule-engine/Alarm/Log');
+                                    history.push(`${url}/detail/${item.id}`, {
+                                      param: {
+                                        detail: true,
+                                      },
+                                    });
+                                  }}
                                 >
-                                  {item.state?.text}
-                                </span>
-                              }
-                            />
-                          </div>
-                          <div className={`new-alarm-item-level level-${item.level}`}>
-                            {item.levelName}
+                                  {item.alarmName}
+                                </a>
+                              </Tooltip>
+                            </div>
+                            <div className={'new-alarm-item-state'}>
+                              <Badge
+                                status={item.state?.value === 'warning' ? 'error' : 'default'}
+                                text={
+                                  <span
+                                    className={
+                                      item.state?.value === 'warning' ? 'error' : 'default'
+                                    }
+                                  >
+                                    {item.state?.text}
+                                  </span>
+                                }
+                              />
+                            </div>
+                            <div className={`new-alarm-item-level level-${item.level}`}>
+                              {item.levelName}
+                            </div>
                           </div>
-                        </div>
-                      </li>
-                    ))}
+                        </li>
+                      ))
+                    ) : (
+                      <Empty />
+                    )}
                   </ul>
                 </div>
               </div>

+ 17 - 1
src/pages/rule-engine/Scene/Save/action/action.tsx

@@ -45,6 +45,7 @@ export default observer((props: ActionProps) => {
   const [deviceMessageType, setDeviceMessageType] = useState('WRITE_PROPERTY');
   const [properties, setProperties] = useState([]); // 物模型-属性
   const [functionList, setFunctionList] = useState([]); // 物模型-功能
+  const [propertiesId, setPropertiesId] = useState<string | undefined>(''); // 物模型-属性ID,用于串行
 
   const [productId, setProductId] = useState('');
 
@@ -84,6 +85,12 @@ export default observer((props: ActionProps) => {
             { column: 'type', value: data.notify.notifyType },
             { column: 'provider', value: notifierItem.provider },
           ],
+          sorts: [
+            {
+              name: 'createTime',
+              order: 'desc',
+            },
+          ],
         });
       }
     }
@@ -103,6 +110,12 @@ export default observer((props: ActionProps) => {
     ) {
       queryMessageConfigs({
         terms: [{ column: 'type$IN', value: props.actionItemData.notify.notifyType }],
+        sorts: [
+          {
+            name: 'createTime',
+            order: 'desc',
+          },
+        ],
       }).then(async (resp) => {
         if (props.actionItemData.notify.notifierId) {
           await handleNotifier(resp, props.actionItemData);
@@ -365,6 +378,7 @@ export default observer((props: ActionProps) => {
                   parallel={props.parallel}
                   productId={productId}
                   isEdit={props.isEdit}
+                  propertiesChange={setPropertiesId}
                 />
               </Form.Item>
             </Col>
@@ -377,6 +391,7 @@ export default observer((props: ActionProps) => {
                 form={props.form}
                 data={props.actionItemData.terms}
                 productId={productId}
+                propertiesId={propertiesId}
               />
             </Row>
           )}
@@ -392,7 +407,7 @@ export default observer((props: ActionProps) => {
                 name={[name, 'device', 'message', 'properties']}
                 rules={[{ required: true, message: '请选择属性' }]}
               >
-                <ReadProperty properties={properties} />
+                <ReadProperty properties={properties} propertiesChange={setPropertiesId} />
               </Form.Item>
             </Col>
             {parallelNode}
@@ -404,6 +419,7 @@ export default observer((props: ActionProps) => {
                 form={props.form}
                 data={props.actionItemData.terms}
                 productId={productId}
+                propertiesId={propertiesId}
               />
             </Row>
           )}

+ 17 - 6
src/pages/rule-engine/Scene/Save/action/device/ConditionalFiltering.tsx

@@ -9,6 +9,7 @@ interface ConditionalFilteringProps {
   form: FormInstance;
   data?: any;
   productId: string;
+  propertiesId?: string;
 }
 
 export default (props: ConditionalFilteringProps) => {
@@ -23,7 +24,7 @@ export default (props: ConditionalFilteringProps) => {
       case 'float':
       case 'double':
       case 'long':
-        return <InputNumber />;
+        return <InputNumber placeholder={'请输入过滤条件值'} />;
       case 'date':
         return (
           <>
@@ -36,6 +37,7 @@ export default (props: ConditionalFilteringProps) => {
       case 'boolean':
         return (
           <Select
+            placeholder={'请选择过滤条件值'}
             options={[
               { label: '是', value: 'true' },
               { label: '否', value: 'false' },
@@ -43,7 +45,7 @@ export default (props: ConditionalFilteringProps) => {
           />
         );
       default:
-        return <Input />;
+        return <Input placeholder={'请输入过滤条件值'} />;
     }
   };
 
@@ -108,13 +110,22 @@ export default (props: ConditionalFilteringProps) => {
   };
 
   useEffect(() => {
-    if (props.data && props.data[0] && props.data[0].column && builtInList && builtInList.length) {
-      getBuiltItemById(props.data[0].column);
+    if (props.data && props.data[0] && props.data[0].column) {
+      if (builtInList && builtInList.length) {
+        getBuiltItemById(props.data[0].column);
+      }
     }
   }, [props.data, builtInList]);
 
   useEffect(() => {
-    if (props.productId) {
+    if (props.data && props.data[0] && props.data[0].column) {
+      setSource(props.data[0].value.source);
+    }
+    getBuiltInParamsData();
+  }, []);
+
+  useEffect(() => {
+    if (props.productId || props.propertiesId) {
       getBuiltInParamsData();
       const actions = props.form.getFieldValue('actions');
       if (actions?.[props.name].terms?.[0]) {
@@ -129,7 +140,7 @@ export default (props: ConditionalFilteringProps) => {
       }
       setSource('fixed');
     }
-  }, [props.productId]);
+  }, [props.productId, props.propertiesId]);
 
   return (
     <>

+ 2 - 0
src/pages/rule-engine/Scene/Save/action/device/WriteProperty/index.tsx

@@ -13,6 +13,7 @@ interface WritePropertyProps {
   form: FormInstance;
   value?: any;
   onChange?: (value?: any) => void;
+  propertiesChange?: (value?: string) => void;
   parallel?: boolean;
   name: number;
   trigger?: any;
@@ -56,6 +57,7 @@ export default (props: WritePropertyProps) => {
 
   const onChange = (key?: string, value?: any, _source: string = 'fixed') => {
     if (props.onChange) {
+      props.propertiesChange?.(key);
       props.onChange({
         [key || 0]: {
           value: value,

+ 11 - 1
src/pages/rule-engine/Scene/Save/action/device/deviceModal.tsx

@@ -195,7 +195,17 @@ export default (props: DeviceModelProps) => {
                 取消选择
               </Button>
             )}
-            request={(params) => queryDevice(params)}
+            request={(params) =>
+              queryDevice({
+                ...params,
+                sorts: [
+                  {
+                    name: 'createTime',
+                    order: 'desc',
+                  },
+                ],
+              })
+            }
             params={searchParam}
           ></ProTable>
         </Modal>

+ 6 - 1
src/pages/rule-engine/Scene/Save/action/device/index.tsx

@@ -6,6 +6,7 @@ import Device from './deviceModal';
 import TagModal from './tagModal';
 import { ItemGroup } from '@/pages/rule-engine/Scene/Save/components';
 import RelationSelect from './relationSelect';
+import encodeQuery from '@/utils/encodeQuery';
 
 interface DeviceProps {
   name: number;
@@ -67,7 +68,11 @@ export default (props: DeviceProps) => {
   };
 
   const getProducts = async () => {
-    const resp = await getProductList({ paging: false });
+    const params = encodeQuery({
+      paging: false,
+      sorts: { createTime: 'desc' },
+    });
+    const resp = await getProductList(params);
     if (resp && resp.status === 200) {
       setProductList(resp.result);
       if (props.value && props.value.productId) {

+ 2 - 0
src/pages/rule-engine/Scene/Save/action/device/readProperty.tsx

@@ -4,6 +4,7 @@ interface ReadPropertyProps {
   properties: any[];
   value?: any;
   onChange?: (value?: any) => void;
+  propertiesChange?: (value?: string) => void;
   id?: string;
 }
 
@@ -23,6 +24,7 @@ export default (props: ReadPropertyProps) => {
       onSelect={(key: any) => {
         if (props.onChange) {
           props.onChange([key]);
+          props.propertiesChange?.(key);
         }
       }}
       placeholder={'请选择属性'}

Разница между файлами не показана из-за своего большого размера
+ 202 - 120
src/pages/rule-engine/Scene/Save/components/TimingTrigger/refactor.tsx


+ 9 - 11
src/pages/rule-engine/Scene/Save/trigger/index.tsx

@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
 import type { FormInstance } from 'antd';
 import { Col, Form, Row, Select } from 'antd';
 import { ItemGroup, TimingTrigger } from '@/pages/rule-engine/Scene/Save/components';
@@ -33,7 +33,7 @@ enum OperatorEnum {
 export default observer((props: TriggerProps) => {
   const [productList, setProductList] = useState<any[]>([]);
   const [productId, setProductId] = useState('');
-  const [selector, setSelector] = useState('fixed');
+  const [selector, setSelector] = useState(props.value?.device?.selector || 'fixed');
 
   const [operatorOptions, setOperatorOptions] = useState<any[] | undefined>(undefined);
 
@@ -43,6 +43,8 @@ export default observer((props: TriggerProps) => {
 
   const [functionItem, setFunctionItem] = useState<any[]>([]); // 单个功能-属性列表
 
+  const isInitRef = useRef<boolean>(true);
+
   const handleMetadata = (metadata?: string) => {
     try {
       const metadataObj = JSON.parse(metadata || '{}');
@@ -125,15 +127,11 @@ export default observer((props: TriggerProps) => {
   }, []);
 
   useEffect(() => {
-    const triggerData = props.value;
-    if (triggerData && triggerData.device) {
-      const _device = triggerData.device;
-
-      if (_device.selector) {
-        setSelector(_device.selector);
-      }
+    if (props.value?.device?.selector && isInitRef.current) {
+      isInitRef.current = false;
+      setSelector(props.value?.device?.selector);
     }
-  }, [props.value]);
+  }, [props.value?.device?.selector]);
 
   return (
     <div className={classNames(props.className)}>
@@ -154,7 +152,6 @@ export default observer((props: TriggerProps) => {
                 props.form?.resetFields([['trigger', 'device', 'selector']]);
                 props.form?.resetFields([['trigger', 'device', 'selectorValues']]);
                 props.form?.resetFields([['trigger', 'device', 'operation']]);
-                productIdChange(key, node?.metadata);
                 setSelector('fixed');
                 props.form?.setFieldsValue({
                   trigger: {
@@ -166,6 +163,7 @@ export default observer((props: TriggerProps) => {
                     productId: key,
                   },
                 });
+                productIdChange(key, node?.metadata);
               }}
               fieldNames={{ label: 'name', value: 'id' }}
               filterOption={(input: string, option: any) =>

+ 17 - 1
src/pages/rule-engine/Scene/TriggerTerm/index.tsx

@@ -175,6 +175,16 @@ const TriggerTerm = (props: Props, ref: any) => {
                   date: DatePicker,
                   boolean: Select,
                 };
+                let tip: string | undefined = '';
+
+                switch (valueType) {
+                  case 'boolean':
+                    tip = '请选择过滤条件值';
+                    break;
+                  default:
+                    tip = '请输入过滤条件值';
+                    break;
+                }
 
                 form1.setFieldState(value, (state) => {
                   state.componentType = valueTypeMap[valueType];
@@ -182,6 +192,7 @@ const TriggerTerm = (props: Props, ref: any) => {
                     style: {
                       width: '100%',
                     },
+                    placeholder: tip,
                   };
                   if (valueType === 'date') {
                     state.componentProps = {
@@ -199,6 +210,11 @@ const TriggerTerm = (props: Props, ref: any) => {
                   if (valueType === 'date') {
                     state.componentProps = {
                       showTime: true,
+                      placeholder: tip,
+                    };
+                  } else {
+                    state.componentProps = {
+                      placeholder: tip,
                     };
                   }
                 });
@@ -211,7 +227,7 @@ const TriggerTerm = (props: Props, ref: any) => {
                   state.dataSource = target?.metrics
                     ?.filter((i: { range: boolean }) => i.range === tag)
                     .map((item: any) => ({
-                      label: item.name,
+                      label: item.name + `(${item.value})`,
                       value: item.id,
                     }));
                   if (modified) {

+ 54 - 27
src/pages/system/Menu/Setting/tree.tsx

@@ -2,10 +2,11 @@ import { Input, Tree } from 'antd';
 import { SearchOutlined } from '@ant-design/icons';
 import DragItem from '@/pages/system/Menu/Setting/dragItem';
 import { useDrop } from 'react-dnd';
-import { useEffect, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
 import type { TreeProps } from 'antd';
 import { cloneDeep, debounce } from 'lodash';
 import './DragItem.less';
+import { Empty } from '@/components';
 
 interface TreeBodyProps {
   treeData: any[];
@@ -38,9 +39,11 @@ export default (props: TreeBodyProps) => {
   const [searchKeys, setSearchKeys] = useState<(string | number)[]>([]);
   const [expandedKeys, setExpandedKeys] = useState<(string | number)[]>([]);
   const [autoExpandParent, setAutoExpandParent] = useState(true);
+  const DefaultTreeRef = useRef<any[]>(props.treeData);
 
   useEffect(() => {
     setNewData(cloneDeep(props.treeData));
+    DefaultTreeRef.current = cloneDeep(props.treeData);
   }, [props.treeData]);
 
   useEffect(() => {
@@ -125,6 +128,18 @@ export default (props: TreeBodyProps) => {
     return parentKey;
   };
 
+  const findItem = (data: any[], keys: string[]): any[] => {
+    return data.filter((item) => {
+      if (item.children) {
+        item.children = findItem(item.children, keys);
+      }
+      if (keys.includes(item.code) || !!item.children?.length) {
+        return true;
+      }
+      return false;
+    });
+  };
+
   const findAllItem = (data: any[], value: string): string[] => {
     return data.reduce((pre, next) => {
       const childrenKeys = next.children ? findAllItem(next.children, value) : [];
@@ -142,10 +157,14 @@ export default (props: TreeBodyProps) => {
       const newExpandedKeys = newKeys.map((key) => {
         return getParentKey(key, props.treeData);
       });
+      const expandKeysSet = new Set([...newExpandedKeys, ...newKeys]);
+      const searchData = findItem(cloneDeep(DefaultTreeRef.current), [...expandKeysSet.keys()]);
+      setNewData(cloneDeep(searchData));
       setSearchKeys(newKeys);
-      setExpandedKeys(newExpandedKeys);
+      setExpandedKeys([...expandKeysSet.keys()]);
     } else {
       setSearchKeys([]);
+      setNewData(cloneDeep(DefaultTreeRef.current));
     }
     setAutoExpandParent(true);
   };
@@ -162,34 +181,42 @@ export default (props: TreeBodyProps) => {
       </div>
       {props.droppableId === 'source' ? (
         <div className={'tree-body'}>
-          <Tree
-            expandedKeys={expandedKeys}
-            onExpand={(_expandedKeys) => {
-              setExpandedKeys(_expandedKeys);
-              setAutoExpandParent(false);
-            }}
-            autoExpandParent={autoExpandParent}
-          >
-            {createTreeNode(newData, props.droppableId)}
-          </Tree>
+          {newData.length ? (
+            <Tree
+              expandedKeys={expandedKeys}
+              onExpand={(_expandedKeys) => {
+                setExpandedKeys(_expandedKeys);
+                setAutoExpandParent(false);
+              }}
+              autoExpandParent={autoExpandParent}
+            >
+              {createTreeNode(newData, props.droppableId)}
+            </Tree>
+          ) : (
+            <Empty />
+          )}
         </div>
       ) : (
         <div className={'tree-body'} ref={drop}>
-          <Tree
-            expandedKeys={expandedKeys}
-            onExpand={(_expandedKeys) => {
-              setExpandedKeys(_expandedKeys);
-              setAutoExpandParent(false);
-            }}
-            autoExpandParent={autoExpandParent}
-            draggable={{
-              icon: false,
-            }}
-            onDrop={props.onTreeDrop}
-            className="menu-setting-drag-tree"
-          >
-            {createTreeNode(props.treeData, props.droppableId)}
-          </Tree>
+          {newData.length ? (
+            <Tree
+              expandedKeys={expandedKeys}
+              onExpand={(_expandedKeys) => {
+                setExpandedKeys(_expandedKeys);
+                setAutoExpandParent(false);
+              }}
+              autoExpandParent={autoExpandParent}
+              draggable={{
+                icon: false,
+              }}
+              onDrop={props.onTreeDrop}
+              className="menu-setting-drag-tree"
+            >
+              {createTreeNode(newData, props.droppableId)}
+            </Tree>
+          ) : (
+            <Empty />
+          )}
         </div>
       )}
     </div>