Преглед изворни кода

fix: bug#4853、4838、4846

xieyonghong пре 3 година
родитељ
комит
ea474f8422

+ 1 - 1
src/pages/demo/AMap/index.tsx

@@ -53,7 +53,7 @@ export default () => {
           height: 500,
           width: '100%',
         }}
-        onInstanceCreated={(_map) => {
+        onInstanceCreated={(_map: any) => {
           setMap(_map);
         }}
         events={{

+ 6 - 0
src/pages/media/Device/Channel/Live/index.less

@@ -24,6 +24,12 @@
       right: 0;
       z-index: 2;
       display: flex;
+      opacity: 0;
+      transition: opacity 0.3s;
+
+      &:hover {
+        opacity: 1;
+      }
 
       .tool-item {
         margin-right: 6px;

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

@@ -102,8 +102,9 @@ const LiveFC = (props: LiveProps) => {
           buttonStyle={'solid'}
           value={mediaType}
           onChange={(e) => {
-            setMediaType(e.target.value);
-            mediaStart(e.target.value);
+            const _type = e.target.value;
+            setMediaType(_type);
+            mediaStart(_type === 'hls' ? 'm3u8' : _type);
           }}
           options={[
             { label: 'MP4', value: 'mp4' },

+ 16 - 3
src/pages/media/Device/Channel/Save.tsx

@@ -99,12 +99,25 @@ const Save = (props: SaveModalProps) => {
             max: 64,
             message: '最多可输入64个字符',
           },
+          {
+            triggerType: 'onBlur',
+            validator: (value: string) => {
+              const reg = /(http|https|rtsp|rtmp):\/\/([\w.]+\/?)\S*/;
+              return new Promise((resolve) => {
+                if (reg.test(value)) {
+                  resolve('');
+                } else {
+                  resolve('请输入正确的视频地址');
+                }
+              });
+            },
+          },
         ],
         'x-decorator-props': {
           gridSpan: 24,
         },
       },
-      media_url: {
+      'others.media_url': {
         type: 'string',
         title: '视频地址',
         'x-visible': props.type === ProviderValue.FIXED,
@@ -112,8 +125,8 @@ const Save = (props: SaveModalProps) => {
         'x-component': 'Input',
         'x-validator': [
           {
-            max: 64,
-            message: '最多可输入64个字符',
+            max: 128,
+            message: '最多可输入128个字符',
           },
         ],
       },

+ 0 - 412
src/pages/rule-engine/Scene/Save/trigger/device.tsx

@@ -1,412 +0,0 @@
-import { useCallback, useEffect, useState } from 'react';
-import { Col, Form, Row, Select, TreeSelect } from 'antd';
-import { ItemGroup, TimingTrigger } from '@/pages/rule-engine/Scene/Save/components';
-import { getProductList } from '@/pages/rule-engine/Scene/Save/action/device/service';
-import { queryOrgTree } from '@/pages/rule-engine/Scene/Save/trigger/service';
-import Device from '@/pages/rule-engine/Scene/Save/action/device/deviceModal';
-import FunctionCall from '@/pages/rule-engine/Scene/Save/action/device/functionCall';
-import Operation from './operation';
-import classNames from 'classnames';
-import { FormModel } from '../index';
-import AllDevice from '@/pages/rule-engine/Scene/Save/action/device/AllDevice';
-
-interface DeviceData {
-  productId?: string;
-  source?: string;
-  selector?: any;
-  selectorValues?: any[];
-  relation?: any;
-  upperKey?: string;
-  operation?: {
-    operator?: string;
-    timer?: any;
-    eventId?: string;
-    readProperties?: string[];
-    writeProperties?: any;
-    functionId?: string;
-    functionParameters?: { name: string; value: any }[];
-  };
-}
-
-interface TriggerProps {
-  value?: DeviceData;
-  onChange?: (value: DeviceData) => void;
-  className?: string;
-}
-
-enum OperatorEnum {
-  'online' = 'online',
-  'offline' = 'offline',
-  'reportEvent' = 'reportEvent',
-  'reportProperty' = 'reportProperty',
-  'readProperty' = 'readProperty',
-  'writeProperty' = 'writeProperty',
-  'invokeFunction' = 'invokeFunction',
-}
-
-export default (props: TriggerProps) => {
-  const [productList, setProductList] = useState<any[]>([]);
-  const [productId, setProductId] = useState('');
-  // const [selector, setSelector] = useState('fixed');
-
-  // const [selectorOptions, setSelectorOptions] = useState<any[]>([]);
-  // const [operation, setOperation] = useState<string | undefined>(undefined);
-  const [operatorOptions, setOperatorOptions] = useState<any[]>([]);
-
-  const [properties, setProperties] = useState<any[]>([]); // 属性
-  const [events, setEvents] = useState([]); // 事件
-  const [functions, setFunctions] = useState([]); // 功能列表
-
-  const [functionItem, setFunctionItem] = useState<any[]>([]); // 单个功能-属性列表
-  const [orgTree, setOrgTree] = useState<any>([]);
-
-  const onChange = (value: DeviceData) => {
-    if (props.onChange) {
-      props.onChange(value);
-    }
-  };
-
-  // const getSelector = () => {
-  //   querySelector().then((resp) => {
-  //     if (resp && resp.status === 200) {
-  //       setSelectorOptions(resp.result);
-  //     }
-  //   });
-  // };
-
-  const handleMetadata = (metadata?: string) => {
-    try {
-      const metadataObj = JSON.parse(metadata || '{}');
-      let newOperator: any[] = [
-        { label: '设备上线', value: OperatorEnum.online },
-        { label: '设备离线', value: OperatorEnum.offline },
-      ];
-      if (metadataObj.properties && metadataObj.properties.length) {
-        newOperator = [
-          ...newOperator,
-          { label: '属性上报', value: OperatorEnum.reportProperty },
-          { label: '属性读取', value: OperatorEnum.readProperty },
-          { label: '修改属性', value: OperatorEnum.writeProperty },
-        ];
-        setProperties(metadataObj.properties);
-      }
-      if (metadataObj.events && metadataObj.events.length) {
-        newOperator = [...newOperator, { label: '事件上报', value: OperatorEnum.reportEvent }];
-        setEvents(metadataObj.events);
-      }
-      if (metadataObj.functions && metadataObj.functions.length) {
-        newOperator = [...newOperator, { label: '功能调用', value: OperatorEnum.invokeFunction }];
-        setFunctions(metadataObj.functions);
-      }
-      setOperatorOptions(newOperator);
-    } catch (err) {
-      console.warn('handleMetadata === ', err);
-    }
-  };
-
-  const productIdChange = useCallback(
-    (id: string, metadata: any) => {
-      setProductId(id);
-      handleMetadata(metadata);
-    },
-    [props.value],
-  );
-
-  const getProducts = async () => {
-    const resp = await getProductList({ paging: false });
-    if (resp && resp.status === 200) {
-      setProductList(resp.result);
-      if (FormModel.trigger && FormModel.trigger.device) {
-        const productItem = resp.result.find(
-          (item: any) => item.id === FormModel.trigger!.device.productId,
-        );
-
-        if (productItem) {
-          productIdChange(FormModel.trigger!.device.productId, productItem.metadata);
-        }
-      }
-    }
-  };
-
-  useEffect(() => {
-    getProducts();
-    // getSelector();
-  }, []);
-
-  useEffect(() => {
-    const triggerData: any = props.value;
-    console.log('trigger', triggerData);
-    if (triggerData) {
-      if (triggerData.selector) {
-        if (triggerData.selector === 'org') {
-          queryOrgTree(triggerData.productId).then((resp) => {
-            if (resp && resp.status === 200) {
-              setOrgTree(resp.result);
-            }
-          });
-        }
-      }
-    }
-  }, [props.value]);
-
-  return (
-    <div className={classNames(props.className)}>
-      <Row gutter={24}>
-        <Col span={6}>
-          <Form.Item
-            noStyle
-            rules={[
-              {
-                validator: async (_: any, value: any) => {
-                  console.log('productId', value);
-                  return Promise.resolve();
-                },
-              },
-            ]}
-          >
-            <Select
-              showSearch
-              value={props.value?.productId}
-              options={productList}
-              placeholder={'请选择产品'}
-              style={{ width: '100%' }}
-              listHeight={220}
-              onChange={(key: any, node: any) => {
-                productIdChange(key, node.metadata);
-                onChange({
-                  productId: key,
-                  selectorValues: undefined,
-                  selector: 'fixed',
-                  operation: {
-                    operator: undefined,
-                  },
-                });
-              }}
-              fieldNames={{ label: 'name', value: 'id' }}
-              filterOption={(input: string, option: any) =>
-                option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }
-            />
-          </Form.Item>
-        </Col>
-        {props.value?.productId ? (
-          <Col span={12}>
-            <ItemGroup compact>
-              <Select
-                value={props.value?.selector}
-                options={[
-                  { label: '全部设备', value: 'all' },
-                  { label: '固定设备', value: 'fixed' },
-                  { label: '按部门', value: 'org' },
-                ]}
-                style={{ width: 120 }}
-                onSelect={(value: string) => {
-                  const _value = { ...props.value };
-                  _value.selector = value;
-                  _value.selectorValues = undefined;
-                  onChange(_value);
-                }}
-              />
-              {props.value?.selector === 'all' && (
-                <AllDevice
-                  value={props.value?.selectorValues}
-                  productId={productId}
-                  onChange={(value) => {
-                    const _value = { ...props.value };
-                    _value.selectorValues = value;
-                    onChange(_value);
-                  }}
-                />
-              )}
-              {props.value?.selector === 'fixed' && (
-                <Device
-                  value={props.value?.selectorValues}
-                  productId={productId}
-                  onChange={(value) => {
-                    const _value = { ...props.value };
-                    _value.selectorValues = value;
-                    onChange(_value);
-                  }}
-                />
-              )}
-              {props.value?.selector === 'org' && (
-                <TreeSelect
-                  value={
-                    props.value?.selectorValues && props.value?.selectorValues.length
-                      ? props.value?.selectorValues[0].id
-                      : undefined
-                  }
-                  treeData={orgTree}
-                  fieldNames={{ label: 'name', value: 'id' }}
-                  placeholder={'请选择部门'}
-                  style={{ width: '100%' }}
-                  onChange={(value, label) => {
-                    const _value = { ...props.value };
-                    _value.selectorValues = [{ id: value, name: label[0] }];
-                    onChange(_value);
-                  }}
-                />
-              )}
-            </ItemGroup>
-          </Col>
-        ) : null}
-        <Col span={6}>
-          {functions.length || events.length || properties.length ? (
-            <Select
-              value={props.value?.operation?.operator}
-              placeholder={'请选择触发类型'}
-              options={operatorOptions}
-              style={{ width: '100%' }}
-              onChange={(value) => {
-                const _value = { ...props.value };
-                _value.operation!.operator = value;
-                onChange(_value);
-              }}
-            />
-          ) : null}
-        </Col>
-      </Row>
-      {props.value?.operation?.operator === OperatorEnum.invokeFunction ||
-      props.value?.operation?.operator === OperatorEnum.readProperty ||
-      props.value?.operation?.operator === OperatorEnum.writeProperty ? (
-        <TimingTrigger
-          value={props.value?.operation?.timer}
-          onChange={(value) => {
-            const _value = { ...props.value };
-            _value.operation!.timer = value;
-            onChange(_value);
-          }}
-        />
-      ) : null}
-      {props.value?.operation?.operator === OperatorEnum.invokeFunction && (
-        <>
-          <Row gutter={24}>
-            <Col span={6}>
-              <Select
-                value={props.value?.operation?.functionId}
-                options={functions}
-                fieldNames={{
-                  label: 'name',
-                  value: 'id',
-                }}
-                style={{ width: '100%' }}
-                placeholder={'请选择功能'}
-                onSelect={(key: any, data: any) => {
-                  const _properties = data.valueType ? data.valueType.properties : data.inputs;
-                  const array = [];
-                  for (const datum of _properties) {
-                    array.push({
-                      id: datum.id,
-                      name: datum.name,
-                      type: datum.valueType ? datum.valueType.type : '-',
-                      format: datum.valueType ? datum.valueType.format : undefined,
-                      options: datum.valueType ? datum.valueType.elements : undefined,
-                      value: undefined,
-                    });
-                  }
-                  setFunctionItem(array);
-                  const _value = { ...props.value };
-                  _value.operation!.functionId = key;
-                  onChange(_value);
-                }}
-              />
-            </Col>
-            <Col span={18}>
-              <span style={{ lineHeight: '32px' }}>定时调用所选功能</span>
-            </Col>
-          </Row>
-          <Row>
-            <Col span={24}>
-              <FunctionCall
-                value={props.value?.operation?.functionParameters}
-                functionData={functionItem}
-                onChange={(value) => {
-                  const _value = { ...props.value };
-                  _value.operation!.functionParameters = value;
-                  onChange(_value);
-                }}
-              />
-            </Col>
-          </Row>
-        </>
-      )}
-      {props.value?.operation?.operator === OperatorEnum.writeProperty && (
-        <Row>
-          <Col span={24}>
-            <Operation
-              value={props.value?.operation?.writeProperties}
-              propertiesList={properties.filter((item) => {
-                if (item.expands) {
-                  return item.expands.type ? item.expands.type.includes('write') : false;
-                }
-                return false;
-              })}
-              onChange={(value) => {
-                const _value = { ...props.value };
-                _value.operation!.writeProperties = value;
-                onChange(_value);
-              }}
-            />
-          </Col>
-        </Row>
-      )}
-      {props.value?.operation?.operator === OperatorEnum.readProperty && (
-        <Row gutter={24}>
-          <Col span={6}>
-            <Select
-              value={props.value?.operation?.readProperties}
-              mode={'multiple'}
-              options={properties.filter((item) => {
-                if (item.expands) {
-                  return item.expands.type ? item.expands.type.includes('read') : false;
-                }
-                return false;
-              })}
-              maxTagCount={'responsive'}
-              // maxTagPlaceholder={(values) => {
-              //   return (
-              //     <div style={{ maxWidth: 'calc(100% - 8px)' }}>
-              //       {values.map((item) => item.label).toString()}
-              //     </div>
-              //   );
-              // }}
-              placeholder={'请选择属性'}
-              style={{ width: '100%' }}
-              fieldNames={{ label: 'name', value: 'id' }}
-              onChange={(value) => {
-                if (props.value) {
-                  const _value = { ...props.value };
-                  _value!.operation!.readProperties = value;
-                  onChange(_value);
-                }
-              }}
-            />
-          </Col>
-          <Col span={18}>
-            <span style={{ lineHeight: '32px' }}>定时读取所选属性值</span>
-          </Col>
-        </Row>
-      )}
-      {props.value?.operation?.operator === OperatorEnum.reportEvent && (
-        <Row gutter={24}>
-          <Col span={6}>
-            <Select
-              value={props.value?.operation?.eventId}
-              options={events}
-              placeholder={'请选择事件'}
-              style={{ width: '100%' }}
-              fieldNames={{ label: 'name', value: 'id' }}
-              onChange={(value) => {
-                if (props.value) {
-                  const _value = { ...props.value };
-                  _value!.operation!.eventId = value;
-                  onChange(_value);
-                }
-              }}
-            />
-          </Col>
-        </Row>
-      )}
-    </div>
-  );
-};

+ 30 - 2
src/pages/system/Platforms/Api/base.tsx

@@ -1,11 +1,12 @@
 import Tree from '@/pages/system/Platforms/Api/leftTree';
 import Table from '@/pages/system/Platforms/Api/basePage';
 import SwaggerUI from '@/pages/system/Platforms/Api/swagger-ui';
-import { useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
 import { service } from '@/pages/system/Platforms';
 import { model } from '@formily/reactive';
 import { observer } from '@formily/react';
 import './index.less';
+import { useLocation } from 'umi';
 
 export const ApiModel = model<{
   data: any[];
@@ -29,7 +30,9 @@ interface ApiPageProps {
 }
 
 export default observer((props: ApiPageProps) => {
+  const location = useLocation();
   const [operations, setOperations] = useState<string[]>([]);
+  const [GrantKeys, setGrantKeys] = useState<string[]>([]);
 
   const initModel = () => {
     ApiModel.data = [];
@@ -39,6 +42,9 @@ export default observer((props: ApiPageProps) => {
     ApiModel.debugger = {};
   };
 
+  /**
+   *  获取能授权的接口ID
+   */
   const getOperations = () => {
     service.apiOperations().then((resp: any) => {
       if (resp.status === 200) {
@@ -47,15 +53,32 @@ export default observer((props: ApiPageProps) => {
     });
   };
 
+  /**
+   * 获取已授权的接口ID
+   */
+  const getApiGrant = useCallback(() => {
+    const param = new URLSearchParams(location.search);
+    const code = param.get('code');
+
+    service.getApiGranted(code!).then((resp: any) => {
+      if (resp.status === 200) {
+        setGrantKeys(resp.result);
+      }
+    });
+  }, [location]);
+
   useEffect(() => {
     initModel();
     getOperations();
+    getApiGrant();
   }, []);
 
   return (
     <div className={'platforms-api'}>
       <div className={'platforms-api-tree'}>
         <Tree
+          isShowGranted={props.isShowGranted}
+          grantKeys={GrantKeys}
           onSelect={(data) => {
             ApiModel.data = data;
             ApiModel.showTable = true;
@@ -63,7 +86,12 @@ export default observer((props: ApiPageProps) => {
         />
       </div>
       {ApiModel.showTable ? (
-        <Table data={ApiModel.data} operations={operations} isShowGranted={props.isShowGranted} />
+        <Table
+          data={ApiModel.data}
+          operations={operations}
+          isShowGranted={props.isShowGranted}
+          grantKeys={GrantKeys}
+        />
       ) : (
         <SwaggerUI showDebugger={props.showDebugger} />
       )}

+ 12 - 18
src/pages/system/Platforms/Api/basePage.tsx

@@ -9,6 +9,8 @@ interface TableProps {
   operations: string[];
   // 是否只暂时已授权的接口
   isShowGranted?: boolean;
+  //
+  grantKeys: string[];
 }
 
 export default (props: TableProps) => {
@@ -20,18 +22,6 @@ export default (props: TableProps) => {
 
   const location = useLocation();
 
-  const getApiGrant = useCallback(() => {
-    const param = new URLSearchParams(location.search);
-    const code = param.get('code');
-
-    service.getApiGranted(code!).then((resp: any) => {
-      if (resp.status === 200) {
-        grantCache.current = resp.result;
-        setSelectKeys(resp.result);
-      }
-    });
-  }, [location]);
-
   const getOperations = async (apiData: any[], operations: string[]) => {
     // 过滤只能授权的接口,当isShowGranted为true时,过滤为已赋权的接口
     setDataSource(
@@ -39,6 +29,14 @@ export default (props: TableProps) => {
     );
   };
 
+  /**
+   * 获取已授权的接口ID
+   */
+  useEffect(() => {
+    grantCache.current = props.grantKeys;
+    setSelectKeys(props.grantKeys);
+  }, [props.grantKeys]);
+
   useEffect(() => {
     if (props.isShowGranted) {
       if (props.data && selectKeys) {
@@ -59,10 +57,6 @@ export default (props: TableProps) => {
     }
   }, [props.data, props.operations, props.isShowGranted]);
 
-  useEffect(() => {
-    getApiGrant();
-  }, []);
-
   const save = useCallback(async () => {
     const param = new URLSearchParams(location.search);
     const code = param.get('code');
@@ -86,7 +80,7 @@ export default (props: TableProps) => {
       const item = dataSource.find((b) => b.operationId === a);
       return {
         id: a,
-        permissions: item.security,
+        permissions: item?.security,
       };
     });
 
@@ -94,7 +88,7 @@ export default (props: TableProps) => {
       const item = dataSource.find((b) => b.operationId === a);
       return {
         id: a,
-        permissions: item.security,
+        permissions: item?.security,
       };
     });
 

+ 37 - 20
src/pages/system/Platforms/Api/leftTree.tsx

@@ -1,10 +1,15 @@
 import { Tree } from 'antd';
-import React, { useEffect, useState } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
 import { service } from '@/pages/system/Platforms';
 import { ApiModel } from '@/pages/system/Platforms/Api/base';
 
 type LeftTreeType = {
   onSelect: (data: any) => void;
+  /**
+   * 是否只展示已授权的接口
+   */
+  isShowGranted?: boolean;
+  grantKeys?: string[];
 };
 
 interface DataNode {
@@ -25,24 +30,38 @@ export default (props: LeftTreeType) => {
     }
   };
 
-  const updateTreeData = (list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] => {
-    return list.map((node) => {
-      if (node.id === key) {
-        return {
-          ...node,
-          children: node.children ? [...node.children, ...children] : children,
-        };
-      }
+  const updateTreeData = useCallback(
+    (list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] => {
+      return list.map((node) => {
+        if (node.id === key) {
+          const newChildren = node.children ? [...node.children, ...children] : children;
+          // api详情时,过滤掉没有授权的接口
+          const filterChildren = props.isShowGranted
+            ? newChildren.filter(
+                (item: any) =>
+                  item.extraData &&
+                  item.extraData.some((extraItem: any) =>
+                    props.grantKeys?.includes(extraItem.operationId),
+                  ),
+              )
+            : newChildren;
+          return {
+            ...node,
+            children: filterChildren,
+          };
+        }
 
-      if (node.children) {
-        return {
-          ...node,
-          children: updateTreeData(node.children, key, children),
-        };
-      }
-      return node;
-    });
-  };
+        if (node.children) {
+          return {
+            ...node,
+            children: updateTreeData(node.children, key, children),
+          };
+        }
+        return node;
+      });
+    },
+    [props.isShowGranted, props.grantKeys],
+  );
 
   const handleTreeData = (data: any) => {
     const newArr = data.tags.map((item: any) => ({ id: item.name, name: item.name, isLeaf: true }));
@@ -62,7 +81,6 @@ export default (props: LeftTreeType) => {
         }
       });
     });
-    console.log(newArr);
     return newArr;
   };
 
@@ -83,7 +101,6 @@ export default (props: LeftTreeType) => {
   };
 
   const onLoadData = (node: any): Promise<void> => {
-    console.log(node);
     return new Promise(async (resolve) => {
       if (node.children) {
         resolve();