Просмотр исходного кода

feat(merge): merge xyh

Next xyh
Lind 3 лет назад
Родитель
Сommit
daabd93187
34 измененных файлов с 495 добавлено и 295 удалено
  1. 1 1
      src/components/Metadata/ArrayParam/index.tsx
  2. 9 2
      src/components/PermissionButton/index.tsx
  3. 2 2
      src/components/ProTableCard/index.tsx
  4. 2 0
      src/hooks/index.ts
  5. 2 2
      src/hooks/permission/index.ts
  6. 30 0
      src/hooks/route/useHistory.tsx
  7. 22 0
      src/hooks/route/useLocation.tsx
  8. 3 2
      src/locales/zh-CN/pages.ts
  9. 1 1
      src/pages/device/Category/Save/index.tsx
  10. 36 29
      src/pages/device/Instance/Detail/Config/index.tsx
  11. 6 3
      src/pages/device/Instance/Detail/Info/index.tsx
  12. 23 10
      src/pages/device/Instance/Detail/index.tsx
  13. 2 4
      src/pages/device/Instance/Save/index.tsx
  14. 12 23
      src/pages/device/Instance/index.tsx
  15. 17 11
      src/pages/device/Product/Detail/Access/index.tsx
  16. 6 3
      src/pages/device/Product/Detail/BaseInfo/index.tsx
  17. 66 67
      src/pages/device/Product/Detail/index.tsx
  18. 18 6
      src/pages/device/Product/index.tsx
  19. 62 51
      src/pages/device/components/Metadata/Base/index.tsx
  20. 13 9
      src/pages/device/components/Metadata/index.tsx
  21. 10 1
      src/pages/link/AccessConfig/Detail/Media/index.tsx
  22. 9 1
      src/pages/link/AccessConfig/Detail/index.tsx
  23. 1 1
      src/pages/link/Certificate/index.tsx
  24. 1 1
      src/pages/link/Gateway/index.tsx
  25. 4 1
      src/pages/media/Device/Channel/index.tsx
  26. 117 50
      src/pages/media/Device/Save/ProviderSelect.tsx
  27. 4 4
      src/pages/media/Device/Save/SaveProduct.tsx
  28. 6 1
      src/pages/media/Device/Save/index.tsx
  29. 1 1
      src/pages/media/Device/index.tsx
  30. 3 3
      src/pages/system/Menu/Detail/buttons.tsx
  31. 2 2
      src/pages/system/Menu/Detail/edit.tsx
  32. 2 1
      src/pages/system/Menu/index.tsx
  33. 1 1
      src/pages/system/Role/index.tsx
  34. 1 1
      src/pages/system/Tenant/index.tsx

+ 1 - 1
src/components/Metadata/ArrayParam/index.tsx

@@ -178,7 +178,7 @@ const ArrayParam = () => {
           },
 
           description: {
-            title: '描述',
+            title: '说明',
             'x-decorator': 'FormItem',
             'x-component': 'Input.TextArea',
           },

+ 9 - 2
src/components/PermissionButton/index.tsx

@@ -8,6 +8,7 @@ interface PermissionButtonProps extends ButtonProps {
   tooltip?: TooltipProps;
   popConfirm?: PopconfirmProps;
   isPermission?: boolean;
+  noButton?: boolean;
 }
 
 /**
@@ -27,7 +28,13 @@ const PermissionButton = (props: PermissionButtonProps) => {
 
   const intl = useIntl();
 
-  const defaultButton = <Button {...buttonProps} disabled={_isPermission} />;
+  const isButton = 'noButton' in props && props.noButton;
+
+  const defaultButton = isButton ? (
+    props.children
+  ) : (
+    <Button {...buttonProps} disabled={_isPermission} />
+  );
 
   const isTooltip = tooltip ? <Tooltip {...tooltip}>{defaultButton}</Tooltip> : null;
 
@@ -38,7 +45,7 @@ const PermissionButton = (props: PermissionButtonProps) => {
         defaultMessage: '没有权限',
       })}
     >
-      {defaultButton}
+      {<Button {...buttonProps} disabled={_isPermission} />}
     </Tooltip>
   );
 

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

@@ -63,9 +63,9 @@ const ProTableCard = <
   };
 
   const windowChange = () => {
-    if (window.innerWidth <= 1366) {
+    if (window.innerWidth <= 1440) {
       setColumn(props.gridColumn && props.gridColumn < 2 ? props.gridColumn : 2);
-    } else if (window.innerWidth > 1366 && window.innerWidth <= 1600) {
+    } else if (window.innerWidth > 1440 && window.innerWidth <= 1600) {
       setColumn(props.gridColumn && props.gridColumn < 3 ? props.gridColumn : 3);
     } else if (window.innerWidth > 1600) {
       setColumn(props.gridColumn && props.gridColumn < 4 ? props.gridColumn : 4);

+ 2 - 0
src/hooks/index.ts

@@ -0,0 +1,2 @@
+export { default as useHistory } from './route/useHistory';
+export { default as useLocation } from './route/useLocation';

+ 2 - 2
src/hooks/permission/index.ts

@@ -3,8 +3,8 @@ import { BUTTON_PERMISSION_ENUM } from '@/utils/menu/router';
 import type { MENUS_CODE_TYPE, BUTTON_PERMISSION } from '@/utils/menu/router';
 import { MENUS_BUTTONS_CACHE } from '@/utils/menu';
 
-type permissionKeyType = keyof typeof BUTTON_PERMISSION_ENUM;
-type permissionType = Record<permissionKeyType, boolean>;
+export type permissionKeyType = keyof typeof BUTTON_PERMISSION_ENUM;
+export type permissionType = Record<permissionKeyType, boolean>;
 
 const usePermissions = (
   code: MENUS_CODE_TYPE,

+ 30 - 0
src/hooks/route/useHistory.tsx

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

+ 22 - 0
src/hooks/route/useLocation.tsx

@@ -0,0 +1,22 @@
+import { useLocation } from 'umi';
+import { useEffect, useState } from 'react';
+import { historyStateModel } from '@/hooks/route/useHistory';
+
+const useLocations = () => {
+  const umiLocation = useLocation();
+  const [location, setLocation] = useState<any>({});
+  useEffect(() => {
+    setLocation({
+      ...umiLocation,
+      state: historyStateModel.state,
+    });
+
+    return () => {
+      historyStateModel.state = undefined;
+    };
+  }, [umiLocation]);
+
+  return location;
+};
+
+export default useLocations;

+ 3 - 2
src/locales/zh-CN/pages.ts

@@ -42,7 +42,7 @@ export default {
   'pages.table.name': '名称',
   'pages.table.deviceName': '设备名称',
   'pages.table.productName': '产品名称',
-  'pages.table.describe': '描述',
+  'pages.table.describe': '说明',
   'pages.table.description': '说明',
   'pages.table.provider': '服务商',
   'pages.table.type': '类型',
@@ -149,6 +149,7 @@ export default {
   'pages.system.menu.buttons': '按钮管理',
   'pages.system.menu.root': '菜单权限',
   'page.system.menu.sort': '排序',
+  'page.system.menu.describe': '说明',
   // 系统设置-第三方平台
   'pages.system.openApi': '第三方平台',
   'pages.system.openApi.username': '用户名',
@@ -223,7 +224,7 @@ export default {
   'pages.device.productDetail.metadata.fileType': '文件类型',
   'pages.device.productDetail.metadata.source': '来源',
   'pages.device.productDetail.metadata.otherConfiguration': '其他配置',
-  'pages.device.productDetail.metadata.describe': '描述',
+  'pages.device.productDetail.metadata.describe': '说明',
   'pages.device.productDetail.metadata.inputParameter': '输入参数',
   'pages.device.productDetail.metadata.outputParameters': '输出参数',
   'pages.device.productDetail.alarm': '告警设置',

+ 1 - 1
src/pages/device/Category/Save/index.tsx

@@ -135,7 +135,7 @@ const Save = (props: Props) => {
         'x-component': 'Input.TextArea',
         'x-component-props': {
           rows: 3,
-          placeholder: '请输入描述',
+          placeholder: '请输入说明',
         },
         name: 'description',
       },

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

@@ -1,4 +1,4 @@
-import { Button, Descriptions, message, Popconfirm, Space, Tooltip } from 'antd';
+import { Descriptions, message, Space, Tooltip } from 'antd';
 import { InstanceModel, service } from '@/pages/device/Instance';
 import { useEffect, useState } from 'react';
 import type { ConfigMetadata } from '@/pages/device/Product/typings';
@@ -10,6 +10,7 @@ import {
   UndoOutlined,
 } from '@ant-design/icons';
 import Edit from './Edit';
+import { PermissionButton } from '@/components';
 
 const Config = () => {
   const params = useParams<{ id: string }>();
@@ -26,6 +27,7 @@ const Config = () => {
 
   const [metadata, setMetadata] = useState<ConfigMetadata[]>([]);
   const [visible, setVisible] = useState<boolean>(false);
+  const { permission } = PermissionButton.usePermission('device/Instance');
 
   const id = InstanceModel.detail?.id || params?.id;
 
@@ -84,7 +86,8 @@ const Config = () => {
       <div style={{ display: 'flex', marginBottom: 20 }}>
         <div style={{ fontSize: 16, fontWeight: 700 }}>配置</div>
         <Space>
-          <Button
+          <PermissionButton
+            isPermission={permission.update}
             type="link"
             onClick={async () => {
               setVisible(true);
@@ -92,48 +95,52 @@ const Config = () => {
           >
             <EditOutlined />
             编辑
-          </Button>
+          </PermissionButton>
           {InstanceModel.detail.state?.value !== 'notActive' && (
-            <Popconfirm
-              title="确认重新应用该配置?"
-              onConfirm={async () => {
-                const resp = await service.deployDevice(id || '');
-                if (resp.status === 200) {
-                  message.success('操作成功');
-                  getDetail();
-                }
+            <PermissionButton
+              popConfirm={{
+                title: '确认重新应用该配置?',
+                onConfirm: async () => {
+                  const resp = await service.deployDevice(id || '');
+                  if (resp.status === 200) {
+                    message.success('操作成功');
+                    getDetail();
+                  }
+                },
               }}
+              isPermission={permission.update}
+              type="link"
             >
-              <Button type="link">
-                <CheckOutlined />
-                应用配置
-              </Button>
+              <CheckOutlined />
+              应用配置
               <Tooltip title="修改配置后需重新应用后才能生效。">
                 <QuestionCircleOutlined />
               </Tooltip>
-            </Popconfirm>
+            </PermissionButton>
           )}
           {InstanceModel.detail?.aloneConfiguration && (
-            <Popconfirm
-              title="确认恢复默认配置?"
-              onConfirm={async () => {
-                const resp = await service.configurationReset(id || '');
-                if (resp.status === 200) {
-                  message.success('恢复默认配置成功');
-                  getDetail();
-                }
+            <PermissionButton
+              popConfirm={{
+                title: '确认恢复默认配置?',
+                onConfirm: async () => {
+                  const resp = await service.configurationReset(id || '');
+                  if (resp.status === 200) {
+                    message.success('恢复默认配置成功');
+                    getDetail();
+                  }
+                },
               }}
+              type="link"
+              isPermission={permission.update}
             >
-              <Button type="link">
-                <UndoOutlined />
-                恢复默认
-              </Button>
+              <UndoOutlined />
+              恢复默认
               <Tooltip
                 title={`该设备单独编辑过配置信息,点击此将恢复成默认的配置信息,请谨慎操作。`}
               >
                 <QuestionCircleOutlined />
               </Tooltip>
-            </Popconfirm>
+            </PermissionButton>
           )}
         </Space>
       </div>

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

@@ -1,4 +1,4 @@
-import { Button, Card, Descriptions } from 'antd';
+import { Card, Descriptions } from 'antd';
 import { InstanceModel } from '@/pages/device/Instance';
 import moment from 'moment';
 import { observer } from '@formily/react';
@@ -9,10 +9,12 @@ import { useState } from 'react';
 import type { DeviceInstance } from '../../typings';
 import { EditOutlined } from '@ant-design/icons';
 import Tags from '@/pages/device/Instance/Detail/Tags';
+import { PermissionButton } from '@/components';
 
 const Info = observer(() => {
   const intl = useIntl();
   const [visible, setVisible] = useState<boolean>(false);
+  const { permission } = PermissionButton.usePermission('device/Instance');
 
   return (
     <>
@@ -23,7 +25,8 @@ const Info = observer(() => {
           bordered
           title={[
             <span key={1}>设备信息</span>,
-            <Button
+            <PermissionButton
+              isPermission={permission.update}
               key={2}
               type={'link'}
               onClick={() => {
@@ -32,7 +35,7 @@ const Info = observer(() => {
             >
               <EditOutlined />
               编辑
-            </Button>,
+            </PermissionButton>,
           ]}
         >
           <Descriptions.Item

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

@@ -1,7 +1,7 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import { InstanceModel, service } from '@/pages/device/Instance';
 import { history, useParams } from 'umi';
-import { Badge, Button, Card, Descriptions, Divider, message, Popconfirm, Tooltip } from 'antd';
+import { Badge, Card, Descriptions, Divider, message } from 'antd';
 import type { ReactNode } from 'react';
 import { useEffect, useState } from 'react';
 import { observer } from '@formily/react';
@@ -19,8 +19,9 @@ import type { DeviceMetadata } from '@/pages/device/Product/typings';
 import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
 import { Store } from 'jetlinks-store';
 import SystemConst from '@/utils/const';
-import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import { getMenuPathByParams, getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
+import { PermissionButton } from '@/components';
 
 export const deviceStatus = new Map();
 deviceStatus.set('online', <Badge status="success" text={'在线'} />);
@@ -31,6 +32,7 @@ const InstanceDetail = observer(() => {
   const intl = useIntl();
   const [tab, setTab] = useState<string>('detail');
   const params = useParams<{ id: string }>();
+  const { permission } = PermissionButton.usePermission('device/Instance');
 
   const resetMetadata = async () => {
     const resp = await service.deleteMetadata(params.id);
@@ -70,11 +72,19 @@ const InstanceDetail = observer(() => {
           <Metadata
             type="device"
             tabAction={
-              <Popconfirm title="确认重置?" onConfirm={resetMetadata}>
-                <Tooltip title="重置后将使用产品的物模型配置">
-                  <Button>重置操作</Button>
-                </Tooltip>
-              </Popconfirm>
+              <PermissionButton
+                isPermission={permission.update}
+                popConfirm={{
+                  title: '确认重置?',
+                  onConfirm: resetMetadata,
+                }}
+                tooltip={{
+                  title: '重置后将使用产品的物模型配置',
+                }}
+                key={'reload'}
+              >
+                重置操作
+              </PermissionButton>
             }
           />
         </Card>
@@ -197,19 +207,22 @@ const InstanceDetail = observer(() => {
         <Descriptions size="small" column={4}>
           <Descriptions.Item label={'ID'}>{InstanceModel.detail?.id}</Descriptions.Item>
           <Descriptions.Item label={'所属产品'}>
-            <Button
+            <PermissionButton
               type={'link'}
               size={'small'}
+              isPermission={!!getMenuPathByCode(MENUS_CODE['device/Product'])}
               onClick={() => {
                 const url = getMenuPathByParams(
                   MENUS_CODE['device/Product/Detail'],
                   InstanceModel.detail?.productId,
                 );
-                history.replace(url);
+                if (url) {
+                  history.replace(url);
+                }
               }}
             >
               {InstanceModel.detail?.productName}
-            </Button>
+            </PermissionButton>
           </Descriptions.Item>
         </Descriptions>
       }

+ 2 - 4
src/pages/device/Instance/Save/index.tsx

@@ -1,9 +1,9 @@
-import { Col, Form, Input, message, Row, Select } from 'antd';
+import { Col, Form, Input, message, Row, Select, Modal } from 'antd';
 import { service } from '@/pages/device/Instance';
 import type { DeviceInstance } from '../typings';
 import { useEffect, useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import { Modal, UploadImage } from '@/components';
+import { UploadImage } from '@/components';
 import { debounce } from 'lodash';
 
 interface Props {
@@ -119,8 +119,6 @@ const Save = (props: Props) => {
       })}
       confirmLoading={loading}
       onOk={handleSave}
-      permissionCode={'device/Instance'}
-      permission={'add'}
     >
       <Form
         form={form}

+ 12 - 23
src/pages/device/Instance/index.tsx

@@ -19,7 +19,7 @@ import {
 import { model } from '@formily/reactive';
 import Service from '@/pages/device/Instance/service';
 import type { MetadataItem } from '@/pages/device/Product/typings';
-import { useIntl, connect } from 'umi';
+import { useIntl } from 'umi';
 import Save from './Save';
 import Export from './Export';
 import Import from './Import';
@@ -30,6 +30,7 @@ import SystemConst from '@/utils/const';
 import Token from '@/utils/token';
 import DeviceCard from '@/components/ProTableCard/CardItems/device';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import { useLocation } from '@/hooks';
 
 export const statusMap = new Map();
 statusMap.set('在线', 'success');
@@ -54,7 +55,7 @@ export const InstanceModel = model<{
   params: new Set<string>(['test']),
 });
 export const service = new Service('device-instance');
-const Instance = (props: any) => {
+const Instance = () => {
   const actionRef = useRef<ActionType>();
   const [visible, setVisible] = useState<boolean>(false);
   const [exportVisible, setExportVisible] = useState<boolean>(false);
@@ -68,23 +69,22 @@ const Instance = (props: any) => {
   const history = useHistory<Record<string, string>>();
   const { permission } = PermissionButton.usePermission('device/Instance');
   const intl = useIntl();
+  const location = useLocation();
 
   useEffect(() => {
-    console.log(searchParams);
-    if (props.path) {
+    if (location.state) {
       const _terms: any[] = [];
-      Object.keys(props.locationState).forEach((key) => {
+      Object.keys(location.state).forEach((key) => {
         _terms.push({
           column: key,
-          value: props.locationState[key],
+          value: location.state[key],
         });
       });
       setSearchParams({
         terms: _terms,
       });
-      props.cleanLocationState();
     }
-  }, [props.path]);
+  }, [location]);
 
   const tools = (record: DeviceInstance) => [
     <Button
@@ -279,7 +279,7 @@ const Instance = (props: any) => {
     <Menu>
       <Menu.Item key="1">
         <PermissionButton
-          isPermission={permission.delete}
+          isPermission={permission.export}
           icon={<ExportOutlined />}
           type="default"
           onClick={() => {
@@ -302,7 +302,7 @@ const Instance = (props: any) => {
       </Menu.Item>
       <Menu.Item key="4">
         <PermissionButton
-          isPermission={permission.active}
+          isPermission={permission.action}
           icon={<CheckCircleOutlined />}
           type="primary"
           ghost
@@ -323,7 +323,7 @@ const Instance = (props: any) => {
       </Menu.Item>
       <Menu.Item key="5">
         <PermissionButton
-          isPermission={permission.sync}
+          isPermission={true}
           icon={<SyncOutlined />}
           type="primary"
           onClick={() => {
@@ -590,15 +590,4 @@ const Instance = (props: any) => {
   );
 };
 
-const mapState = (state: any) => {
-  return {
-    locationState: state.location.locationState,
-    path: state.location.path,
-  };
-};
-
-const actionCreate = {
-  cleanLocationState: (payload: any) => ({ type: 'location/clean', payload }),
-};
-
-export default connect(mapState, actionCreate)(Instance);
+export default Instance;

+ 17 - 11
src/pages/device/Product/Detail/Access/index.tsx

@@ -13,6 +13,7 @@ import { createSchemaField } from '@formily/react';
 import { createForm } from '@formily/core';
 import { QuestionCircleOutlined } from '@ant-design/icons';
 import TitleComponent from '@/components/TitleComponent';
+import usePermissions from '@/hooks/permission';
 
 const componentMap = {
   string: 'Input',
@@ -25,6 +26,7 @@ const Access = () => {
   const [access, setAccess] = useState<any>();
   const [providers, setProviders] = useState<any[]>([]);
   const [networkList, setNetworkList] = useState<any[]>([]);
+  const { permission } = usePermissions('device/Product');
 
   const MetworkTypeMapping = new Map();
   MetworkTypeMapping.set('websocket-server', 'WEB_SOCKET_SERVER');
@@ -345,17 +347,21 @@ const Access = () => {
         <div style={{ padding: '100px 0' }}>
           <Empty
             description={
-              <span>
-                请先
-                <a
-                  onClick={() => {
-                    setConfigVisible(true);
-                  }}
-                >
-                  选择
-                </a>
-                设备接入网关,用以提供设备接入能力
-              </span>
+              permission.add ? (
+                <span>
+                  请先
+                  <a
+                    onClick={() => {
+                      setConfigVisible(true);
+                    }}
+                  >
+                    选择
+                  </a>
+                  设备接入网关,用以提供设备接入能力
+                </span>
+              ) : (
+                '暂无权限,请联系管理员'
+              )
             }
           />
         </div>

+ 6 - 3
src/pages/device/Product/Detail/BaseInfo/index.tsx

@@ -1,10 +1,11 @@
 import { productModel, service } from '@/pages/device/Product';
-import { Button, Descriptions } from 'antd';
+import { Descriptions } from 'antd';
 import { useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { EditOutlined } from '@ant-design/icons';
 import { getDateFormat } from '@/utils/util';
 import Save from '@/pages/device/Product/Save';
+import { PermissionButton } from '@/components';
 
 // const componentMap = {
 //   string: 'Input',
@@ -16,6 +17,7 @@ const BaseInfo = () => {
   // const [metadata, setMetadata] = useState<ConfigMetadata[]>([]);
   // const [state, setState] = useState<boolean>(false);
   const [visible, setVisible] = useState(false);
+  const { permission } = PermissionButton.usePermission('device/Product');
 
   // const form = createForm({
   //   validateFirst: true,
@@ -152,7 +154,8 @@ const BaseInfo = () => {
         column={3}
         title={[
           <span key={1}>产品信息</span>,
-          <Button
+          <PermissionButton
+            isPermission={permission.update}
             key={2}
             type={'link'}
             onClick={() => {
@@ -160,7 +163,7 @@ const BaseInfo = () => {
             }}
           >
             <EditOutlined />
-          </Button>,
+          </PermissionButton>,
         ]}
         bordered
       >

+ 66 - 67
src/pages/device/Product/Detail/index.tsx

@@ -1,22 +1,11 @@
 import { PageContainer } from '@ant-design/pro-layout';
-import { history, useLocation, useParams } from 'umi';
-import {
-  Badge,
-  Button,
-  Card,
-  Descriptions,
-  message,
-  Popconfirm,
-  Space,
-  Spin,
-  Switch,
-  Tooltip,
-} from 'antd';
+import { useIntl, useLocation, useParams } from 'umi';
+import { Badge, Card, Descriptions, message, Popconfirm, Space, Spin, Switch, Tooltip } from 'antd';
 import BaseInfo from '@/pages/device/Product/Detail/BaseInfo';
 import { observer } from '@formily/react';
 import { productModel, service } from '@/pages/device/Product';
 import { useCallback, useEffect, useState } from 'react';
-import { useIntl, connect } from 'umi';
+import { useHistory } from '@/hooks';
 import Metadata from '@/pages/device/components/Metadata';
 import Access from '@/pages/device/Product/Detail/Access';
 import type { DeviceMetadata } from '@/pages/device/Product/typings';
@@ -26,6 +15,7 @@ import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
 import encodeQuery from '@/utils/encodeQuery';
 import MetadataMap from '@/pages/device/Instance/Detail/MetadataMap';
 import SystemConst from '@/utils/const';
+import { PermissionButton } from '@/components';
 
 export const ModelEnum = {
   base: 'base',
@@ -33,12 +23,15 @@ export const ModelEnum = {
   access: 'access',
 };
 
-const ProductDetail = observer((props: any) => {
+const ProductDetail = observer(() => {
   const intl = useIntl();
   const [mode, setMode] = useState('base');
   const param = useParams<{ id: string }>();
   const [loading, setLoading] = useState<boolean>(false);
   const location = useLocation();
+  const history = useHistory();
+
+  const { permission } = PermissionButton.usePermission('device/Product');
 
   const statusMap = {
     1: {
@@ -194,7 +187,9 @@ const ProductDetail = observer((props: any) => {
       onBack={() => history.goBack()}
       extraContent={<Space size={24} />}
       onTabChange={(key) => {
-        setMode(key);
+        if (permission.update) {
+          setMode(key);
+        }
       }}
       tabList={list}
       tabActiveKey={mode}
@@ -202,63 +197,78 @@ const ProductDetail = observer((props: any) => {
         <Spin spinning={loading}>
           <Descriptions size="small" column={2}>
             <Descriptions.Item label={'设备数量'}>
-              <Button
+              <PermissionButton
                 type={'link'}
+                isPermission={!!getMenuPathByCode(MENUS_CODE['device/Instance'])}
                 style={{ padding: 0, height: 'auto' }}
                 onClick={() => {
                   const url = getMenuPathByCode(MENUS_CODE['device/Instance']);
                   const params = {
                     productId: productModel.current?.id,
                   };
-                  props.push({
-                    locationState: params,
-                    path: url,
-                  });
-                  history.push(url, params);
+                  if (url) {
+                    history.push(url, params);
+                  }
                 }}
               >
                 {productModel.current?.count || 0}
-              </Button>
+              </PermissionButton>
             </Descriptions.Item>
           </Descriptions>
         </Spin>
       }
       title={productModel.current?.name}
       subTitle={
-        <Popconfirm
-          title={productModel.current?.state === 1 ? '确认取消发布' : '确认发布'}
-          onConfirm={() => {
-            changeDeploy(statusMap[productModel.current?.state || 0].action);
-          }}
-        >
-          <Switch
-            key={2}
-            checked={productModel.current?.state === 1}
-            checkedChildren="已发布"
-            unCheckedChildren="未发布"
-          />
-        </Popconfirm>
+        permission.update ? (
+          <Popconfirm
+            title={productModel.current?.state === 1 ? '确认取消发布' : '确认发布'}
+            onConfirm={() => {
+              changeDeploy(statusMap[productModel.current?.state || 0].action);
+            }}
+          >
+            <Switch
+              key={2}
+              checked={productModel.current?.state === 1}
+              checkedChildren="已发布"
+              unCheckedChildren="未发布"
+            />
+          </Popconfirm>
+        ) : (
+          <Tooltip
+            title={intl.formatMessage({
+              id: 'pages.data.option.noPermission',
+              defaultMessage: '没有权限',
+            })}
+          >
+            <Switch
+              key={2}
+              disabled
+              checked={productModel.current?.state === 1}
+              checkedChildren="已发布"
+              unCheckedChildren="未发布"
+            />
+          </Tooltip>
+        )
       }
       extra={[
-        <Popconfirm title={'确定应用配置?'} key="1" onConfirm={() => changeDeploy('deploy')}>
-          {productModel.current?.state === 0 ? (
-            <Tooltip title={'请先发布产品'}>
-              <Button disabled type="primary">
-                {intl.formatMessage({
-                  id: 'pages.device.productDetail.setting',
-                  defaultMessage: '应用配置',
-                })}
-              </Button>
-            </Tooltip>
-          ) : (
-            <Button key="1" type="primary">
-              {intl.formatMessage({
-                id: 'pages.device.productDetail.setting',
-                defaultMessage: '应用配置',
-              })}
-            </Button>
-          )}
-        </Popconfirm>,
+        <PermissionButton
+          key="1"
+          type={'primary'}
+          popConfirm={{
+            title: '确定应用配置?',
+            onConfirm: () => {
+              changeDeploy('deploy');
+            },
+          }}
+          tooltip={productModel.current?.state === 0 ? { title: '请先发布产品' } : undefined}
+          isPermission={permission.update}
+          disabled={productModel.current?.state === 0}
+        >
+          {intl.formatMessage({
+            id: 'pages.device.productDetail.setting',
+            defaultMessage: '应用配置',
+          })}
+        </PermissionButton>,
       ]}
     >
       <Card>
@@ -332,15 +342,4 @@ const ProductDetail = observer((props: any) => {
   );
 });
 
-const mapState = (state: any) => ({
-  state: state.state,
-  path: state.path,
-});
-
-const actionCreate = {
-  push: (payload: any) => {
-    return { type: 'location/push', payload };
-  },
-};
-
-export default connect(mapState, actionCreate)(ProductDetail);
+export default ProductDetail;

+ 18 - 6
src/pages/device/Product/index.tsx

@@ -192,9 +192,10 @@ const Product = observer(() => {
       type={'link'}
       style={{ padding: 0 }}
       isPermission={permission.delete}
+      disabled={record.state === 1}
       popConfirm={{
         title: intl.formatMessage({
-          id: record.state === 1 ? 'pages.device.productDetail.deleteTip' : 'page.table.isDelete',
+          id: 'page.table.isDelete',
           defaultMessage: '是否删除?',
         }),
         onConfirm: async () => {
@@ -207,7 +208,10 @@ const Product = observer(() => {
       }}
       tooltip={{
         title: intl.formatMessage({
-          id: 'pages.data.option.remove',
+          id:
+            record.state === 1
+              ? 'pages.device.productDetail.deleteTip'
+              : 'pages.data.option.remove',
           defaultMessage: '删除',
         }),
       }}
@@ -477,12 +481,20 @@ const Product = observer(() => {
                 type={'link'}
                 style={{ padding: 0 }}
                 isPermission={permission.delete}
+                disabled={record.state === 1}
+                tooltip={
+                  record.state === 1
+                    ? {
+                        title: intl.formatMessage({
+                          id: 'pages.device.productDetail.deleteTip',
+                          defaultMessage: '已发布的产品不能进行删除操作',
+                        }),
+                      }
+                    : undefined
+                }
                 popConfirm={{
                   title: intl.formatMessage({
-                    id:
-                      record.state === 1
-                        ? 'pages.device.productDetail.deleteTip'
-                        : 'page.table.isDelete',
+                    id: 'page.table.isDelete',
                     defaultMessage: '是否删除?',
                   }),
                   onConfirm: async () => {

+ 62 - 51
src/pages/device/components/Metadata/Base/index.tsx

@@ -5,7 +5,7 @@ import { useParams } from 'umi';
 import DB from '@/db';
 import type { MetadataItem, MetadataType } from '@/pages/device/Product/typings';
 import MetadataMapping from './columns';
-import { Button, message, Popconfirm, Tooltip } from 'antd';
+import { message } from 'antd';
 import { DeleteOutlined, EditOutlined, ImportOutlined, PlusOutlined } from '@ant-design/icons';
 import Edit from './Edit';
 import { observer } from '@formily/react';
@@ -17,10 +17,13 @@ import PropertyImport from '@/pages/device/Product/Detail/PropertyImport';
 import { productModel } from '@/pages/device/Product';
 import { InstanceModel } from '@/pages/device/Instance';
 import { asyncUpdateMedata, removeMetadata } from '../metadata';
+import type { permissionType } from '@/hooks/permission';
+import { PermissionButton } from '@/components';
 
 interface Props {
   type: MetadataType;
   target: 'product' | 'device';
+  permission: Partial<permissionType>;
 }
 
 const BaseMetadata = observer((props: Props) => {
@@ -73,36 +76,41 @@ const BaseMetadata = observer((props: Props) => {
       align: 'center',
       width: 200,
       render: (_: unknown, record: MetadataItem) => [
-        <Tooltip key={'edit'} title={operateLimits('add', type) ? '暂不支持' : '编辑'}>
-          <Button
-            key="editable"
-            type="link"
-            disabled={operateLimits('updata', type)}
-            onClick={() => {
-              MetadataModel.edit = true;
-              MetadataModel.item = record;
-              MetadataModel.type = type;
-              MetadataModel.action = 'edit';
-            }}
-          >
-            <Tooltip title="编辑">
-              <EditOutlined />
-            </Tooltip>
-          </Button>
-        </Tooltip>,
-        ,
-        <a key="delete">
-          <Popconfirm
-            title="确认删除?"
-            onConfirm={async () => {
+        <PermissionButton
+          isPermission={props.permission.update}
+          type="link"
+          key={'edit'}
+          style={{ padding: 0 }}
+          disabled={operateLimits('updata', type)}
+          onClick={() => {
+            MetadataModel.edit = true;
+            MetadataModel.item = record;
+            MetadataModel.type = type;
+            MetadataModel.action = 'edit';
+          }}
+          tooltip={{
+            title: operateLimits('add', type) ? '暂不支持' : '编辑',
+          }}
+        >
+          <EditOutlined />
+        </PermissionButton>,
+        <PermissionButton
+          isPermission={props.permission.update}
+          type="link"
+          key={'delete'}
+          style={{ padding: 0 }}
+          popConfirm={{
+            title: '确认删除?',
+            onConfirm: async () => {
               await removeItem(record);
-            }}
-          >
-            <Tooltip title="删除">
-              <DeleteOutlined />
-            </Tooltip>
-          </Popconfirm>
-        </a>,
+            },
+          }}
+          tooltip={{
+            title: '删除',
+          }}
+        >
+          <DeleteOutlined />
+        </PermissionButton>,
       ],
     },
   ];
@@ -165,7 +173,8 @@ const BaseMetadata = observer((props: Props) => {
         }}
         toolBarRender={() => [
           props.type === 'properties' && (
-            <Button
+            <PermissionButton
+              isPermission={props.permission.update}
               onClick={() => {
                 MetadataModel.importMetadata = true;
               }}
@@ -174,27 +183,29 @@ const BaseMetadata = observer((props: Props) => {
               type="ghost"
             >
               导入属性
-            </Button>
+            </PermissionButton>
           ),
-          <Tooltip key={'add'} title={operateLimits('add', type) ? '暂不支持' : '新增'}>
-            <Button
-              onClick={() => {
-                MetadataModel.edit = true;
-                MetadataModel.item = undefined;
-                MetadataModel.type = type;
-                MetadataModel.action = 'add';
-              }}
-              disabled={operateLimits('add', type)}
-              key="button"
-              icon={<PlusOutlined />}
-              type="primary"
-            >
-              {intl.formatMessage({
-                id: 'pages.searchTable.new',
-                defaultMessage: '新建',
-              })}
-            </Button>
-          </Tooltip>,
+          <PermissionButton
+            isPermission={props.permission.update}
+            key={'add'}
+            onClick={() => {
+              MetadataModel.edit = true;
+              MetadataModel.item = undefined;
+              MetadataModel.type = type;
+              MetadataModel.action = 'add';
+            }}
+            disabled={operateLimits('add', type)}
+            icon={<PlusOutlined />}
+            type="primary"
+            tooltip={{
+              title: operateLimits('add', type) ? '暂不支持' : '新增',
+            }}
+          >
+            {intl.formatMessage({
+              id: 'pages.searchTable.new',
+              defaultMessage: '新建',
+            })}
+          </PermissionButton>,
         ]}
       />
       {MetadataModel.importMetadata && <PropertyImport type={target} />}

+ 13 - 9
src/pages/device/components/Metadata/index.tsx

@@ -1,5 +1,5 @@
 import { observer } from '@formily/react';
-import { Button, Space, Tabs } from 'antd';
+import { Space, Tabs } from 'antd';
 import BaseMetadata from './Base';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import Import from './Import';
@@ -10,6 +10,7 @@ import Service from '@/pages/device/components/Metadata/service';
 import { InfoCircleOutlined } from '@ant-design/icons';
 import styles from './index.less';
 import { InstanceModel } from '@/pages/device/Instance';
+import { PermissionButton } from '@/components';
 
 interface Props {
   tabAction?: ReactNode;
@@ -22,6 +23,9 @@ const Metadata = observer((props: Props) => {
   const intl = useIntl();
   const [visible, setVisible] = useState<boolean>(false);
   const [cat, setCat] = useState<boolean>(false);
+  const { permission } = PermissionButton.usePermission(
+    props.type === 'device' ? 'device/Instance' : 'device/Product',
+  );
   console.log(InstanceModel.detail, 'test');
   return (
     <div style={{ position: 'relative' }}>
@@ -36,19 +40,19 @@ const Metadata = observer((props: Props) => {
         tabBarExtraContent={
           <Space>
             {props?.tabAction}
-            <Button onClick={() => setVisible(true)}>
+            <PermissionButton isPermission={permission.update} onClick={() => setVisible(true)}>
               {intl.formatMessage({
                 id: 'pages.device.productDetail.metadata.quickImport',
                 defaultMessage: '快速导入',
               })}
-            </Button>
-            <Button onClick={() => setCat(true)}>
+            </PermissionButton>
+            <PermissionButton isPermission={permission.update} onClick={() => setCat(true)}>
               {intl.formatMessage({
                 id: 'pages.device.productDetail.metadata',
                 defaultMessage: '物模型',
               })}
               TSL
-            </Button>
+            </PermissionButton>
           </Space>
         }
         destroyInactiveTabPane
@@ -60,7 +64,7 @@ const Metadata = observer((props: Props) => {
           })}
           key="properties"
         >
-          <BaseMetadata target={props.type} type={'properties'} />
+          <BaseMetadata target={props.type} type={'properties'} permission={permission} />
         </Tabs.TabPane>
         <Tabs.TabPane
           tab={intl.formatMessage({
@@ -69,7 +73,7 @@ const Metadata = observer((props: Props) => {
           })}
           key="functions"
         >
-          <BaseMetadata target={props.type} type={'functions'} />
+          <BaseMetadata target={props.type} type={'functions'} permission={permission} />
         </Tabs.TabPane>
         <Tabs.TabPane
           tab={intl.formatMessage({
@@ -78,7 +82,7 @@ const Metadata = observer((props: Props) => {
           })}
           key="events"
         >
-          <BaseMetadata target={props.type} type={'events'} />
+          <BaseMetadata target={props.type} type={'events'} permission={permission} />
         </Tabs.TabPane>
         <Tabs.TabPane
           tab={intl.formatMessage({
@@ -87,7 +91,7 @@ const Metadata = observer((props: Props) => {
           })}
           key="tags"
         >
-          <BaseMetadata target={props.type} type={'tags'} />
+          <BaseMetadata target={props.type} type={'tags'} permission={permission} />
         </Tabs.TabPane>
       </Tabs>
       <Import visible={visible} close={() => setVisible(false)} />

+ 10 - 1
src/pages/link/AccessConfig/Detail/Media/index.tsx

@@ -473,7 +473,16 @@ const Media = (props: Props) => {
                   }
                   if (resp.status === 200) {
                     message.success('操作成功!');
-                    history.back();
+                    if (params.get('save')) {
+                      if ((window as any).onTabSaveSuccess) {
+                        if (resp.result) {
+                          (window as any).onTabSaveSuccess(resp.result);
+                          setTimeout(() => window.close(), 300);
+                        }
+                      }
+                    } else {
+                      history.back();
+                    }
                   }
                 }}
               >

+ 9 - 1
src/pages/link/AccessConfig/Detail/index.tsx

@@ -23,7 +23,10 @@ const Detail = () => {
 
   useEffect(() => {
     setLoading(true);
-    const id = new URLSearchParams(location.search).get('id') || undefined;
+    const _params = new URLSearchParams(location.search);
+    const id = _params.get('id') || undefined;
+    const paramsType = _params.get('type');
+
     service.getProviders().then((resp) => {
       if (resp.status === 200) {
         setDataSource(resp.result);
@@ -42,6 +45,11 @@ const Detail = () => {
               setType('network');
             }
           });
+        } else if (paramsType) {
+          setType('media');
+          setProvider(resp.result.find((item: any) => item.id === paramsType));
+          setData({});
+          setVisible(false);
         } else {
           setVisible(true);
         }

+ 1 - 1
src/pages/link/Certificate/index.tsx

@@ -175,7 +175,7 @@ const Certificate = () => {
         },
       },
       description: {
-        title: '描述',
+        title: '说明',
         'x-component': 'Input.TextArea',
         'x-decorator': 'FormItem',
       },

+ 1 - 1
src/pages/link/Gateway/index.tsx

@@ -347,7 +347,7 @@ const Gateway = () => {
         'x-decorator': 'FormItem',
       },
       describe: {
-        title: '描述',
+        title: '说明',
         'x-component': 'Input.TextArea',
         'x-decorator': 'FormItem',
         'x-component-props': {

+ 4 - 1
src/pages/media/Device/Channel/index.tsx

@@ -239,7 +239,10 @@ export default () => {
             search={false}
             headerTitle={[
               type === ProviderValue.GB281 ? (
-                <Tooltip key="button" title={'接入方式为GB/T28281时,不支持新增'}>
+                <Tooltip
+                  key="button"
+                  title={<div style={{ width: 265 }}>接入方式为GB/T28281时,不支持新增</div>}
+                >
                   <Button disabled>
                     {intl.formatMessage({
                       id: 'pages.data.option.add',

+ 117 - 50
src/pages/media/Device/Save/ProviderSelect.tsx

@@ -1,13 +1,20 @@
 import classNames from 'classnames';
-import { Badge } from 'antd';
+import { Badge, Button, Empty } from 'antd';
 import { StatusColorEnum } from '@/components/BadgeStatus';
 import styles from '@/pages/link/AccessConfig/index.less';
 import { TableCard } from '@/components';
 import './providerSelect.less';
+import usePermissions from '@/hooks/permission';
+import { useIntl } from 'umi';
+import { providerType, service } from '@/pages/media/Device';
+import { useCallback, useEffect, useRef, useState } from 'react';
+import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
+import { useRequest } from '@@/plugin-request/request';
 
 interface ProviderProps {
   value?: string;
   options?: any[];
+  type: string;
   onChange?: (id: string) => void;
   onSelect?: (id: string, rowData: any) => void;
 }
@@ -15,64 +22,124 @@ interface ProviderProps {
 const defaultImage = require('/public/images/device-access.png');
 
 export default (props: ProviderProps) => {
+  const { permission } = usePermissions('link/AccessConfig');
+  const [options, setOptions] = useState<any[]>([]);
+  const addItemKey = useRef('');
+  const intl = useIntl();
+
+  const itemClick = useCallback(
+    (item: any) => {
+      if (props.onChange) {
+        props.onChange(item.id);
+      }
+
+      if (props.onSelect) {
+        props.onSelect(item.id, item);
+      }
+    },
+    [props],
+  );
+
+  const { run: getProviderList } = useRequest(service.queryProvider, {
+    manual: true,
+    formatResult: (res) => res.result,
+    onSuccess: (resp) => {
+      if (resp.data && resp.data.length) {
+        setOptions(resp.data);
+        if (addItemKey.current) {
+          const _item = resp.data.find((item: any) => item.id === addItemKey.current);
+          itemClick(_item);
+          addItemKey.current = '';
+        }
+      }
+    },
+  });
+
+  const jumpPage = useCallback(() => {
+    const url = getMenuPathByCode(MENUS_CODE['link/AccessConfig/Detail']);
+    const tab: any = window.open(`${origin}/#${url}?save=true&type=${props.type}`);
+    tab!.onTabSaveSuccess = (value: any) => {
+      addItemKey.current = value.id;
+      getProviderList({
+        sorts: [{ name: 'createTime', value: 'asc' }],
+        terms: [{ column: 'provider', value: props.type }],
+        pageSize: 100,
+      });
+    };
+  }, [props.type]);
+
+  useEffect(() => {
+    setOptions(props.options || []);
+  }, [props.options]);
+
+  const emptyDescription = permission.add ? (
+    <>
+      暂无数据,请先
+      <Button type={'link'} onClick={jumpPage} style={{ padding: 0 }}>
+        添加{providerType[props.type]} 接入网关
+      </Button>
+    </>
+  ) : (
+    intl.formatMessage({
+      id: 'pages.data.option.noPermission',
+      defaultMessage: '没有权限',
+    })
+  );
+
   return (
     <div className={'provider-list'}>
-      {props.options && props.options.length
-        ? props.options.map((item) => (
-            <div
-              onClick={() => {
-                if (props.onChange) {
-                  props.onChange(item.id);
-                }
-
-                if (props.onSelect) {
-                  props.onSelect(item.id, item);
-                }
+      {options && options.length ? (
+        options.map((item) => (
+          <div
+            onClick={() => {
+              itemClick(item);
+            }}
+            style={{ padding: 16 }}
+          >
+            <TableCard
+              className={classNames({ active: item.id === props.value })}
+              showMask={false}
+              showTool={false}
+              status={item.state.value}
+              statusText={item.state.text}
+              statusNames={{
+                enabled: StatusColorEnum.processing,
+                disabled: StatusColorEnum.error,
               }}
-              style={{ padding: 16 }}
             >
-              <TableCard
-                className={classNames({ active: item.id === props.value })}
-                showMask={false}
-                showTool={false}
-                status={item.state.value}
-                statusText={item.state.text}
-                statusNames={{
-                  enabled: StatusColorEnum.processing,
-                  disabled: StatusColorEnum.error,
-                }}
-              >
-                <div className={styles.context}>
-                  <div>
-                    <img width={88} height={88} src={defaultImage} alt={''} />
+              <div className={styles.context}>
+                <div>
+                  <img width={88} height={88} src={defaultImage} alt={''} />
+                </div>
+                <div className={styles.card}>
+                  <div className={styles.header}>
+                    <div className={styles.title}>{item.name || '--'}</div>
+                    <div className={styles.desc}>{item.description || '--'}</div>
                   </div>
-                  <div className={styles.card}>
-                    <div className={styles.header}>
-                      <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 style={{ width: '100%' }}>
-                          {item.channelInfo?.addresses.map((i: any, index: number) => (
-                            <p key={i.address + `_address${index}`}>
-                              <Badge color={i.health === -1 ? 'red' : 'green'} text={i.address} />
-                            </p>
-                          ))}
-                        </div>
-                      </div>
-                      <div className={styles.procotol}>
-                        <div className={styles.subTitle}>{item?.protocolDetail?.name || '--'}</div>
-                        <p>{item.protocolDetail?.description || '--'}</p>
+                  <div className={styles.container}>
+                    <div className={styles.server}>
+                      <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}`}>
+                            <Badge color={i.health === -1 ? 'red' : 'green'} text={i.address} />
+                          </p>
+                        ))}
                       </div>
                     </div>
+                    <div className={styles.procotol}>
+                      <div className={styles.subTitle}>{item?.protocolDetail?.name || '--'}</div>
+                      <p>{item.protocolDetail?.description || '--'}</p>
+                    </div>
                   </div>
                 </div>
-              </TableCard>
-            </div>
-          ))
-        : null}
+              </div>
+            </TableCard>
+          </div>
+        ))
+      ) : (
+        <Empty description={<span>{emptyDescription}</span>} />
+      )}
     </div>
   );
 };

+ 4 - 4
src/pages/media/Device/Save/SaveProduct.tsx

@@ -24,10 +24,9 @@ export default (props: SaveProps) => {
   useEffect(() => {
     if (visible) {
       getProviderList({
-        terms: [
-          { column: 'provider', value: props.type },
-          { column: 'state', value: 'enabled' },
-        ],
+        sorts: [{ name: 'createTime', value: 'desc' }],
+        terms: [{ column: 'provider', value: props.type }],
+        pageSize: 100,
       });
     }
   }, [visible]);
@@ -107,6 +106,7 @@ export default (props: SaveProps) => {
         >
           <ProviderItem
             options={providerList}
+            type={props.type}
             onSelect={(_, rowData) => {
               form.setFieldsValue({
                 accessName: rowData.name,

+ 6 - 1
src/pages/media/Device/Save/index.tsx

@@ -326,7 +326,12 @@ export default (props: SaveProps) => {
             <Col span={24}>
               <Form.Item label={'说明'} name={'description'}>
                 <Input.TextArea
-                  placeholder={intlFormat('pages.form.tip.input', '请输入')}
+                  placeholder={intlFormat(
+                    'pages.form.tip.input.props',
+                    '请输入',
+                    'pages.table.describe',
+                    '说明',
+                  )}
                   rows={4}
                   style={{ width: '100%' }}
                   maxLength={200}

+ 1 - 1
src/pages/media/Device/index.tsx

@@ -28,7 +28,7 @@ import Save from './Save';
 
 export const service = new Service('media/device');
 
-const providerType = {
+export const providerType = {
   'gb28181-2016': 'GB/T28181',
   'fixed-media': '固定地址',
 };

+ 3 - 3
src/pages/system/Menu/Detail/buttons.tsx

@@ -153,7 +153,7 @@ export default (props: ButtonsProps) => {
     {
       title: intl.formatMessage({
         id: 'page.system.menu.describe',
-        defaultMessage: '备注说明',
+        defaultMessage: '说明',
       }),
       dataIndex: 'description',
       // render: (_, row) => () => {
@@ -348,10 +348,10 @@ export default (props: ButtonsProps) => {
             name="description"
             label={intl.formatMessage({
               id: 'pages.table.describe',
-              defaultMessage: '描述',
+              defaultMessage: '说明',
             })}
           >
-            <Input.TextArea disabled={disabled} placeholder={'请输入描述'} />
+            <Input.TextArea disabled={disabled} placeholder={'请输入说明'} />
           </Form.Item>
         </Form>
       </Modal>

+ 2 - 2
src/pages/system/Menu/Detail/edit.tsx

@@ -36,7 +36,7 @@ export default (props: EditProps) => {
   const [show] = useState(true);
   const [accessSupport, setAccessSupport] = useState('unsupported');
   const history = useHistory();
-  const { permission } = PermissionButton.usePermission('system/Menu');
+  const { getOtherPermission } = PermissionButton.usePermission('system/Menu');
 
   const [form] = Form.useForm();
 
@@ -328,7 +328,7 @@ export default (props: EditProps) => {
                 saveData();
               }
             }}
-            isPermission={disabled ? permission.update : permission.add}
+            isPermission={getOtherPermission(['add', 'update'])}
           >
             {intl.formatMessage({
               id: `pages.data.option.${disabled ? 'edit' : 'save'}`,

+ 2 - 1
src/pages/system/Menu/index.tsx

@@ -107,7 +107,7 @@ export default observer(() => {
     {
       title: intl.formatMessage({
         id: 'page.system.menu.describe',
-        defaultMessage: '备注说明',
+        defaultMessage: '说明',
       }),
       width: 200,
       dataIndex: 'describe',
@@ -175,6 +175,7 @@ export default observer(() => {
           key="delete"
           type="link"
           style={{ padding: 0 }}
+          isPermission={permission.delete}
           popConfirm={{
             title: intl.formatMessage({
               id: 'page.system.menu.table.delete',

+ 1 - 1
src/pages/system/Role/index.tsx

@@ -175,7 +175,7 @@ const Role: React.FC = observer(() => {
         'x-component': 'Input.TextArea',
         'x-component-props': {
           checkStrength: true,
-          placeholder: '请输入描述',
+          placeholder: '请输入说明',
         },
         'x-decorator-props': {},
         name: 'password',

+ 1 - 1
src/pages/system/Tenant/index.tsx

@@ -215,7 +215,7 @@ const Tenant = observer(() => {
       },
       description: {
         type: 'string',
-        title: '备注',
+        title: '说明',
         required: true,
         'x-decorator': 'FormItem',
         'x-component': 'Input.TextArea',