ソースを参照

fix: 新增按钮权限

sun-chaochao 3 年 前
コミット
4e66fe4dc5
30 ファイル変更367 行追加348 行削除
  1. 1 1
      src/components/AIcon/index.tsx
  2. 3 3
      src/components/FBraftEditor/index.tsx
  3. 4 4
      src/components/ProTableCard/CardItems/AccessConfig/index.tsx
  4. 4 4
      src/components/ProTableCard/CardItems/cascade.tsx
  5. 5 5
      src/components/Upload/Image/index.tsx
  6. 8 8
      src/pages/device/Category/Save/index.tsx
  7. 60 59
      src/pages/device/Category/index.tsx
  8. 11 6
      src/pages/device/Instance/Detail/Config/index.tsx
  9. 6 5
      src/pages/device/Instance/Detail/Diagnose/Status/index.tsx
  10. 7 7
      src/pages/device/Instance/Detail/Log/index.tsx
  11. 20 16
      src/pages/device/Instance/Detail/MetadataMap/index.tsx
  12. 0 1
      src/pages/device/Instance/Detail/Running/Event/index.tsx
  13. 5 5
      src/pages/device/Instance/Detail/Tags/index.tsx
  14. 11 11
      src/pages/device/Instance/Detail/index.tsx
  15. 7 7
      src/pages/device/Instance/Save/index.tsx
  16. 5 5
      src/pages/device/Product/Detail/Access/AccessConfig/index.tsx
  17. 11 11
      src/pages/device/Product/Detail/Access/index.tsx
  18. 8 8
      src/pages/device/Product/Save/index.tsx
  19. 22 16
      src/pages/device/components/Metadata/Base/Edit/index.tsx
  20. 4 4
      src/pages/device/components/Metadata/Cat/index.tsx
  21. 7 7
      src/pages/link/AccessConfig/index.tsx
  22. 15 15
      src/pages/link/Protocol/index.tsx
  23. 10 10
      src/pages/link/Type/Detail/index.tsx
  24. 17 11
      src/pages/link/Type/index.tsx
  25. 1 0
      src/pages/media/Cascade/index.tsx
  26. 14 7
      src/pages/media/Stream/index.tsx
  27. 4 2
      src/pages/system/Permission/Save/index.tsx
  28. 53 66
      src/pages/system/Permission/index.tsx
  29. 5 5
      src/pages/system/Role/Detail/UserManage/BindUser.tsx
  30. 39 39
      src/pages/system/Role/index.tsx

+ 1 - 1
src/components/AIcon/index.tsx

@@ -1,4 +1,4 @@
-import {createFromIconfontCN} from '@ant-design/icons';
+import { createFromIconfontCN } from '@ant-design/icons';
 
 const AIcon = createFromIconfontCN({
   scriptUrl: '/icons/iconfont.js', // 在 iconfont.cn 上生成

+ 3 - 3
src/components/FBraftEditor/index.tsx

@@ -1,7 +1,7 @@
-import {connect, mapProps} from '@formily/react';
-import BraftEditor, {BraftEditorProps, EditorState} from 'braft-editor';
+import { connect, mapProps } from '@formily/react';
+import BraftEditor, { BraftEditorProps, EditorState } from 'braft-editor';
 import 'braft-editor/dist/index.css';
-import {useState} from 'react';
+import { useState } from 'react';
 
 interface Props extends BraftEditorProps {
   value: any;

+ 4 - 4
src/components/ProTableCard/CardItems/AccessConfig/index.tsx

@@ -1,9 +1,9 @@
 import React from 'react';
-import {StatusColorEnum} from '@/components/BadgeStatus';
-import {TableCard} from '@/components';
+import { StatusColorEnum } from '@/components/BadgeStatus';
+import { TableCard } from '@/components';
 import '@/style/common.less';
-import {Badge, Tooltip} from 'antd';
-import type {AccessItem} from '@/pages/link/AccessConfig/typings';
+import { Badge, Tooltip } from 'antd';
+import type { AccessItem } from '@/pages/link/AccessConfig/typings';
 import './index.less';
 import classNames from 'classnames';
 

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

@@ -1,10 +1,10 @@
 import React from 'react';
-import type {CascadeItem} from '@/pages/media/Cascade/typings';
-import {StatusColorEnum} from '@/components/BadgeStatus';
-import {TableCard} from '@/components';
+import type { CascadeItem } from '@/pages/media/Cascade/typings';
+import { StatusColorEnum } from '@/components/BadgeStatus';
+import { TableCard } from '@/components';
 import '@/style/common.less';
 import '../index.less';
-import {Badge} from 'antd';
+import { Badge } from 'antd';
 
 export interface CascadeCardProps extends CascadeItem {
   detail?: React.ReactNode;

+ 5 - 5
src/components/Upload/Image/index.tsx

@@ -1,10 +1,10 @@
-import {message, Upload} from 'antd';
-import React, {useEffect, useState} from 'react';
-import {LoadingOutlined, PlusOutlined} from '@ant-design/icons';
+import { message, Upload } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
 import SystemConst from '@/utils/const';
 import Token from '@/utils/token';
-import type {UploadChangeParam} from 'antd/lib/upload/interface';
-import type {RcFile} from 'antd/es/upload';
+import type { UploadChangeParam } from 'antd/lib/upload/interface';
+import type { RcFile } from 'antd/es/upload';
 import './index.less';
 
 interface UploadImageProps {

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

@@ -13,16 +13,16 @@ import {
   Upload,
 } from '@formily/antd';
 import React from 'react';
-import {createForm} from '@formily/core';
-import {createSchemaField} from '@formily/react';
+import { createForm } from '@formily/core';
+import { createSchemaField } from '@formily/react';
 import FUpload from '@/components/Upload';
 import * as ICONS from '@ant-design/icons';
-import {message, Modal} from 'antd';
-import {useIntl} from '@@/plugin-locale/localeExports';
-import type {ISchema} from '@formily/json-schema';
-import type {CategoryItem} from '@/pages/visualization/Category/typings';
-import {service, state} from '@/pages/device/Category';
-import type {Response} from '@/utils/typings';
+import { message, Modal } from 'antd';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import type { ISchema } from '@formily/json-schema';
+import type { CategoryItem } from '@/pages/visualization/Category/typings';
+import { service, state } from '@/pages/device/Category';
+import type { Response } from '@/utils/typings';
 
 interface Props {
   visible: boolean;

+ 60 - 59
src/pages/device/Category/index.tsx

@@ -1,17 +1,17 @@
-import {PageContainer} from '@ant-design/pro-layout';
+import { PageContainer } from '@ant-design/pro-layout';
 import Service from '@/pages/device/Category/service';
-import type {ActionType, ProColumns} from '@jetlinks/pro-table';
+import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
-import {DeleteOutlined, EditOutlined, PlusOutlined} from '@ant-design/icons';
-import {Button, message, Popconfirm, Tooltip} from 'antd';
-import {useRef, useState} from 'react';
-import {useIntl} from '@@/plugin-locale/localeExports';
+import { DeleteOutlined, EditOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons';
+import { message } from 'antd';
+import { useRef, useState } from 'react';
+import { useIntl } from '@@/plugin-locale/localeExports';
 import Save from '@/pages/device/Category/Save';
-import {model} from '@formily/reactive';
-import {observer} from '@formily/react';
-import type {Response} from '@/utils/typings';
+import { model } from '@formily/reactive';
+import { observer } from '@formily/react';
+import type { Response } from '@/utils/typings';
 import SearchComponent from '@/components/SearchComponent';
-import {getButtonPermission} from '@/utils/menu';
+import { PermissionButton } from '@/components';
 
 export const service = new Service('device/category');
 
@@ -51,6 +51,8 @@ const Category = observer(() => {
   const [param, setParam] = useState({});
   const [sortParam, setSortParam] = useState<any>({ name: 'sortIndex', order: 'asc' });
   const [treeData, setTreeData] = useState<any[]>([]);
+  const permissionCode = 'device/Category';
+  const { permission } = PermissionButton.usePermission(permissionCode);
 
   const intl = useIntl();
 
@@ -90,29 +92,35 @@ const Category = observer(() => {
       valueType: 'option',
       width: 200,
       render: (text, record) => [
-        <Button
-          key={'edit'}
+        <PermissionButton
+          key="editable"
+          tooltip={{
+            title: intl.formatMessage({
+              id: 'pages.data.option.edit',
+              defaultMessage: '编辑',
+            }),
+          }}
+          isPermission={permission.update}
+          style={{ padding: 0 }}
+          type="link"
           onClick={() => {
             state.visible = true;
             state.current = record;
           }}
-          type="link"
-          style={{ padding: 0 }}
-          disabled={getButtonPermission('device/Category', ['update', 'add'])}
         >
-          <Tooltip
-            title={intl.formatMessage({
-              id: 'pages.data.option.edit',
-              defaultMessage: '编辑',
-            })}
-          >
-            <EditOutlined />
-          </Tooltip>
-        </Button>,
-        <Button
-          type="link"
+          <EditOutlined />
+        </PermissionButton>,
+        <PermissionButton
+          key={'addChildren'}
           style={{ padding: 0 }}
-          key={'add-next'}
+          tooltip={{
+            title: intl.formatMessage({
+              id: 'pages.device.category.addClass',
+              defaultMessage: '添加子分类',
+            }),
+          }}
+          type="link"
+          isPermission={permission.add}
           onClick={() => {
             state.visible = true;
             const sortIndex = getSortIndex(treeData, record.id);
@@ -121,25 +129,19 @@ const Category = observer(() => {
               sortIndex,
             };
           }}
-          disabled={getButtonPermission('device/Category', ['update', 'add'])}
         >
-          <Tooltip
-            title={intl.formatMessage({
-              id: 'pages.device.category.addClass',
-              defaultMessage: '添加子分类',
-            })}
-          >
-            <PlusOutlined />
-          </Tooltip>
-        </Button>,
-        <Button
-          disabled={getButtonPermission('device/Category', ['delete'])}
+          <PlusCircleOutlined />
+        </PermissionButton>,
+        <PermissionButton
           type="link"
+          key="delete"
           style={{ padding: 0 }}
-          key={'delete'}
-        >
-          <Popconfirm
-            onConfirm={async () => {
+          popConfirm={{
+            title: intl.formatMessage({
+              id: 'pages.system.role.option.delete',
+              defaultMessage: '确定要删除吗',
+            }),
+            onConfirm: async () => {
               const resp = (await service.remove(record.id)) as Response<any>;
               if (resp.status === 200) {
                 message.success('操作成功');
@@ -147,19 +149,18 @@ const Category = observer(() => {
                 message.error('操作失败');
               }
               actionRef.current?.reload();
-            }}
-            title={'确认删除吗?'}
-          >
-            <Tooltip
-              title={intl.formatMessage({
-                id: 'pages.data.option.remove',
-                defaultMessage: '删除',
-              })}
-            >
-              <DeleteOutlined />
-            </Tooltip>
-          </Popconfirm>
-        </Button>,
+            },
+          }}
+          tooltip={{
+            title: intl.formatMessage({
+              id: 'pages.data.option.delete',
+              defaultMessage: '删除',
+            }),
+          }}
+          isPermission={permission.delete}
+        >
+          <DeleteOutlined />
+        </PermissionButton>,
       ],
     },
   ];
@@ -204,8 +205,8 @@ const Category = observer(() => {
           }
         }}
         headerTitle={
-          <Button
-            disabled={getButtonPermission('device/Category', ['add'])}
+          <PermissionButton
+            isPermission={permission.add}
             onClick={() => {
               const sortIndex = getSortIndex(treeData, '');
               state.current = {
@@ -221,7 +222,7 @@ const Category = observer(() => {
               id: 'pages.data.option.add',
               defaultMessage: '新增',
             })}
-          </Button>
+          </PermissionButton>
         }
         pagination={false}
         actionRef={actionRef}

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

@@ -1,9 +1,14 @@
-import {Button, Descriptions, message, Popconfirm, Space, Tooltip} from 'antd';
-import {InstanceModel, service} from '@/pages/device/Instance';
-import {useEffect, useState} from 'react';
-import type {ConfigMetadata} from '@/pages/device/Product/typings';
-import {history, useParams} from 'umi';
-import {CheckOutlined, EditOutlined, QuestionCircleOutlined, UndoOutlined,} from '@ant-design/icons';
+import { Button, Descriptions, message, Popconfirm, Space, Tooltip } from 'antd';
+import { InstanceModel, service } from '@/pages/device/Instance';
+import { useEffect, useState } from 'react';
+import type { ConfigMetadata } from '@/pages/device/Product/typings';
+import { history, useParams } from 'umi';
+import {
+  CheckOutlined,
+  EditOutlined,
+  QuestionCircleOutlined,
+  UndoOutlined,
+} from '@ant-design/icons';
 import Edit from './Edit';
 
 const Config = () => {

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

@@ -37,7 +37,7 @@ const Status = observer((props: Props) => {
     });
   };
 
-  const initList = (proItem: ProductItem, configuration: any[], deviceConfigs: any) => {
+  const initList = (proItem: ProductItem, configuration: any, deviceConfigs: any) => {
     const datalist = [
       {
         key: 'product',
@@ -122,7 +122,7 @@ const Status = observer((props: Props) => {
                           );
                           if (resp.status === 200) {
                             message.success('操作成功!');
-                            DiagnoseStatusModel.product = {
+                            DiagnoseStatusModel.status.product = {
                               status: 'success',
                               text: '已发布',
                               info: null,
@@ -242,7 +242,7 @@ const Status = observer((props: Props) => {
                         const resp = await service.deployDevice(InstanceModel.detail?.id || '');
                         if (resp.status === 200) {
                           message.success('操作成功!');
-                          DiagnoseStatusModel.device = {
+                          DiagnoseStatusModel.status.device = {
                             status: 'success',
                             text: '已启用',
                             info: null,
@@ -335,7 +335,7 @@ const Status = observer((props: Props) => {
                           const resp = await service.startGateway(proItem?.accessId || '');
                           if (resp.status === 200) {
                             message.success('操作成功!');
-                            DiagnoseStatusModel.gateway = {
+                            DiagnoseStatusModel.status.gateway = {
                               status: 'success',
                               text: '已启用',
                               info: null,
@@ -381,7 +381,7 @@ const Status = observer((props: Props) => {
                             const resp = await service.startNetwork(deviceConfig.result?.channelId);
                             if (resp.status === 200) {
                               message.success('操作成功!');
-                              DiagnoseStatusModel.gateway = {
+                              DiagnoseStatusModel.status.gateway = {
                                 status: 'success',
                                 text: '已启用',
                                 info: null,
@@ -461,6 +461,7 @@ const Status = observer((props: Props) => {
       network = await service.queryNetworkState(deviceConfig?.channelId);
     }
     initList(proItem.result, configuration.result, deviceConfig.result);
+
     diagnoseProduct(proItem.result)
       .then(() => diagnoseConfig(proItem.result))
       .then(() => diagnoseDevice())

+ 7 - 7
src/pages/device/Instance/Detail/Log/index.tsx

@@ -1,11 +1,11 @@
-import type {ActionType, ProColumns} from '@jetlinks/pro-table';
+import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
-import type {LogItem} from '@/pages/device/Instance/Detail/Log/typings';
-import {Card, Input, Modal, Tooltip} from 'antd';
-import {SearchOutlined} from '@ant-design/icons';
-import {useIntl} from '@@/plugin-locale/localeExports';
-import {InstanceModel, service} from '@/pages/device/Instance';
-import {useEffect, useRef, useState} from 'react';
+import type { LogItem } from '@/pages/device/Instance/Detail/Log/typings';
+import { Card, Input, Modal, Tooltip } from 'antd';
+import { SearchOutlined } from '@ant-design/icons';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import { InstanceModel, service } from '@/pages/device/Instance';
+import { useEffect, useRef, useState } from 'react';
 import SearchComponent from '@/components/SearchComponent';
 
 const Log = () => {

+ 20 - 16
src/pages/device/Instance/Detail/MetadataMap/index.tsx

@@ -1,11 +1,10 @@
 import { Card, Empty } from 'antd';
 import { useEffect, useState } from 'react';
-import { InstanceModel, service } from '@/pages/device/Instance';
-import { productModel } from '@/pages/device/Product';
+import { service } from '@/pages/device/Instance';
 import EditableTable from './EditableTable';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import type { ProductItem } from '@/pages/device/Product/typings';
-
+import { useParams } from 'umi';
 interface Props {
   type: 'device' | 'product';
 }
@@ -14,20 +13,25 @@ const MetadataMap = (props: Props) => {
   const { type } = props;
   const [product, setProduct] = useState<Partial<ProductItem>>();
   const [data, setData] = useState<any>({});
+  const params = useParams<{ id: string }>();
 
-  const handleSearch = () => {
-    service
-      .queryProductState(InstanceModel.detail?.productId || productModel.current?.id || '')
-      .then((resp) => {
-        if (resp.status === 200) {
-          setProduct(resp.result);
-          if (type === 'product') {
-            setData(resp.result);
-          } else {
-            setData(InstanceModel.detail);
-          }
+  const handleSearch = async () => {
+    if (props.type === 'product') {
+      const resp = await service.queryProductState(params.id || '');
+      if (resp.status === 200) {
+        setProduct(resp.result);
+        setData(resp.result);
+      }
+    } else {
+      const resp = await service.detail(params.id || '');
+      if (resp.status === 200) {
+        setData(resp.result);
+        const response = await service.queryProductState(resp.result?.productId || '');
+        if (response.status === 200) {
+          setProduct(response.result);
         }
-      });
+      }
+    }
   };
 
   const checkUrl = (str: string) => {
@@ -93,7 +97,7 @@ const MetadataMap = (props: Props) => {
 
   useEffect(() => {
     handleSearch();
-  }, []);
+  }, [props.type]);
 
   return <Card bordered={false}>{renderComponent()}</Card>;
 };

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

@@ -131,7 +131,6 @@ const EventLog = (props: Props) => {
         actionRef={actionRef}
         search={false}
         params={searchParams}
-        toolBarRender={false}
         request={async (param) => {
           param.pageIndex = param.current - 1;
           delete param.current;

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

@@ -1,8 +1,8 @@
-import {Button, Descriptions} from 'antd';
-import {useIntl} from '@@/plugin-locale/localeExports';
-import {InstanceModel} from '@/pages/device/Instance';
-import {useEffect, useState} from 'react';
-import {EditOutlined} from '@ant-design/icons';
+import { Button, Descriptions } from 'antd';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import { InstanceModel } from '@/pages/device/Instance';
+import { useEffect, useState } from 'react';
+import { EditOutlined } from '@ant-design/icons';
 import Edit from './Edit';
 
 const Tags = () => {

+ 11 - 11
src/pages/device/Instance/Detail/index.tsx

@@ -1,10 +1,10 @@
-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 type {ReactNode} from 'react';
-import {useEffect, useState} from 'react';
-import {observer} from '@formily/react';
+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 type { ReactNode } from 'react';
+import { useEffect, useState } from 'react';
+import { observer } from '@formily/react';
 import Log from '@/pages/device/Instance/Detail/Log';
 // import Alarm from '@/pages/device/components/Alarm';
 import Info from '@/pages/device/Instance/Detail/Info';
@@ -13,13 +13,13 @@ import Running from '@/pages/device/Instance/Detail/Running';
 import ChildDevice from '@/pages/device/Instance/Detail/ChildDevice';
 import Diagnose from '@/pages/device/Instance/Detail/Diagnose';
 import MetadataMap from '@/pages/device/Instance/Detail/MetadataMap';
-import {useIntl} from '@@/plugin-locale/localeExports';
+import { useIntl } from '@@/plugin-locale/localeExports';
 import Metadata from '../../components/Metadata';
-import type {DeviceMetadata} from '@/pages/device/Product/typings';
+import type { DeviceMetadata } from '@/pages/device/Product/typings';
 import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
-import {Store} from 'jetlinks-store';
+import { Store } from 'jetlinks-store';
 import SystemConst from '@/utils/const';
-import {getMenuPathByParams, MENUS_CODE} from '@/utils/menu';
+import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
 
 export const deviceStatus = new Map();

+ 7 - 7
src/pages/device/Instance/Save/index.tsx

@@ -1,10 +1,10 @@
-import {Col, Form, Input, message, Row, Select} 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 {debounce} from 'lodash';
+import { Col, Form, Input, message, Row, Select } 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 { debounce } from 'lodash';
 
 interface Props {
   visible: boolean;

+ 5 - 5
src/pages/device/Product/Detail/Access/AccessConfig/index.tsx

@@ -1,9 +1,9 @@
-import {useEffect, useState} from 'react';
-import {Button, Col, message, Modal, Pagination, Row} from 'antd';
-import {service} from '@/pages/link/AccessConfig';
-import {productModel} from '@/pages/device/Product';
+import { useEffect, useState } from 'react';
+import { Button, Col, message, Modal, Pagination, Row } from 'antd';
+import { service } from '@/pages/link/AccessConfig';
+import { productModel } from '@/pages/device/Product';
 import SearchComponent from '@/components/SearchComponent';
-import type {ProColumns} from '@jetlinks/pro-table';
+import type { ProColumns } from '@jetlinks/pro-table';
 import styles from './index.less';
 import Service from '@/pages/device/Product/service';
 

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

@@ -1,17 +1,17 @@
-import {Badge, Button, Col, Empty, message, Row, Table, Tooltip} from 'antd';
-import {service} from '@/pages/link/AccessConfig';
-import {productModel, service as productService} from '@/pages/device/Product';
+import { Badge, Button, Col, Empty, message, Row, Table, Tooltip } from 'antd';
+import { service } from '@/pages/link/AccessConfig';
+import { productModel, service as productService } from '@/pages/device/Product';
 import styles from './index.less';
-import type {SetStateAction} from 'react';
-import {useEffect, useState} from 'react';
+import type { SetStateAction } from 'react';
+import { useEffect, useState } from 'react';
 import AccessConfig from './AccessConfig';
 import ReactMarkdown from 'react-markdown';
-import {Form, FormGrid, FormItem, FormLayout, Input, Password, PreviewText} from '@formily/antd';
-import type {ISchema} from '@formily/json-schema';
-import type {ConfigProperty} from '@/pages/device/Product/typings';
-import {createSchemaField} from '@formily/react';
-import {createForm} from '@formily/core';
-import {QuestionCircleOutlined} from '@ant-design/icons';
+import { Form, FormGrid, FormItem, FormLayout, Input, Password, PreviewText } from '@formily/antd';
+import type { ISchema } from '@formily/json-schema';
+import type { ConfigProperty } from '@/pages/device/Product/typings';
+import { createSchemaField } from '@formily/react';
+import { createForm } from '@formily/core';
+import { QuestionCircleOutlined } from '@ant-design/icons';
 import TitleComponent from '@/components/TitleComponent';
 
 const componentMap = {

+ 8 - 8
src/pages/device/Product/Save/index.tsx

@@ -1,11 +1,11 @@
-import {useEffect, useState} from 'react';
-import {service} from '@/pages/device/Product';
-import type {ProductItem} from '@/pages/device/Product/typings';
-import {useIntl} from '@@/plugin-locale/localeExports';
-import {RadioCard, UploadImage} from '@/components';
-import {Col, Form, Input, message, Modal, Row, TreeSelect} from 'antd';
-import {useRequest} from 'umi';
-import {debounce} from 'lodash';
+import { useEffect, useState } from 'react';
+import { service } from '@/pages/device/Product';
+import type { ProductItem } from '@/pages/device/Product/typings';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import { RadioCard, UploadImage } from '@/components';
+import { Col, Form, Input, message, Modal, Row, TreeSelect } from 'antd';
+import { useRequest } from 'umi';
+import { debounce } from 'lodash';
 
 interface Props {
   visible: boolean;

+ 22 - 16
src/pages/device/components/Metadata/Base/Edit/index.tsx

@@ -1,8 +1,8 @@
-import {Button, Drawer, Dropdown, Menu, message} from 'antd';
-import {createSchemaField, observer} from '@formily/react';
+import { Button, Drawer, Dropdown, Menu, message } from 'antd';
+import { createSchemaField, observer } from '@formily/react';
 import MetadataModel from '../model';
-import type {Field, IFieldState} from '@formily/core';
-import {createForm, registerValidateRules} from '@formily/core';
+import type { Field, IFieldState } from '@formily/core';
+import { createForm, registerValidateRules } from '@formily/core';
 import {
   ArrayItems,
   Editable,
@@ -15,28 +15,34 @@ import {
   Select,
   Space,
 } from '@formily/antd';
-import type {ISchema} from '@formily/json-schema';
-import {DataTypeList, DateTypeList, EventLevel, FileTypeList, PropertySource,} from '@/pages/device/data';
-import {useMemo} from 'react';
-import {productModel} from '@/pages/device/Product';
-import {service} from '@/pages/device/components/Metadata';
-import {Store} from 'jetlinks-store';
-import type {MetadataItem} from '@/pages/device/Product/typings';
+import type { ISchema } from '@formily/json-schema';
+import {
+  DataTypeList,
+  DateTypeList,
+  EventLevel,
+  FileTypeList,
+  PropertySource,
+} from '@/pages/device/data';
+import { useMemo } from 'react';
+import { productModel } from '@/pages/device/Product';
+import { service } from '@/pages/device/components/Metadata';
+import { Store } from 'jetlinks-store';
+import type { MetadataItem } from '@/pages/device/Product/typings';
 
 import JsonParam from '@/components/Metadata/JsonParam';
 import ArrayParam from '@/components/Metadata/ArrayParam';
 import EnumParam from '@/components/Metadata/EnumParam';
 import BooleanEnum from '@/components/Metadata/BooleanParam';
 import ConfigParam from '@/components/Metadata/ConfigParam';
-import {useIntl} from '@@/plugin-locale/localeExports';
-import {lastValueFrom} from 'rxjs';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import { lastValueFrom } from 'rxjs';
 import SystemConst from '@/utils/const';
 import DB from '@/db';
 import _ from 'lodash';
-import {InstanceModel} from '@/pages/device/Instance';
+import { InstanceModel } from '@/pages/device/Instance';
 import FRuleEditor from '@/components/FRuleEditor';
-import {action} from '@formily/reactive';
-import {asyncUpdateMedata, updateMetadata} from '../../metadata';
+import { action } from '@formily/reactive';
+import { asyncUpdateMedata, updateMetadata } from '../../metadata';
 
 interface Props {
   type: 'product' | 'device';

+ 4 - 4
src/pages/device/components/Metadata/Cat/index.tsx

@@ -1,8 +1,8 @@
-import {Drawer, Tabs} from 'antd';
-import {useEffect, useState} from 'react';
-import {productModel, service} from '@/pages/device/Product';
+import { Drawer, Tabs } from 'antd';
+import { useEffect, useState } from 'react';
+import { productModel, service } from '@/pages/device/Product';
 import MonacoEditor from 'react-monaco-editor';
-import {observer} from '@formily/react';
+import { observer } from '@formily/react';
 
 interface Props {
   visible: boolean;

+ 7 - 7
src/pages/link/AccessConfig/index.tsx

@@ -1,12 +1,12 @@
 import SearchComponent from '@/components/SearchComponent';
-import {getButtonPermission, getMenuPathByCode, MENUS_CODE} from '@/utils/menu';
-import {PageContainer} from '@ant-design/pro-layout';
-import type {ProColumns} from '@jetlinks/pro-table';
-import {Button, Card, Col, Empty, message, Pagination, Popconfirm, Row, Tooltip} from 'antd';
-import {useEffect, useState} from 'react';
-import {useHistory} from 'umi';
+import { getButtonPermission, getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
+import { PageContainer } from '@ant-design/pro-layout';
+import type { ProColumns } from '@jetlinks/pro-table';
+import { Button, Card, Col, Empty, message, Pagination, Popconfirm, Row, Tooltip } from 'antd';
+import { useEffect, useState } from 'react';
+import { useHistory } from 'umi';
 import Service from './service';
-import {CheckCircleOutlined, DeleteOutlined, EditOutlined, StopOutlined} from '@ant-design/icons';
+import { CheckCircleOutlined, DeleteOutlined, EditOutlined, StopOutlined } from '@ant-design/icons';
 import AccessConfigCard from '@/components/ProTableCard/CardItems/AccessConfig';
 
 export const service = new Service('gateway/device');

+ 15 - 15
src/pages/link/Protocol/index.tsx

@@ -118,22 +118,22 @@ const Protocol = () => {
             </Popconfirm>
           </Button>
         ),
-        <Button
-          style={{ padding: 0 }}
+        <Tooltip
           key="delete"
-          type="link"
-          disabled={record.state === 1 || getButtonPermission('link/Protocol', ['delete'])}
+          title={
+            record.state !== 1
+              ? intl.formatMessage({
+                  id: 'pages.data.option.remove',
+                  defaultMessage: '删除',
+                })
+              : '请先禁用该协议,再删除。'
+          }
         >
-          <Tooltip
+          <Button
+            style={{ padding: 0 }}
             key="delete"
-            title={
-              record.state !== 1
-                ? intl.formatMessage({
-                    id: 'pages.data.option.remove',
-                    defaultMessage: '删除',
-                  })
-                : '请先禁用该组件,再删除。'
-            }
+            type="link"
+            disabled={record.state === 1 || getButtonPermission('link/Protocol', ['delete'])}
           >
             <Popconfirm
               title={intl.formatMessage({
@@ -164,8 +164,8 @@ const Protocol = () => {
                 <DeleteOutlined />
               </Tooltip>
             </Popconfirm>
-          </Tooltip>
-        </Button>,
+          </Button>
+        </Tooltip>,
       ],
     },
   ];

+ 10 - 10
src/pages/link/Type/Detail/index.tsx

@@ -1,5 +1,5 @@
-import {PageContainer} from '@ant-design/pro-layout';
-import {createSchemaField, observer} from '@formily/react';
+import { PageContainer } from '@ant-design/pro-layout';
+import { createSchemaField, observer } from '@formily/react';
 import {
   ArrayCollapse,
   Form,
@@ -14,17 +14,17 @@ import {
   Select,
   Submit,
 } from '@formily/antd';
-import type {ISchema} from '@formily/json-schema';
-import {useEffect, useMemo, useRef} from 'react';
-import type {Field} from '@formily/core';
-import {createForm, onFieldValueChange} from '@formily/core';
-import {Card, message} from 'antd';
+import type { ISchema } from '@formily/json-schema';
+import { useEffect, useMemo, useRef } from 'react';
+import type { Field } from '@formily/core';
+import { createForm, onFieldValueChange } from '@formily/core';
+import { Card, message } from 'antd';
 import styles from './index.less';
-import {useAsyncDataSource} from '@/utils/util';
-import {service} from '../index';
+import { useAsyncDataSource } from '@/utils/util';
+import { service } from '../index';
 import _ from 'lodash';
 import FAutoComplete from '@/components/FAutoComplete';
-import {Store} from 'jetlinks-store';
+import { Store } from 'jetlinks-store';
 
 /**
  *  根据类型过滤配置信息

+ 17 - 11
src/pages/link/Type/index.tsx

@@ -1,16 +1,22 @@
-import {useRef, useState} from 'react';
-import type {ActionType, ProColumns} from '@jetlinks/pro-table';
-import {Badge, Button, message, Popconfirm, Tooltip} from 'antd';
-import {CloseCircleOutlined, DeleteOutlined, EditOutlined, PlayCircleOutlined, PlusOutlined,} from '@ant-design/icons';
-import {PageContainer} from '@ant-design/pro-layout';
-import type {NetworkItem} from '@/pages/link/Type/typings';
-import {useIntl} from '@@/plugin-locale/localeExports';
+import { useRef, useState } from 'react';
+import type { ActionType, ProColumns } from '@jetlinks/pro-table';
+import { Badge, Button, message, Popconfirm, Tooltip } from 'antd';
+import {
+  CloseCircleOutlined,
+  DeleteOutlined,
+  EditOutlined,
+  PlayCircleOutlined,
+  PlusOutlined,
+} from '@ant-design/icons';
+import { PageContainer } from '@ant-design/pro-layout';
+import type { NetworkItem } from '@/pages/link/Type/typings';
+import { useIntl } from '@@/plugin-locale/localeExports';
 import SearchComponent from '@/components/SearchComponent';
-import {getButtonPermission, getMenuPathByParams, MENUS_CODE} from '@/utils/menu';
-import {history} from 'umi';
+import { getButtonPermission, getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import { history } from 'umi';
 import Service from '@/pages/link/service';
-import {Store} from 'jetlinks-store';
-import {ProTableCard} from '@/components';
+import { Store } from 'jetlinks-store';
+import { ProTableCard } from '@/components';
 import NetworkCard from '@/components/ProTableCard/CardItems/networkCard';
 
 export const service = new Service('network/config');

+ 1 - 0
src/pages/media/Cascade/index.tsx

@@ -58,6 +58,7 @@ const Cascade = () => {
       type={'link'}
       key={'channel'}
       style={{ padding: 0 }}
+      disabled={getButtonPermission('media/Cascade', ['channel'])}
       onClick={() => {
         const url = getMenuPathByCode(MENUS_CODE[`media/Cascade/Channel`]);
         history.push(url + `?id=${record.id}`);

+ 14 - 7
src/pages/media/Stream/index.tsx

@@ -8,8 +8,9 @@ import Service from '@/pages/media/Stream/service';
 import { getButtonPermission, getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { useHistory } from 'umi';
 import styles from './index.less';
-import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
+import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
 import { model } from '@formily/reactive';
+import { PermissionButton } from '@/components';
 
 export const service = new Service('media/server');
 
@@ -22,6 +23,8 @@ export const StreamModel = model<{
 const Stream = () => {
   const history = useHistory<Record<string, string>>();
   const [param, setParam] = useState<any>({ pageSize: 10, terms: [] });
+  const permissionCode = 'media/Stream';
+  const { permission } = PermissionButton.usePermission(permissionCode);
 
   const columns: ProColumns<StreamItem>[] = [
     {
@@ -75,16 +78,18 @@ const Stream = () => {
       <Card>
         {dataSource.data.length > 0 ? (
           <>
-            <Button
-              disabled={getButtonPermission('media/Stream', ['add'])}
-              type="primary"
+            <PermissionButton
+              isPermission={permission.add}
               onClick={() => {
                 history.push(`${getMenuPathByParams(MENUS_CODE['media/Stream/Detail'])}`);
                 StreamModel.current = {};
               }}
+              key="button"
+              icon={<PlusOutlined />}
+              type="primary"
             >
               新增
-            </Button>
+            </PermissionButton>
 
             <Row gutter={[16, 16]} style={{ marginTop: 10 }}>
               {(dataSource?.data || []).map((item: any) => (
@@ -186,14 +191,16 @@ const Stream = () => {
             description={
               <span>
                 暂无数据,请先
-                <a
+                <Button
+                  type="link"
+                  disabled={getButtonPermission('media/Stream', ['add'])}
                   onClick={() => {
                     history.push(`${getMenuPathByParams(MENUS_CODE['media/Stream/Detail'])}`);
                     StreamModel.current = {};
                   }}
                 >
                   新增流媒体服务
-                </a>
+                </Button>
               </span>
             }
           />

+ 4 - 2
src/pages/system/Permission/Save/index.tsx

@@ -1,4 +1,4 @@
-import { message, Modal } from 'antd';
+import { message } from 'antd';
 import { useIntl } from 'umi';
 import { createForm, onFormSubmitStart } from '@formily/core';
 import { createSchemaField } from '@formily/react';
@@ -8,7 +8,7 @@ import { ArrayTable, Editable, Form, FormItem, Input } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
 import type { PermissionItem } from '@/pages/system/Permission/typings';
 import { service } from '@/pages/system/Permission';
-
+import { Modal } from '@/components';
 interface Props {
   model: 'add' | 'edit' | 'query';
   data: Partial<PermissionItem>;
@@ -259,6 +259,8 @@ const Save = (props: Props) => {
       onCancel={props.close}
       onOk={save}
       width="1000px"
+      permissionCode={'system/Permission'}
+      permission={['add', 'edit']}
     >
       <Form form={form} layout="vertical">
         <SchemaField schema={schema} />

+ 53 - 66
src/pages/system/Permission/index.tsx

@@ -7,7 +7,7 @@ import {
   PlayCircleOutlined,
   PlusOutlined,
 } from '@ant-design/icons';
-import { Badge, Button, Dropdown, Menu, message, Popconfirm, Space, Tooltip, Upload } from 'antd';
+import { Badge, Button, Dropdown, Menu, message, Popconfirm, Space, Upload } from 'antd';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
 import { useIntl } from '@@/plugin-locale/localeExports';
@@ -20,15 +20,18 @@ import SystemConst from '@/utils/const';
 import { downloadObject } from '@/utils/util';
 import Token from '@/utils/token';
 import { getButtonPermission } from '@/utils/menu';
+import { PermissionButton } from '@/components';
 
 export const service = new Service('permission');
 const Permission: React.FC = observer(() => {
   const intl = useIntl();
   const actionRef = useRef<ActionType>();
+  const permissionCode = 'system/Permission';
 
   const [param, setParam] = useState({});
   const [model, setMode] = useState<'add' | 'edit' | 'query'>('query');
   const [current, setCurrent] = useState<Partial<PermissionItem>>({});
+  const { permission } = PermissionButton.usePermission(permissionCode);
 
   const edit = async (record: PermissionItem) => {
     setMode('edit');
@@ -144,36 +147,33 @@ const Permission: React.FC = observer(() => {
       valueType: 'option',
       width: 200,
       render: (text, record) => [
-        <Button
-          type="link"
-          disabled={getButtonPermission('system/Permission', ['add'])}
-          style={{ padding: 0 }}
+        <PermissionButton
           key="editable"
-          onClick={() => {
-            edit(record);
-          }}
-        >
-          <Tooltip
-            title={intl.formatMessage({
+          tooltip={{
+            title: intl.formatMessage({
               id: 'pages.data.option.edit',
               defaultMessage: '编辑',
-            })}
-          >
-            <EditOutlined />
-          </Tooltip>
-        </Button>,
-        <Button
+            }),
+          }}
+          isPermission={permission.update}
           style={{ padding: 0 }}
-          disabled={getButtonPermission('system/Permission', ['action'])}
           type="link"
-          key="view"
+          onClick={() => {
+            edit(record);
+          }}
         >
-          <Popconfirm
-            title={intl.formatMessage({
-              id: 'pages.data.option.disabled.tips',
+          <EditOutlined />
+        </PermissionButton>,
+        <PermissionButton
+          type={'link'}
+          key={'state'}
+          style={{ padding: 0 }}
+          popConfirm={{
+            title: intl.formatMessage({
+              id: `pages.data.option.${record.status ? 'disabled' : 'enabled'}.tips`,
               defaultMessage: '确认禁用?',
-            })}
-            onConfirm={async () => {
+            }),
+            onConfirm: async () => {
               await service.update({
                 ...record,
                 id: record.id,
@@ -186,40 +186,27 @@ const Permission: React.FC = observer(() => {
                 }),
               );
               actionRef.current?.reload();
-            }}
-          >
-            <Tooltip
-              title={intl.formatMessage({
-                id: `pages.data.option.${record.status ? 'disabled' : 'enabled'}`,
-                defaultMessage: record.status ? '禁用' : '启用',
-              })}
-            >
-              {record.status ? <CloseCircleOutlined /> : <PlayCircleOutlined />}
-            </Tooltip>
-          </Popconfirm>
-        </Button>,
-        <Button
-          type="link"
-          style={{ padding: 0 }}
-          disabled={record.status === 1 || getButtonPermission('system/Permission', ['delete'])}
+            },
+          }}
+          isPermission={permission.action}
+          tooltip={{
+            title: intl.formatMessage({
+              id: `pages.data.option.${record.status ? 'disabled' : 'enabled'}`,
+              defaultMessage: record.status ? '禁用' : '启用',
+            }),
+          }}
         >
-          <Tooltip
-            key="delete"
-            title={
-              record.status === 0
-                ? intl.formatMessage({
-                    id: 'pages.data.option.remove',
-                    defaultMessage: '删除',
-                  })
-                : '请先禁用该权限,再删除。'
-            }
-          >
-            <Popconfirm
-              title={intl.formatMessage({
-                id: 'pages.data.option.remove.tips',
-                defaultMessage: '确认删除?',
-              })}
-              onConfirm={async () => {
+          {record.status ? <CloseCircleOutlined /> : <PlayCircleOutlined />}
+        </PermissionButton>,
+        <PermissionButton
+          type={'link'}
+          key={'delete'}
+          style={{ padding: 0 }}
+          isPermission={permission.delete}
+          popConfirm={{
+            title: '确认删除',
+            onConfirm: async () => {
+              if (record.status) {
                 await service.remove(record.id);
                 message.success(
                   intl.formatMessage({
@@ -228,12 +215,12 @@ const Permission: React.FC = observer(() => {
                   }),
                 );
                 actionRef.current?.reload();
-              }}
-            >
-              <DeleteOutlined />
-            </Popconfirm>
-          </Tooltip>
-        </Button>,
+              }
+            },
+          }}
+        >
+          <DeleteOutlined />
+        </PermissionButton>,
       ],
     },
   ];
@@ -256,11 +243,11 @@ const Permission: React.FC = observer(() => {
         search={false}
         headerTitle={
           <Space>
-            <Button
+            <PermissionButton
               onClick={() => {
                 setMode('add');
               }}
-              disabled={getButtonPermission('system/Permission', ['add'])}
+              isPermission={permission.add}
               key="button"
               icon={<PlusOutlined />}
               type="primary"
@@ -269,7 +256,7 @@ const Permission: React.FC = observer(() => {
                 id: 'pages.data.option.add',
                 defaultMessage: '新增',
               })}
-            </Button>
+            </PermissionButton>
             <Dropdown key={'more'} overlay={menu} placement="bottom">
               <Button>批量操作</Button>
             </Dropdown>

+ 5 - 5
src/pages/system/Role/Detail/UserManage/BindUser.tsx

@@ -1,9 +1,9 @@
-import type {ProColumns} from '@jetlinks/pro-table';
+import type { ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
-import {message, Modal} from 'antd';
-import {useRef, useState} from 'react';
-import {useIntl} from '@@/plugin-locale/localeExports';
-import {service} from '@/pages/system/User/index';
+import { message, Modal } from 'antd';
+import { useRef, useState } from 'react';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import { service } from '@/pages/system/User/index';
 import Service from '@/pages/system/Role/service';
 import SearchComponent from '@/components/SearchComponent';
 

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

@@ -1,7 +1,7 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import React, { useEffect, useRef } from 'react';
 import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
-import { Button, message, Popconfirm, Tooltip } from 'antd';
+import { message } from 'antd';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import BaseCrud from '@/components/BaseCrud';
 import Service from './service';
@@ -12,12 +12,15 @@ import { Store } from 'jetlinks-store';
 import SystemConst from '@/utils/const';
 import { CurdModel } from '@/components/BaseCrud/model';
 import { getButtonPermission, getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import { PermissionButton } from '@/components';
 
 export const service = new Service('role');
 
 const Role: React.FC = observer(() => {
   const intl = useIntl();
   const actionRef = useRef<ActionType>();
+  const permissionCode = 'system/Role';
+  const { permission } = PermissionButton.usePermission(permissionCode);
 
   const columns: ProColumns<RoleItem>[] = [
     // {
@@ -83,36 +86,33 @@ const Role: React.FC = observer(() => {
       valueType: 'option',
       width: 200,
       render: (text, record) => [
-        <Button
-          type="link"
-          key={'edit'}
-          style={{ padding: 0 }}
-          disabled={getButtonPermission('system/Role', ['update'])}
-          onClick={() =>
-            history.push(`${getMenuPathByParams(MENUS_CODE['system/Role/Detail'], record.id)}`)
-          }
-        >
-          <Tooltip
-            title={intl.formatMessage({
+        <PermissionButton
+          key="editable"
+          tooltip={{
+            title: intl.formatMessage({
               id: 'pages.data.option.edit',
               defaultMessage: '编辑',
-            })}
-          >
-            <EditOutlined />
-          </Tooltip>
-        </Button>,
-        <Button
-          type="link"
-          disabled={getButtonPermission('system/Role', ['delete'])}
+            }),
+          }}
+          isPermission={permission.update}
           style={{ padding: 0 }}
-          key="delete"
+          type="link"
+          onClick={() => {
+            history.push(`${getMenuPathByParams(MENUS_CODE['system/Role/Detail'], record.id)}`);
+          }}
         >
-          <Popconfirm
-            title={intl.formatMessage({
-              id: 'pages.data.option.remove.tips',
-              defaultMessage: '确认删除?',
-            })}
-            onConfirm={async () => {
+          <EditOutlined />
+        </PermissionButton>,
+        <PermissionButton
+          type="link"
+          key="delete"
+          style={{ padding: 0 }}
+          popConfirm={{
+            title: intl.formatMessage({
+              id: 'pages.system.role.option.delete',
+              defaultMessage: '确定要删除吗',
+            }),
+            onConfirm: async () => {
               await service.remove(record.id);
               message.success(
                 intl.formatMessage({
@@ -121,18 +121,18 @@ const Role: React.FC = observer(() => {
                 }),
               );
               actionRef.current?.reload();
-            }}
-          >
-            <Tooltip
-              title={intl.formatMessage({
-                id: 'pages.data.option.remove',
-                defaultMessage: '删除',
-              })}
-            >
-              <DeleteOutlined />
-            </Tooltip>
-          </Popconfirm>
-        </Button>,
+            },
+          }}
+          tooltip={{
+            title: intl.formatMessage({
+              id: 'pages.data.option.delete',
+              defaultMessage: '删除',
+            }),
+          }}
+          isPermission={permission.delete}
+        >
+          <DeleteOutlined />
+        </PermissionButton>,
       ],
     },
   ];