xieyonghong 3 лет назад
Родитель
Сommit
1f70c25d60
54 измененных файлов с 851 добавлено и 183 удалено
  1. BIN
      public/images/apiHome.png
  2. 1 1
      src/components/FRuleEditor/Operator/index.tsx
  3. 5 8
      src/components/NoticeIcon/index.tsx
  4. 2 2
      src/components/ProTableCard/CardItems/aliyun.tsx
  5. 2 2
      src/components/ProTableCard/CardItems/device.tsx
  6. 4 4
      src/components/ProTableCard/CardItems/mediaDevice.tsx
  7. 1 1
      src/components/ProTableCard/CardItems/scene.tsx
  8. 3 3
      src/hooks/route/useHistory.tsx
  9. 2 2
      src/hooks/route/useLocation.tsx
  10. 1 1
      src/pages/Log/System/index.tsx
  11. 5 5
      src/pages/account/NotificationRecord/detail/index.tsx
  12. 7 4
      src/pages/account/NotificationRecord/index.tsx
  13. 5 5
      src/pages/device/Instance/Detail/Config/index.tsx
  14. 1 1
      src/pages/device/Instance/Detail/Info/index.tsx
  15. 317 2
      src/pages/device/Instance/Detail/Parsing/index.tsx
  16. 2 2
      src/pages/device/Instance/Detail/Reation/index.tsx
  17. 3 1
      src/pages/device/Instance/Detail/Running/Property/FileComponent/index.tsx
  18. 1 1
      src/pages/device/Instance/Detail/Running/Property/PropertyCard.tsx
  19. 1 1
      src/pages/device/Instance/Detail/Running/Property/index.tsx
  20. 3 3
      src/pages/device/Instance/Detail/Tags/index.tsx
  21. 10 8
      src/pages/device/Instance/Detail/index.tsx
  22. 33 0
      src/pages/device/Instance/service.ts
  23. 1 0
      src/pages/device/Instance/typings.d.ts
  24. 18 0
      src/pages/device/Product/Detail/index.tsx
  25. 3 3
      src/pages/link/AccessConfig/Detail/Channel/index.tsx
  26. 3 3
      src/pages/link/AccessConfig/Detail/Cloud/Finish/index.tsx
  27. 2 2
      src/pages/link/AccessConfig/Detail/Cloud/Protocol/index.tsx
  28. 3 0
      src/pages/link/Protocol/FileUpload/index.tsx
  29. 4 12
      src/pages/link/Protocol/save/index.tsx
  30. 5 5
      src/pages/media/Device/Save/ProviderSelect.tsx
  31. 65 47
      src/pages/media/Device/Save/index.tsx
  32. 3 3
      src/pages/notice/Config/Detail/doc/AliyunSms.tsx
  33. 1 1
      src/pages/notice/Config/Detail/doc/AliyunVoice.tsx
  34. 2 2
      src/pages/notice/Config/Detail/doc/DingTalk.tsx
  35. 1 1
      src/pages/notice/Config/Detail/doc/DingTalkRebot.tsx
  36. 4 4
      src/pages/notice/Config/Detail/doc/Email.tsx
  37. 2 2
      src/pages/notice/Config/Detail/doc/Webhook.tsx
  38. 2 2
      src/pages/notice/Config/Detail/doc/WeixinApp.tsx
  39. 2 2
      src/pages/notice/Config/Detail/doc/WeixinCorp.tsx
  40. 1 1
      src/pages/notice/Config/SyncUser/index.tsx
  41. 3 3
      src/pages/notice/Template/Detail/doc/DingTalk.tsx
  42. 1 1
      src/pages/notice/Template/Detail/doc/DingTalkRebot.tsx
  43. 4 4
      src/pages/notice/Template/Detail/doc/Email.tsx
  44. 7 7
      src/pages/notice/Template/Detail/doc/WeixinApp.tsx
  45. 2 2
      src/pages/notice/Template/Detail/doc/WeixinCorp.tsx
  46. 6 6
      src/pages/rule-engine/Alarm/Log/Detail/Info.tsx
  47. 18 8
      src/pages/system/Platforms/Api/base.tsx
  48. 1 1
      src/pages/system/Platforms/Api/index.tsx
  49. 20 1
      src/pages/system/Platforms/Api/leftTree.tsx
  50. 38 0
      src/pages/system/Platforms/Home/index.less
  51. 175 0
      src/pages/system/Platforms/Home/index.tsx
  52. 1 1
      src/pages/system/Platforms/Setting/index.tsx
  53. 1 1
      src/pages/system/Platforms/View/index.tsx
  54. 43 1
      src/pages/system/Role/Detail/Permission/Allocate/MenuPermission.tsx

BIN
public/images/apiHome.png


+ 1 - 1
src/components/FRuleEditor/Operator/index.tsx

@@ -28,7 +28,7 @@ const Operator = () => {
         description: `### ${p.name}
         \n 数据类型: ${p.valueType?.type}
         \n 是否只读: ${p.expands?.readOnly || 'false'}
-        \n 可写数值范围: ---`,
+        \n 可写数值范围: `,
         type: 'property',
       })),
     };

+ 5 - 8
src/components/NoticeIcon/index.tsx

@@ -9,7 +9,6 @@ import encodeQuery from '@/utils/encodeQuery';
 import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
 import useHistory from '@/hooks/route/useHistory';
 import { throttleTime } from 'rxjs/operators';
-import Icon from '@ant-design/icons';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
 
 export type GlobalHeaderRightProps = {
@@ -100,14 +99,14 @@ const NoticeIconView = () => {
       ?.pipe(throttleTime(2000))
       .subscribe((resp: any) => {
         getUnread();
-        notification.open({
+        notification.warning({
           message: resp?.payload?.topicName,
           description: resp?.payload?.message,
           key: resp.payload.id,
-          top: 60,
           btn: (
             <Button
               type="primary"
+              size="small"
               onClick={() => {
                 service.changeNoticeReadState(resp.payload.id).then((response) => {
                   if (response.status === 200) {
@@ -120,7 +119,6 @@ const NoticeIconView = () => {
               标记已读
             </Button>
           ),
-          icon: <Icon type="exclamation-circle" style={{ color: '#E23D38' }} />,
         });
       });
   };
@@ -136,11 +134,10 @@ const NoticeIconView = () => {
   const changeReadState = async (item: any) => {
     const resp = await service.changeNoticeReadState(item.id);
     if (resp.status === 200) {
-      getUnread();
+      const url = getMenuPathByCode(MENUS_CODE['account/NotificationRecord']);
+      history.push(url, { ...item });
+      setVisible(false);
     }
-    const url = getMenuPathByCode(MENUS_CODE['account/NotificationRecord']);
-    history.push(url, { ...item });
-    setVisible(false);
   };
 
   const clearReadState = async (title: string) => {

+ 2 - 2
src/components/ProTableCard/CardItems/aliyun.tsx

@@ -36,11 +36,11 @@ export default (props: AliyunCardProps) => {
           <div className={'card-item-content'}>
             <div>
               <label>网桥产品</label>
-              <div className={'ellipsis'}>{props?.bridgeProductName || '--'}</div>
+              <div className={'ellipsis'}>{props?.bridgeProductName || ''}</div>
             </div>
             <div>
               <label>说明</label>
-              <div className={'ellipsis'}>{props?.description || '--'}</div>
+              <div className={'ellipsis'}>{props?.description || ''}</div>
             </div>
           </div>
         </div>

+ 2 - 2
src/components/ProTableCard/CardItems/device.tsx

@@ -148,11 +148,11 @@ export default (props: DeviceCardProps) => {
           <div className={'card-item-content'}>
             <div>
               <label>设备类型</label>
-              <div className={'ellipsis'}>{props.deviceType ? props.deviceType.text : '--'}</div>
+              <div className={'ellipsis'}>{props.deviceType ? props.deviceType.text : ''}</div>
             </div>
             <div>
               <label>产品名称</label>
-              <div className={'ellipsis'}>{props.productName || '--'}</div>
+              <div className={'ellipsis'}>{props.productName || ''}</div>
             </div>
           </div>
         </div>

+ 4 - 4
src/components/ProTableCard/CardItems/mediaDevice.tsx

@@ -38,19 +38,19 @@ export default (props: ProductCardProps) => {
           <div className={'card-item-content'}>
             <div>
               <label>厂商</label>
-              <div className={'ellipsis'}>{props.manufacturer || '--'}</div>
+              <div className={'ellipsis'}>{props.manufacturer || ''}</div>
             </div>
             <div>
               <label>通道数量</label>
-              <div className={'ellipsis'}>{props.channelNumber || '--'}</div>
+              <div className={'ellipsis'}>{props.channelNumber || ''}</div>
             </div>
             <div>
               <label>型号</label>
-              <div className={'ellipsis'}>{props.model || '--'}</div>
+              <div className={'ellipsis'}>{props.model || ''}</div>
             </div>
             <div>
               <label>接入方式</label>
-              <div className={'ellipsis'}>{props.provider || '--'}</div>
+              <div className={'ellipsis'}>{props.provider || ''}</div>
             </div>
           </div>
         </div>

+ 1 - 1
src/components/ProTableCard/CardItems/scene.tsx

@@ -48,7 +48,7 @@ export default (props: DeviceCardProps) => {
             </div>
             <div>
               <label>说明</label>
-              <div className={'ellipsis'}>{props.description || '--'}</div>
+              <div className={'ellipsis'}>{props.description || ''}</div>
             </div>
           </div>
         </div>

+ 3 - 3
src/hooks/route/useHistory.tsx

@@ -1,6 +1,6 @@
 import { useHistory } from 'umi';
 import { useEffect, useState } from 'react';
-import type { LocationDescriptor, LocationState, Path } from 'history';
+import type { LocationState, Path } from 'history';
 import { model } from '@formily/reactive';
 
 export const historyStateModel = model<{ state: any }>({ state: {} });
@@ -10,9 +10,9 @@ const useHistories = () => {
 
   const [history, setHistory] = useState<any>();
 
-  const push = (location: Path | LocationDescriptor<LocationState>, state?: LocationState) => {
+  const push = (location: Path, state?: LocationState) => {
     if (state) {
-      historyStateModel.state = state;
+      historyStateModel.state[location] = state;
     }
     umiHistory.push(location, state);
   };

+ 2 - 2
src/hooks/route/useLocation.tsx

@@ -8,11 +8,11 @@ const useLocations = () => {
   useEffect(() => {
     setLocation({
       ...umiLocation,
-      state: historyStateModel.state,
+      state: historyStateModel.state[umiLocation.pathname],
     });
 
     return () => {
-      historyStateModel.state = undefined;
+      delete historyStateModel.state[umiLocation.pathname];
     };
   }, [umiLocation]);
 

+ 1 - 1
src/pages/Log/System/index.tsx

@@ -71,7 +71,7 @@ const System = () => {
       dataIndex: 'context.server',
       width: 150,
       ellipsis: true,
-      render: (text, record) => record?.context?.server || '--',
+      render: (text, record) => record?.context?.server || '',
     },
     {
       title: intl.formatMessage({

+ 5 - 5
src/pages/account/NotificationRecord/detail/index.tsx

@@ -34,15 +34,15 @@ const Detail = (props: Props) => {
         {data?.targetType === 'device' && (
           <>
             <Descriptions.Item label="告警设备" span={1}>
-              {data?.targetName || '--'}
+              {data?.targetName || ''}
             </Descriptions.Item>
             <Descriptions.Item label="设备ID" span={1}>
-              {data?.targetId || '--'}
+              {data?.targetId || ''}
             </Descriptions.Item>
           </>
         )}
         <Descriptions.Item label="告警名称" span={1}>
-          {data?.alarmName || '--'}
+          {data?.alarmName || ''}
         </Descriptions.Item>
         <Descriptions.Item label="告警时间" span={1}>
           {moment(data?.alarmTime).format('YYYY-MM-DD HH:mm:ss')}
@@ -52,10 +52,10 @@ const Detail = (props: Props) => {
             ?.title || data?.level}
         </Descriptions.Item>
         <Descriptions.Item label="告警说明" span={1}>
-          {data?.description || '--'}
+          {data?.description || ''}
         </Descriptions.Item>
         <Descriptions.Item label="告警流水" span={2}>
-          {data?.alarmInfo || '--'}
+          {data?.alarmInfo || ''}
         </Descriptions.Item>
       </Descriptions>
     </Modal>

+ 7 - 4
src/pages/account/NotificationRecord/index.tsx

@@ -13,7 +13,7 @@ import encodeQuery from '@/utils/encodeQuery';
 import { useDomFullHeight } from '@/hooks';
 import { onlyMessage } from '@/utils/util';
 import type { CustomIconComponentProps } from '@ant-design/icons/lib/components/Icon';
-import { historyStateModel } from '@/hooks/route/useHistory';
+import useLocations from '@/hooks/route/useLocation';
 import { observer } from '@formily/reactive-react';
 
 export const service = new Service('notifications');
@@ -27,6 +27,8 @@ const NotificationRecord = observer(() => {
   const [typeList, setTypeList] = useState<any>({});
   const { minHeight } = useDomFullHeight(`.record`, 24);
 
+  const location = useLocations();
+
   useEffect(() => {
     service.getProvidersList().then((resp) => {
       const obj: any = {};
@@ -38,11 +40,12 @@ const NotificationRecord = observer(() => {
   }, []);
 
   useEffect(() => {
-    if (historyStateModel.state.id) {
+    console.log(location.state);
+    if (location.state?.id) {
       setVisible(true);
-      setCurrent(historyStateModel.state);
+      setCurrent(location.state);
     }
-  }, [historyStateModel.state]);
+  }, [location.state]);
 
   const ReadSvg = () => (
     <svg

+ 5 - 5
src/pages/device/Instance/Detail/Config/index.tsx

@@ -64,7 +64,7 @@ const Config = () => {
       if (isExit(item.property)) {
         return (
           <div>
-            <span style={{ marginRight: '10px' }}>{config[item.property] || '--'}</span>
+            <span style={{ marginRight: '10px' }}>{config[item.property] || ''}</span>
             <Tooltip title={`有效值:${config[item.property]}`}>
               <QuestionCircleOutlined />
             </Tooltip>
@@ -73,16 +73,16 @@ const Config = () => {
       } else {
         return (
           <div>
-            <Tooltip title={config[item.property] || '--'} placement="topLeft">
-              <div className="ellipsis" style={{ maxWidth: 300 }}>
-                {config[item.property] || '--'}
+            <Tooltip title={config[item.property] || ''} placement="topLeft">
+              <div className="ellipsis" style={{ width: 300 }}>
+                {config[item.property] || ''}
               </div>
             </Tooltip>
           </div>
         );
       }
     } else {
-      return '--';
+      return '';
     }
   };
 

+ 1 - 1
src/pages/device/Instance/Detail/Info/index.tsx

@@ -118,7 +118,7 @@ const Info = observer(() => {
           >
             {InstanceModel.detail?.onlineTime
               ? moment(InstanceModel.detail?.onlineTime).format('YYYY-MM-DD HH:mm:ss')
-              : '--'}
+              : ''}
           </Descriptions.Item>
           <Descriptions.Item
             label={intl.formatMessage({

Разница между файлами не показана из-за своего большого размера
+ 317 - 2
src/pages/device/Instance/Detail/Parsing/index.tsx


+ 2 - 2
src/pages/device/Instance/Detail/Reation/index.tsx

@@ -58,11 +58,11 @@ const Reation = () => {
         {(data || [])?.map((item: any) => (
           <Descriptions.Item span={1} label={item.relationName} key={item.objectId}>
             <Tooltip
-              title={item?.related ? _.map(item?.related || [], 'name').join(',') : '--'}
+              title={item?.related ? _.map(item?.related || [], 'name').join(',') : ''}
               placement="topLeft"
             >
               <div className="ellipsis" style={{ width: 300 }}>
-                {item?.related ? _.map(item?.related || [], 'name').join(',') : '--'}
+                {item?.related ? _.map(item?.related || [], 'name').join(',') : ''}
               </div>
             </Tooltip>
           </Descriptions.Item>

+ 3 - 1
src/pages/device/Instance/Detail/Running/Property/FileComponent/index.tsx

@@ -33,7 +33,9 @@ const FileComponent = (props: Props) => {
 
   const renderValue = () => {
     if (value?.formatValue !== 0 && !value?.formatValue) {
-      return <div className={props.type === 'card' ? styles.cardValue : styles.otherValue}>--</div>;
+      return (
+        <div className={props.type === 'card' ? styles.cardValue : styles.otherValue}>{''}</div>
+      );
     } else if (data?.valueType?.type === 'file') {
       if (
         data?.valueType?.fileType === 'base64' ||

+ 1 - 1
src/pages/device/Instance/Detail/Running/Property/PropertyCard.tsx

@@ -107,7 +107,7 @@ const Property = (props: Props) => {
           <div style={{ marginTop: 10 }}>
             <div style={{ color: 'rgba(0, 0, 0, .65)', fontSize: 12 }}>更新时间</div>
             <div style={{ marginTop: 5, fontSize: 16, color: 'black' }} className="value">
-              {value?.timestamp ? moment(value?.timestamp).format('YYYY-MM-DD HH:mm:ss') : '--'}
+              {value?.timestamp ? moment(value?.timestamp).format('YYYY-MM-DD HH:mm:ss') : ''}
             </div>
           </div>
         </div>

+ 1 - 1
src/pages/device/Instance/Detail/Running/Property/index.tsx

@@ -288,7 +288,7 @@ const Property = (props: Props) => {
               <Row gutter={[16, 16]} style={{ minHeight: 450 }}>
                 {dataSource.data.map((item: any) => (
                   <Col {...ColResponsiveProps} key={item.id}>
-                    <PropertyCard data={item} value={item?.id ? propertyValue[item?.id] : '--'} />
+                    <PropertyCard data={item} value={item?.id ? propertyValue[item?.id] : ''} />
                   </Col>
                 ))}
               </Row>

+ 3 - 3
src/pages/device/Instance/Detail/Tags/index.tsx

@@ -45,9 +45,9 @@ const Tags = () => {
       >
         {(tags || [])?.map((item: any) => (
           <Descriptions.Item span={1} label={`${item.name}(${item.key})`} key={item.key}>
-            <Tooltip title={item.value || '--'} placement="topLeft">
-              <div className="ellipsis" style={{ maxWidth: 300 }}>
-                {item.value || '--'}
+            <Tooltip title={item.value || ''} placement="topLeft">
+              <div className="ellipsis" style={{ width: 300 }}>
+                {item.value || ''}
               </div>
             </Tooltip>
           </Descriptions.Item>

+ 10 - 8
src/pages/device/Instance/Detail/index.tsx

@@ -136,14 +136,6 @@ const InstanceDetail = observer(() => {
       component: <Functions />,
     },
     {
-      key: 'parsing',
-      tab: intl.formatMessage({
-        id: 'pages.device.instanceDetail.parsing',
-        defaultMessage: '数据解析',
-      }),
-      component: <Parsing />,
-    },
-    {
       key: 'log',
       tab: intl.formatMessage({
         id: 'pages.device.instanceDetail.log',
@@ -185,6 +177,16 @@ const InstanceDetail = observer(() => {
           component: <MetadataMap type="device" />,
         });
       }
+      if (response.result.transport === 'MQTT' || response.result.transport === 'HTTP') {
+        datalist.push({
+          key: 'parsing',
+          tab: intl.formatMessage({
+            id: 'pages.device.instanceDetail.parsing',
+            defaultMessage: '数据解析',
+          }),
+          component: <Parsing tag="device" data={InstanceModel.detail} />,
+        });
+      }
       if (response.result.protocol === 'modbus-tcp') {
         datalist.push({
           key: 'modbus',

+ 33 - 0
src/pages/device/Instance/service.ts

@@ -303,6 +303,39 @@ class Service extends BaseService<DeviceInstance> {
       method: 'POST',
       data,
     });
+  //获取产品解析规则
+  public productCode = (productId: string) =>
+    request(`/${SystemConst.API_BASE}/device/transparent-codec/${productId}`, {
+      method: 'GET',
+    });
+  //保存产品解析规则
+  public saveProductCode = (productId: string, data: any) =>
+    request(`/${SystemConst.API_BASE}/device/transparent-codec/${productId}`, {
+      method: 'POST',
+      data,
+    });
+  //获取设备解析规则
+  public deviceCode = (productId: string, deviceId: string) =>
+    request(`/${SystemConst.API_BASE}/device/transparent-codec/${productId}/${deviceId}`, {
+      method: 'GET',
+    });
+  //保存设备解析规则
+  public saveDeviceCode = (productId: string, deviceId: string, data: any) =>
+    request(`/${SystemConst.API_BASE}/device/transparent-codec/${productId}/${deviceId}`, {
+      method: 'POST',
+      data,
+    });
+  //编码测试
+  public testCode = (data: any) =>
+    request(`/${SystemConst.API_BASE}/device/transparent-codec/decode-test`, {
+      method: 'POST',
+      data,
+    });
+  //获取指定协议
+  public getProtocal = (id: string, transport: string) =>
+    request(`/${SystemConst.API_BASE}/protocol/${id}/transport/${transport}`, {
+      method: 'GET',
+    });
 }
 
 export default Service;

+ 1 - 0
src/pages/device/Instance/typings.d.ts

@@ -41,6 +41,7 @@ export type DeviceInstance = {
   photoUrl: string;
   independentMetadata?: boolean;
   accessProvider?: string;
+  accessId?: string;
   features?: any[];
 };
 

+ 18 - 0
src/pages/device/Product/Detail/index.tsx

@@ -18,6 +18,7 @@ import SystemConst from '@/utils/const';
 import { PermissionButton } from '@/components';
 import { QuestionCircleOutlined } from '@ant-design/icons';
 import { onlyMessage } from '@/utils/util';
+import Parsing from '../../Instance/Detail/Parsing';
 
 export const ModelEnum = {
   base: 'base',
@@ -153,6 +154,7 @@ const ProductDetail = observer(() => {
   };
 
   useEffect(() => {
+    console.log(productModel.current);
     if (
       productModel.current?.accessProvider &&
       pList.includes(productModel.current?.accessProvider)
@@ -168,6 +170,22 @@ const ProductDetail = observer(() => {
     } else {
       setList([...initList]);
     }
+    if (
+      productModel.current?.transportProtocol === 'MQTT' ||
+      productModel.current?.transportProtocol === 'HTTP'
+    ) {
+      setList([
+        ...initList,
+        {
+          key: 'parsing',
+          tab: intl.formatMessage({
+            id: 'pages.device.instanceDetail.parsing',
+            defaultMessage: '数据解析',
+          }),
+          component: <Parsing tag="product" data={productModel.current} />,
+        },
+      ]);
+    }
   }, [productModel.current]);
 
   useEffect(() => {

+ 3 - 3
src/pages/link/AccessConfig/Detail/Channel/index.tsx

@@ -109,11 +109,11 @@ const Media = (props: Props) => {
             <div style={{ marginLeft: 10 }}>
               <TitleComponent data={'配置概览'} />
               <div>
-                <p>接入方式:{props.provider?.name || '--'}</p>
-                {props.provider?.description && <p>{props.provider?.description || '--'}</p>}
+                <p>接入方式:{props.provider?.name || ''}</p>
+                {props.provider?.description && <p>{props.provider?.description || ''}</p>}
                 <p>消息协议:{procotol}</p>
                 {config?.document && (
-                  <div>{<ReactMarkdown>{config?.document}</ReactMarkdown> || '--'}</div>
+                  <div>{<ReactMarkdown>{config?.document}</ReactMarkdown> || ''}</div>
                 )}
               </div>
               <TitleComponent data={'设备接入指引'} />

+ 3 - 3
src/pages/link/AccessConfig/Detail/Cloud/Finish/index.tsx

@@ -101,11 +101,11 @@ const Finish = (props: Props) => {
         <div style={{ marginLeft: 10 }}>
           <TitleComponent data={'配置概览'} />
           <div>
-            <p>接入方式:{props.provider?.name || '--'}</p>
-            {props.provider?.description && <p>{props.provider?.description || '--'}</p>}
+            <p>接入方式:{props.provider?.name || ''}</p>
+            {props.provider?.description && <p>{props.provider?.description || ''}</p>}
             <p>消息协议:{props.procotol}</p>
             {config?.document && (
-              <div>{<ReactMarkdown>{config?.document}</ReactMarkdown> || '--'}</div>
+              <div>{<ReactMarkdown>{config?.document}</ReactMarkdown> || ''}</div>
             )}
           </div>
           <TitleComponent data={'设备接入指引'} />

+ 2 - 2
src/pages/link/AccessConfig/Detail/Cloud/Protocol/index.tsx

@@ -99,8 +99,8 @@ const Protocol = (props: Props) => {
                 }}
               >
                 <div style={{ height: '45px' }}>
-                  <div className={styles.title}>{item.name || '--'}</div>
-                  <div className={styles.desc}>{item.description || '--'}</div>
+                  <div className={styles.title}>{item.name || ''}</div>
+                  <div className={styles.desc}>{item.description || ''}</div>
                 </div>
               </Card>
             </Col>

+ 3 - 0
src/pages/link/Protocol/FileUpload/index.tsx

@@ -51,6 +51,9 @@ const FileUpload = connect((props: Props) => {
               e.stopPropagation();
             }}
             placeholder="请上传文件"
+            onBlur={(e) => {
+              props.onChange(e.target.value);
+            }}
           />
           <Button
             disabled={props?.disabled}

+ 4 - 12
src/pages/link/Protocol/save/index.tsx

@@ -242,19 +242,11 @@ const Save = (props: Props) => {
     },
   };
 
-  const save = async (deploy: boolean) => {
+  const save = async () => {
     const value = await form.submit<ProtocolItem>();
-    let response = undefined;
-    if (!props.data?.id) {
-      response = await service.save(value);
-    } else {
-      response = await service.update(value);
-    }
-    if (response && response.status === 200) {
+    const response: any = await service.savePatch({ ...props.data, ...value });
+    if (response && response?.status === 200) {
       onlyMessage('操作成功');
-      if (deploy) {
-        await service.modifyState(value.id, 'deploy');
-      }
       props.reload();
       if ((window as any).onTabSaveSuccess) {
         (window as any).onTabSaveSuccess(response);
@@ -278,7 +270,7 @@ const Save = (props: Props) => {
           type="primary"
           key={2}
           onClick={() => {
-            save(false);
+            save();
           }}
           disabled={props.data?.id ? !permission.update : !permission.add}
         >

+ 5 - 5
src/pages/media/Device/Save/ProviderSelect.tsx

@@ -113,12 +113,12 @@ export default (props: ProviderProps) => {
                 </div>
                 <div className={styles.card}>
                   <div className={styles.header}>
-                    <div className={styles.title}>{item.name || '--'}</div>
-                    <div className={styles.desc}>{item.description || '--'}</div>
+                    <div className={styles.title}>{item.name || ''}</div>
+                    <div className={styles.desc}>{item.description || ''}</div>
                   </div>
                   <div className={styles.container}>
                     <div className={styles.server}>
-                      <div className={styles.subTitle}>{item?.channelInfo?.name || '--'}</div>
+                      <div className={styles.subTitle}>{item?.channelInfo?.name || ''}</div>
                       <div style={{ width: '100%' }}>
                         {item.channelInfo?.addresses.map((i: any, index: number) => (
                           <p key={i.address + `_address${index}`}>
@@ -128,8 +128,8 @@ export default (props: ProviderProps) => {
                       </div>
                     </div>
                     <div className={styles.procotol}>
-                      <div className={styles.subTitle}>{item?.protocolDetail?.name || '--'}</div>
-                      <p>{item.protocolDetail?.description || '--'}</p>
+                      <div className={styles.subTitle}>{item?.protocolDetail?.name || ''}</div>
+                      <p>{item.protocolDetail?.description || ''}</p>
                     </div>
                   </div>
                 </div>

+ 65 - 47
src/pages/media/Device/Save/index.tsx

@@ -136,6 +136,7 @@ const Save = () => {
                         model={'singular'}
                         itemStyle={{ width: '50%' }}
                         onSelect={(key) => {
+                          console.log(key);
                           setAccessType(key);
                           queryProduct(key);
                         }}
@@ -341,55 +342,72 @@ const Save = () => {
               </Form>
             </Col>
             <Col span={12}>
-              <div className={styles.doc} style={{ height: 800 }}>
-                <h1>1、概述</h1>
-                <div>
-                  视频设备通过GB/T28181接入平台整体分为2部分,包括平台端配置和设备端配置,不同的设备端配置的路径或页面存在差异,但配置项基本大同小异。
+              {accessType === DefaultAccessType ? (
+                <div className={styles.doc} style={{ height: 800 }}>
+                  <h1>1.概述</h1>
+                  <div>
+                    视频设备通过GB/T28181接入平台整体分为2部分,包括平台端配置和设备端配置,不同的设备端配置的路径或页面存在差异,但配置项基本大同小异。
+                  </div>
+                  <h1>2.配置说明</h1>
+                  <h1>平台端配置</h1>
+                  <h2>1、ID</h2>
+                  <div>设备唯一标识,若不填写,系统将自动生成唯一标识</div>
+                  <h2>2、所属产品</h2>
+                  <div>
+                    只能选择接入方式为GB/T28281的产品,若当前无对应产品,可点击右侧快速添加按钮,填写产品名称和选择GB/T28181类型的网关完成产品创建
+                  </div>
+                  <h2>3、接入密码</h2>
+                  <div>
+                    配置接入密码,设备端配置的密码需与该密码一致。该字段可在产品-设备接入页面进行统一配置,配置后所有设备将继承产品配置。设备单独修改后将脱离继承关系。
+                  </div>
+                  <h1>设备端配置</h1>
+                  <div>
+                    各个厂家、不同设备型号的设备端配置页面布局存在差异,但配置项基本大同小异,此处以大华摄像头为例作为接入配置示例
+                  </div>
+                  <div className={styles.image}>
+                    <Image width="100%" src={img1} />
+                  </div>
+                  <h2>1、SIP服务器编号/SIP域</h2>
+                  <div>
+                    SIP服务器编号填入该设备所属产品-接入方式页面“连接信息”的SIP。
+                    SIP域通常为SIP服务器编号的前10位。
+                  </div>
+                  <div className={styles.image}>
+                    <Image width="100%" src={img2} />
+                  </div>
+                  <h2>2、SIP服务器IP/端口</h2>
+                  <div>SIP服务器IP/端口填入该设备所属产品-接入方式页面中“连接信息”的IP/端口。</div>
+                  <div className={styles.image}>
+                    <Image width="100%" src={img3} />
+                  </div>
+                  <h2>3、设备编号</h2>
+                  <div>
+                    设备编号为设备唯一性标识,物联网平台的设备接入没有校验该字段,输入任意数字均不影响设备接入平台。
+                  </div>
+                  <h2>4、注册密码</h2>
+                  <div>填入该设备所属产品-接入方式页面中“GB28281配置”处的接入密码</div>
+                  <div className={styles.image}>
+                    <Image width="100%" src={img4} />
+                  </div>
+                  <h2>5、其他字段</h2>
+                  <div>不影响设备接入平台,可保持设备初始化值。</div>
                 </div>
-                <h1>2、配置说明</h1>
-                <h1>平台端配置</h1>
-                <h2>1、ID</h2>
-                <div>设备唯一标识,若不填写,系统将自动生成唯一标识</div>
-                <h2>2、所属产品</h2>
-                <div>
-                  只能选择接入方式为GB/T28281的产品,若当前无对应产品,可点击右侧快速添加按钮,填写产品名称和选择GB/T28181类型的网关完成产品创建
+              ) : (
+                <div className={styles.doc} style={{ height: 600 }}>
+                  <h1>1.概述</h1>
+                  <div>视频设备通过RTSP、RTMP固定地址接入平台分为2步。</div>
+                  <div>1.添加视频设备</div>
+                  <div>2.添加视频下的通道地址。</div>
+                  <div>注:当前页面为新增视频设备,新增完成后点击设备的“通道”按钮,添加通道。</div>
+                  <h1>2.配置说明</h1>
+                  <h2>1、ID</h2>
+                  <div>设备唯一标识,若不填写,系统将自动生成唯一标识。</div>
+                  <h2>2、所属产品</h2>
+                  <div>
+                    只能选择接入方式为固定地址的产品,若当前无对应产品,可点击右侧快速添加按钮,填写产品名称和选择固定地址类型的网关完成产品创建。
+                  </div>
                 </div>
-                <h2>3、接入密码</h2>
-                <div>
-                  配置接入密码,设备端配置的密码需与该密码一致。该字段可在产品-设备接入页面进行统一配置,配置后所有设备将继承产品配置。设备单独修改后将脱离继承关系。
-                </div>
-                <h1>设备端配置</h1>
-                <div>
-                  各个厂家、不同设备型号的设备端配置页面布局存在差异,但配置项基本大同小异,此处以大华摄像头为例作为接入配置示例
-                </div>
-                <div className={styles.image}>
-                  <Image width="100%" src={img1} />
-                </div>
-                <h2>1、SIP服务器编号/SIP域</h2>
-                <div>
-                  SIP服务器编号填入该设备所属产品-接入方式页面“连接信息”的SIP。
-                  SIP域通常为SIP服务器编号的前10位。
-                </div>
-                <div className={styles.image}>
-                  <Image width="100%" src={img2} />
-                </div>
-                <h2>2、SIP服务器IP/端口</h2>
-                <div>SIP服务器IP/端口填入该设备所属产品-接入方式页面中“连接信息”的IP/端口。</div>
-                <div className={styles.image}>
-                  <Image width="100%" src={img3} />
-                </div>
-                <h2>3、设备编号</h2>
-                <div>
-                  设备编号为设备唯一性标识,物联网平台的设备接入没有校验该字段,输入任意数字均不影响设备接入平台。
-                </div>
-                <h2>4、注册密码</h2>
-                <div>填入该设备所属产品-接入方式页面中“GB28281配置”处的接入密码</div>
-                <div className={styles.image}>
-                  <Image width="100%" src={img4} />
-                </div>
-                <h2>5、其他字段</h2>
-                <div>不影响设备接入平台,可保持设备初始化值。</div>
-              </div>
+              )}
             </Col>
           </Row>
         </Card>

+ 3 - 3
src/pages/notice/Config/Detail/doc/AliyunSms.tsx

@@ -11,19 +11,19 @@ const AliyunSms = () => {
           https://home.console.aliyun.com
         </a>
       </div>
-      <h1>1. 概述</h1>
+      <h1>1.概述</h1>
       <div>
         通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
       </div>
       <h1>2.通知配置说明</h1>
       <div>
-        <h2>1. RegionID</h2>
+        <h2>1RegionID</h2>
         <div>阿里云内部给每台机器设置的唯一编号。请根据购买的阿里云服务器地址进行填写。</div>
         <div>
           阿里云地域和可用区对照表地址:https://help.aliyun.com/document_detail/40654.html?spm=a2c6h.13066369.0.0.54a174710O7rWH
         </div>
       </div>
-      <h2>2. AccesskeyID/Secret</h2>
+      <h2>2AccesskeyID/Secret</h2>
       <div>
         <div>用于程序通知方式调用云服务费API的用户标识和秘钥</div>
         <div>获取路径:“阿里云管理控制台”--“用户头像”--“”--“AccessKey管理”--“查看”</div>

+ 1 - 1
src/pages/notice/Config/Detail/doc/AliyunVoice.tsx

@@ -18,7 +18,7 @@ const AliyunVoice = () => {
       </div>
       <h1>2.通知配置说明</h1>
       <div>
-        <h2>1. RegionID</h2>
+        <h2>1RegionID</h2>
         <div>
           阿里云内部给每台机器设置的唯一编号。请根据购买的阿里云服务器阿里云地域和可用区对照表地址:https://help.aliyun.com/document_detail/40654.html?spm=a2c6h.13066369.0.0.54a174710O7rWH获取路径:“微信公众平台”管理后台--“设置与开发”--“基本配置”
         </div>

+ 2 - 2
src/pages/notice/Config/Detail/doc/DingTalk.tsx

@@ -18,7 +18,7 @@ const DingTalk = () => {
       </div>
       <h1>2.通知配置说明</h1>
       <div>
-        <h2>1. AppKey</h2>
+        <h2>1AppKey</h2>
         <div>
           企业内部应用的唯一身份标识。在钉钉开发者后台创建企业内部应用后,系统会自动生成一对AppKey和AppSecret。
         </div>
@@ -27,7 +27,7 @@ const DingTalk = () => {
           <Image width="100%" src={appKey} />
         </div>
       </div>
-      <h2>2. AppSecret</h2>
+      <h2>2AppSecret</h2>
       <div>
         <div>钉钉应用对应的调用密钥</div>
         <div>获取路径:“钉钉开放平台”--“应用开发”--“应用信息”</div>

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

@@ -15,7 +15,7 @@ const DingTalkRebot = () => {
       </div>
       <h1>2.通知配置说明</h1>
       <div>
-        <h2> 1. WebHook</h2>
+        <h2> 1WebHook</h2>
         <div>在钉钉群内每创建一个钉钉群自定义机器人都会产生唯一的WebHook地址。</div>
         <div>获取路径:“钉钉桌面客户端”--“群设置”--“智能群助手”--“机器人信息”</div>
         <div className={'image'}>

+ 4 - 4
src/pages/notice/Config/Detail/doc/Email.tsx

@@ -8,16 +8,16 @@ const Email = () => {
         通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
       </div>
       <h1>2.通知配置说明</h1>
-      <h2>1. 服务器地址</h2>
+      <h2>1 服务器地址</h2>
       <div>下拉可选择国内常用的邮箱服务配置,也支持手动输入其他地址。</div>
       <div>
         系统POP协议。POP允许电子邮件客户端下载服务器上的邮件,但是您在电子邮件客户端的操作(如:移动邮件、标记已读等),这是不会反馈到服务器上。
       </div>
-      <h2>2. 发件人</h2>
+      <h2>2发件人</h2>
       <div>用于发送邮件时“发件人“信息的显示</div>
-      <h2>3. 用户名</h2>
+      <h2>3 用户名</h2>
       <div>用该账号进行发送邮件。</div>
-      <h2>4. 密码</h2>
+      <h2>4密码</h2>
       <div>用与账号身份认证,认证通过后可通过该账号进行发送邮件。</div>
     </div>
   );

+ 2 - 2
src/pages/notice/Config/Detail/doc/Webhook.tsx

@@ -9,10 +9,10 @@ const Webhook = () => {
         POST请求),实现了Webhook的第三方系统可以基于该URL订阅本平台系统信息,本平台按配置把特定的事件结果推送到指定的地址,便于系统做后续处理。
       </div>
       <h1>2.通知配置说明</h1>
-      <h2>1. Webhook</h2>
+      <h2>1Webhook</h2>
       <div>Webhook地址。</div>
 
-      <h2>2. 请求头</h2>
+      <h2>2请求头</h2>
       <div>支持根据系统提供的接口设置不同的请求头。如 Accept-Language 、Content-Type</div>
     </div>
   );

+ 2 - 2
src/pages/notice/Config/Detail/doc/WeixinApp.tsx

@@ -19,14 +19,14 @@ const WeixinApp = () => {
       </div>
       <h1>2.通知配置说明</h1>
       <div>
-        <h2>1. AppID</h2>
+        <h2>1AppID</h2>
         <div>微信服务号的唯一专属编号。</div>
         <div>获取路径:“微信公众平台”管理后台--“设置与开发”--“基本配置”</div>
         <div className={'image'}>
           <Image width="100%" src={appId} />
         </div>
       </div>
-      <h2>2. AppSecret</h2>
+      <h2>2AppSecret</h2>
       <div>
         <div>公众号开发者身份的密码</div>
         <div>获取路径:“微信公众平台”管理后台--“设置与开发”--“基本配置”</div>

+ 2 - 2
src/pages/notice/Config/Detail/doc/WeixinCorp.tsx

@@ -18,7 +18,7 @@ const WeixinCorp = () => {
       </div>
       <h1>2.通知配置说明</h1>
       <div>
-        <h2>1. corpId</h2>
+        <h2>1corpId</h2>
         <div>企业号的唯一专属编号。</div>
         <div>获取路径:“企业微信”管理后台--“我的企业”--“企业ID”</div>
         <div className={'image'}>
@@ -26,7 +26,7 @@ const WeixinCorp = () => {
         </div>
       </div>
 
-      <h2>2. corpSecret</h2>
+      <h2>2corpSecret</h2>
       <div>
         <div>应用的唯一secret,一个企业微信中可以有多个corpSecret</div>
         <div>获取路径:“企业微信”--“应用与小程序”--“自建应用”中获取</div>

+ 1 - 1
src/pages/notice/Config/SyncUser/index.tsx

@@ -45,7 +45,7 @@ const SyncUser = observer(() => {
       dataIndex: 'userId',
       title: `用户`,
       render: (text: any, record: any) => (
-        <span>{record?.userId ? `${record?.userName}(${record?.username})` : '--'}</span>
+        <span>{record?.userId ? `${record?.userName}(${record?.username})` : ''}</span>
       ),
     },
     {

+ 3 - 3
src/pages/notice/Template/Detail/doc/DingTalk.tsx

@@ -26,13 +26,13 @@ const DingTalk = () => {
       <h1> 2.模板配置说明</h1>
       <h2> 1、绑定配置</h2>
       <div> 使用固定的通知配置发送此通知模板</div>
-      <h2> 2. Agentid</h2>
+      <h2> 2Agentid</h2>
       <div> 应用唯一标识</div>
       <div className="image">
         <Image width="100%" src={agentId} />
       </div>
       <div> 获取路径:“钉钉开发平台”--“应用开发”--“查看应用”</div>
-      <h2> 3. 收信人ID、收信部门ID</h2>
+      <h2> 3收信人ID、收信部门ID</h2>
       <div>
         接收通知的2种方式,2个字段若在此页面都没有填写,则在模板调试和配置告警通知时需要手动填写
       </div>
@@ -42,7 +42,7 @@ const DingTalk = () => {
         <Image width="100%" src={userId} />
         <Image width="100%" src={dept} />
       </div>
-      <h2> 4. 模板内容</h2>
+      <h2> 4模板内容</h2>
       <div>
         支持填写带变量的动态模板。变量填写规范示例:${a}
         。填写动态参数后,可对变量的名称、类型、格式进行配置,以便告警通知时填写。

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

@@ -20,7 +20,7 @@ const DingTalkRebot = () => {
         <div> 使用固定的通知配置发送此通知模板</div>
         <h2> 2、消息类型</h2>
         <div> 目前支持text、markdown、link3种。</div>
-        <h2> 3. 模板内容</h2>
+        <h2> 3模板内容</h2>
         <div>
           支持填写带变量的动态模板。变量填写规范示例:${b}
           。填写动态参数后,可对变量的名称、类型、格式进行配置,以便告警通知时填写。

+ 4 - 4
src/pages/notice/Template/Detail/doc/Email.tsx

@@ -12,13 +12,13 @@ const Email = () => {
       </div>
       <h1>2.模板配置说明</h1>
       <div>
-        <h2> 1. 服务器地址</h2>
+        <h2> 1服务器地址</h2>
         <div>服务器地址支持自定义输入</div>
-        <h2> 2. 标题</h2>
+        <h2> 2标题</h2>
         <div>支持输入变量,变量格式${a}</div>
-        <h2> 3. 收件人</h2>
+        <h2> 3收件人</h2>
         <div> 支持录入多个邮箱地址,可填写变量参数。</div>
-        <h2> 4. 模板内容</h2>
+        <h2> 4模板内容</h2>
         <div>
           支持填写带变量的动态模板。变量填写规范示例:${b}
           。填写动态参数后,可对变量的名称、类型、格式进行配置,以便告警通知时填写。

+ 7 - 7
src/pages/notice/Template/Detail/doc/WeixinApp.tsx

@@ -18,34 +18,34 @@ const WeixinApp = () => {
       </div>
       <h1>2.模板配置说明</h1>
       <div>
-        <h2>1. 绑定配置</h2>
+        <h2>1绑定配置</h2>
         <div>使用固定的通知配置发送此通知模板</div>
       </div>
       <div>
-        <h2>2. 用户标签</h2>
+        <h2>2用户标签</h2>
         <div>以标签的维度通知该标签下所有用户</div>
       </div>
       <div>
-        <h2>3. 消息模板</h2>
+        <h2>3消息模板</h2>
         <div>微信公众号中配置的消息模板</div>
       </div>
       <div>
-        <h2>4. 模板跳转链接</h2>
+        <h2>4模板跳转链接</h2>
         <div>点击消息之后进行页面跳转</div>
       </div>
       <div>
-        <h2>5. 跳转小程序Appid</h2>
+        <h2>5跳转小程序Appid</h2>
         <div>点击消息之后打开对应的小程序</div>
       </div>
       <div>
-        <h2>6. 跳转小程序具体路径</h2>
+        <h2>6跳转小程序具体路径</h2>
         <div>点击消息之后跳转到小程序的具体页面</div>
         <div className="image">
           <Image width="100%" src={appId} />
         </div>
       </div>
       <div>
-        <h2>7. 模板内容</h2>
+        <h2>7模板内容</h2>
         <div>
           支持填写带变量的动态模板。变量填写规范示例:${name}
           。填写动态参数后,可对变量的名称、类型、格式进行配置,以便告警通知时填写。

+ 2 - 2
src/pages/notice/Template/Detail/doc/WeixinCorp.tsx

@@ -23,13 +23,13 @@ const WeixinCorp = () => {
       <div>
         <h2> 1、绑定配置</h2>
         <div> 使用固定的通知配置发送此通知模板</div>
-        <h2> 2. Agentid</h2>
+        <h2> 2Agentid</h2>
         <div> 应用唯一标识</div>
         <div> 获取路径:“企业微信”管理后台--“应用管理”--“应用”--“查看应用”</div>
         <div className="image">
           <Image width="100%" src={agentId} />
         </div>
-        <h2> 3. 收信人ID、收信部门ID、标签推送</h2>
+        <h2> 3收信人ID、收信部门ID、标签推送</h2>
         <div>
           接收通知的3种方式,3个字段若在此页面都没有填写,则在模板调试和配置告警通知时需要手动填写
         </div>

+ 6 - 6
src/pages/rule-engine/Alarm/Log/Detail/Info.tsx

@@ -29,15 +29,15 @@ const Info = (props: Props) => {
         {data.targetType === 'device' && (
           <>
             <Descriptions.Item label="告警设备" span={1}>
-              {data?.targetName || '--'}
+              {data?.targetName || ''}
             </Descriptions.Item>
             <Descriptions.Item label="设备ID" span={1}>
-              {data?.targetId || '--'}
+              {data?.targetId || ''}
             </Descriptions.Item>
           </>
         )}
         <Descriptions.Item label="告警名称" span={1}>
-          {data?.alarmConfigName || '--'}
+          {data?.alarmConfigName || ''}
         </Descriptions.Item>
         <Descriptions.Item label="告警时间" span={1}>
           {moment(data?.alarmTime).format('YYYY-MM-DD HH:mm:ss')}
@@ -57,14 +57,14 @@ const Info = (props: Props) => {
           </Tooltip>
         </Descriptions.Item>
         <Descriptions.Item label="告警说明" span={1}>
-          <Tooltip placement="topLeft" title={data?.description || '--'}>
+          <Tooltip placement="topLeft" title={data?.description || ''}>
             <div className="ellipsis" style={{ maxWidth: 1 }}>
-              {data?.description || '--'}
+              {data?.description || ''}
             </div>
           </Tooltip>
         </Descriptions.Item>
         <Descriptions.Item label="告警流水" span={2}>
-          {data?.alarmInfo || '--'}
+          {data?.alarmInfo || ''}
         </Descriptions.Item>
       </Descriptions>
     </Modal>

+ 18 - 8
src/pages/system/Platforms/Api/base.tsx

@@ -8,9 +8,10 @@ import { observer } from '@formily/react';
 import './index.less';
 import { useLocation } from 'umi';
 import { useDomFullHeight } from '@/hooks';
+import Home from '../Home';
 
 export const ApiModel = model<{
-  data: any[];
+  data: any[] | undefined;
   baseUrl: string;
   showTable: boolean;
   components: any;
@@ -36,6 +37,7 @@ interface ApiPageProps {
    */
   isOpenGranted?: boolean;
   type?: 'all' | 'empowerment' | 'authorize';
+  showHome?: boolean;
 }
 
 export default observer((props: ApiPageProps) => {
@@ -98,21 +100,29 @@ export default observer((props: ApiPageProps) => {
           isShowGranted={props.isShowGranted}
           grantKeys={GrantKeys}
           operations={operations}
+          showHome={props.showHome}
           type={props.type}
           onSelect={(data) => {
+            console.log(data);
             ApiModel.data = data;
             ApiModel.showTable = true;
           }}
         />
       </div>
       {ApiModel.showTable ? (
-        <Table
-          data={ApiModel.data}
-          operations={operations}
-          isOpenGranted={props.isOpenGranted}
-          isShowGranted={props.isShowGranted}
-          grantKeys={GrantKeys}
-        />
+        <>
+          {ApiModel.data ? (
+            <Table
+              data={ApiModel.data}
+              operations={operations}
+              isOpenGranted={props.isOpenGranted}
+              isShowGranted={props.isShowGranted}
+              grantKeys={GrantKeys}
+            />
+          ) : (
+            <Home />
+          )}
+        </>
       ) : (
         <SwaggerUI showDebugger={props.showDebugger} />
       )}

+ 1 - 1
src/pages/system/Platforms/Api/index.tsx

@@ -4,7 +4,7 @@ import BasePage from './base';
 export default () => {
   return (
     <PageContainer>
-      <BasePage type={'empowerment'} />
+      <BasePage type={'empowerment'} showHome={true} />
     </PageContainer>
   );
 };

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

@@ -12,6 +12,7 @@ type LeftTreeType = {
   grantKeys?: string[]; // 已授权的接口
   type?: 'all' | 'empowerment' | 'authorize'; // 全部、赋权、授权
   operations?: string[]; // 能赋权的key
+  showHome?: boolean;
 };
 
 interface DataNode {
@@ -28,7 +29,19 @@ export default (props: LeftTreeType) => {
   const getLevelOne = async () => {
     const resp = await service.getApiFirstLevel();
     if (resp.urls && resp.urls.length) {
-      setTreeData(resp.urls.map((item: any) => ({ ...item, id: item.url })));
+      if (props.showHome) {
+        const home = [
+          {
+            id: 'home',
+            name: '首页',
+            isLeaf: true,
+          },
+        ];
+        ApiModel.data = undefined;
+        setTreeData(home.concat(resp.urls.map((item: any) => ({ ...item, id: item.url }))));
+      } else {
+        setTreeData(resp.urls.map((item: any) => ({ ...item, id: item.url })));
+      }
     }
   };
 
@@ -152,6 +165,12 @@ export default (props: LeftTreeType) => {
           props.onSelect(node.extraData);
         }
       }}
+      // onExpand={(_,{node}:any)=>{
+      //   if (node.isLeaf && props.onSelect) {
+      //     props.onSelect(node.extraData);
+      //   }
+      // }}
+      defaultSelectedKeys={['home']}
       loadData={onLoadData}
       treeData={treeData}
     />

+ 38 - 0
src/pages/system/Platforms/Home/index.less

@@ -0,0 +1,38 @@
+.home {
+  padding: 20px;
+
+  h1 {
+    font-weight: 600;
+    font-size: 20px;
+  }
+
+  h2 {
+    font-weight: 600;
+    font-size: 18px;
+  }
+
+  .h2-text {
+    color: #999;
+  }
+
+  h3 {
+    margin-top: 10px;
+    font-weight: 600;
+    font-size: 16px;
+  }
+
+  .h3-text {
+    max-width: 530px;
+    margin-top: 3px;
+    color: #999;
+  }
+
+  p {
+    color: #666;
+  }
+
+  .div-border {
+    padding: 10px;
+    border-left: 10px solid #eee;
+  }
+}

Разница между файлами не показана из-за своего большого размера
+ 175 - 0
src/pages/system/Platforms/Home/index.tsx


+ 1 - 1
src/pages/system/Platforms/Setting/index.tsx

@@ -9,7 +9,7 @@ export default () => {
         <ExclamationCircleOutlined style={{ marginRight: 12, fontSize: 16 }} />
         配置系统支持API赋权的范围
       </div>
-      <ApiPage type={'all'} showDebugger={true} isOpenGranted={false} />
+      <ApiPage type={'all'} showDebugger={true} isOpenGranted={false} showHome={false} />
     </PageContainer>
   );
 };

+ 1 - 1
src/pages/system/Platforms/View/index.tsx

@@ -111,7 +111,7 @@ export default () => {
         </Col>
         <Col span={24}>
           <Card title={'API文档'}>
-            <ApiPage type={'authorize'} showDebugger={true} isShowGranted={true} />
+            <ApiPage type={'authorize'} showDebugger={true} isShowGranted={true} showHome={true} />
           </Card>
         </Col>
       </Row>

+ 43 - 1
src/pages/system/Role/Detail/Permission/Allocate/MenuPermission.tsx

@@ -99,6 +99,26 @@ const MenuPermission = (props: Props) => {
                 fontWeight: value.id === 'menu-permission' ? 600 : 400,
               }}
               onChange={(e) => {
+                let access: any[] = [];
+                if (e.target.checked && !checkValue) {
+                  setCheckValue('creator');
+                  access = (value?.assetAccesses || []).map((i: any) => {
+                    return {
+                      ...i,
+                      granted: i.supportId === 'creator',
+                    };
+                  });
+                } else if (!e.target.checked) {
+                  setCheckValue('');
+                  access = (value?.assetAccesses || []).map((i: any) => {
+                    return {
+                      ...i,
+                      granted: false,
+                    };
+                  });
+                } else {
+                  access = value?.assetAccesses || [];
+                }
                 setCheckAll(e.target.checked);
                 setIndeterminate(false);
                 const buttons = (value?.buttons || []).map((i: any) => {
@@ -109,6 +129,7 @@ const MenuPermission = (props: Props) => {
                 });
                 props.change({
                   ...value,
+                  assetAccesses: [...access],
                   check: e.target.checked ? 1 : 3, // 1: 全选 2: 只选了部分 3: 一个都没选
                   buttons: [...buttons],
                   children: checkAllData(value.children || [], e.target.checked),
@@ -131,6 +152,26 @@ const MenuPermission = (props: Props) => {
                   'id',
                 )}
                 onChange={(data: CheckboxValueType[]) => {
+                  let access: any[] = [];
+                  if (data.length > 0 && !checkValue) {
+                    setCheckValue('creator');
+                    access = (value?.assetAccesses || []).map((i: any) => {
+                      return {
+                        ...i,
+                        granted: i.supportId === 'creator',
+                      };
+                    });
+                  } else if (data.length === 0) {
+                    setCheckValue('');
+                    access = (value?.assetAccesses || []).map((i: any) => {
+                      return {
+                        ...i,
+                        granted: false,
+                      };
+                    });
+                  } else {
+                    access = value?.assetAccesses || [];
+                  }
                   const buttons = value.buttons.map((i: any) => {
                     return {
                       ...i,
@@ -152,6 +193,7 @@ const MenuPermission = (props: Props) => {
                   const d = {
                     ...value,
                     check,
+                    assetAccesses: [...access],
                     buttons: [...buttons],
                   };
                   props.change(d);
@@ -220,7 +262,7 @@ const MenuPermission = (props: Props) => {
                 <div>{value?.accessDescription}</div>
               ) : (
                 <Radio.Group
-                  defaultValue={value?.assetAccesses[0]?.supportId}
+                  defaultValue={'creator'}
                   value={checkValue}
                   onChange={(e) => {
                     setCheckValue(e.target.value);