Procházet zdrojové kódy

Merge sc

fix: 修改bug
XieYongHong před 3 roky
rodič
revize
72dd4c895e

+ 55 - 33
src/components/NoticeIcon/index.tsx

@@ -1,4 +1,4 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
 import { Button, message, notification } from 'antd';
 import { groupBy } from 'lodash';
 import moment from 'moment';
@@ -72,6 +72,9 @@ const NoticeIconView = () => {
   // const { data } = useRequest(getNotices);
 
   const history = useHistory();
+
+  const historyRef = useRef(history);
+  historyRef.current = history;
   const [subscribeTopic] = useSendWebsocketMessage();
 
   const getUnread = () => {
@@ -92,6 +95,54 @@ const NoticeIconView = () => {
       });
   };
 
+  const changeReadState = async (item: any, type?: 'notice' | 'icon') => {
+    const resp = await service.changeNoticeReadState(item.id);
+    if (resp.status === 200) {
+      const url = getMenuPathByCode(MENUS_CODE['account/NotificationRecord']);
+      historyRef.current?.push(url, { ...item });
+      if (type === 'icon') {
+        setVisible(false);
+      } else {
+        notification.close(item.id);
+      }
+    }
+  };
+
+  const openNotification = (resp: any) => {
+    notification.warning({
+      style: { width: 320 },
+      message: resp?.payload?.topicName,
+      description: (
+        <div
+          className="ellipsis"
+          style={{ cursor: 'pointer' }}
+          onClick={() => {
+            changeReadState(resp?.payload, 'notice');
+          }}
+        >
+          {resp?.payload?.message}
+        </div>
+      ),
+      key: resp.payload.id,
+      btn: (
+        <Button
+          type="primary"
+          size="small"
+          onClick={() => {
+            service.changeNoticeReadState(resp.payload.id).then((response) => {
+              if (response.status === 200) {
+                notification.close(resp.payload.id);
+                getUnread();
+              }
+            });
+          }}
+        >
+          标记已读
+        </Button>
+      ),
+    });
+  };
+
   const subscribeNotice = () => {
     const id = `notification`;
     const topic = `/notifications`;
@@ -99,27 +150,7 @@ const NoticeIconView = () => {
       ?.pipe(throttleTime(2000))
       .subscribe((resp: any) => {
         getUnread();
-        notification.warning({
-          message: resp?.payload?.topicName,
-          description: resp?.payload?.message,
-          key: resp.payload.id,
-          btn: (
-            <Button
-              type="primary"
-              size="small"
-              onClick={() => {
-                service.changeNoticeReadState(resp.payload.id).then((response) => {
-                  if (response.status === 200) {
-                    notification.close(resp.payload.id);
-                    getUnread();
-                  }
-                });
-              }}
-            >
-              标记已读
-            </Button>
-          ),
-        });
+        openNotification(resp);
       });
   };
 
@@ -129,16 +160,7 @@ const NoticeIconView = () => {
   }, []);
 
   const noticeData = getNoticeData(notices);
-  // const unreadMsg = getUnreadData(noticeData || {});
-
-  const changeReadState = async (item: any) => {
-    const resp = await service.changeNoticeReadState(item.id);
-    if (resp.status === 200) {
-      const url = getMenuPathByCode(MENUS_CODE['account/NotificationRecord']);
-      history.push(url, { ...item });
-      setVisible(false);
-    }
-  };
+  // const unreadMsg = getUnreadData(noticeData || {})
 
   const clearReadState = async (title: string) => {
     const clearIds = (getNoticeData(notices).unread || []).map((item) => item.id) || [];
@@ -154,7 +176,7 @@ const NoticeIconView = () => {
       className={styles.action}
       count={unreadCount}
       onItemClick={(item) => {
-        changeReadState(item!);
+        changeReadState(item!, 'icon');
       }}
       onClear={(title: string) => clearReadState(title)}
       loading={loading}

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

@@ -2,7 +2,8 @@ import TitleComponent from '@/components/TitleComponent';
 import { Badge, Button, message, Popconfirm, Space } from 'antd';
 import styles from './index.less';
 import { observer } from '@formily/reactive-react';
-import { ListProps, urlMap } from './model';
+import type { ListProps } from './model';
+import { urlMap } from './model';
 import { gatewayList } from './model';
 import { textColorMap } from './model';
 import {
@@ -1185,6 +1186,7 @@ const Status = observer((props: Props) => {
   }, [DiagnoseStatusModel.status, DiagnoseStatusModel.list]);
 
   const handleSearch = async () => {
+    console.log(devicePermission);
     DiagnoseStatusModel.gateway = {};
     DiagnoseStatusModel.product = {};
     DiagnoseStatusModel.configuration = {

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

@@ -6,7 +6,7 @@ import { useIntl } from '@@/plugin-locale/localeExports';
 import Config from '@/pages/device/Instance/Detail/Config';
 import Reation from '@/pages/device/Instance/Detail/Reation';
 import Save from '../../Save';
-import { useEffect, useState } from 'react';
+import { useState } from 'react';
 import type { DeviceInstance } from '../../typings';
 import { EditOutlined } from '@ant-design/icons';
 import Tags from '@/pages/device/Instance/Detail/Tags';
@@ -19,10 +19,6 @@ const Info = observer(() => {
   const { permission } = PermissionButton.usePermission('device/Instance');
   const { minHeight } = useDomFullHeight(`.device-detail-body`);
 
-  useEffect(() => {
-    console.log(InstanceModel.detail);
-  }, [InstanceModel.detail]);
-
   return (
     <>
       <Card className={'device-detail-body'} style={{ minHeight }}>

+ 17 - 6
src/pages/device/Instance/Detail/Tags/Edit.tsx

@@ -6,10 +6,12 @@ import { Modal } from 'antd';
 import { useIntl } from 'umi';
 import GeoComponent from './location/GeoComponent';
 import { onlyMessage } from '@/utils/util';
+import RemoveData from './RemoveData';
 
 interface Props {
   close: () => void;
   tags: any[];
+  refresh: () => void;
 }
 
 const Edit = (props: Props) => {
@@ -27,6 +29,7 @@ const Edit = (props: Props) => {
       FormItem,
       Input,
       ArrayTable,
+      RemoveData,
       GeoComponent,
     },
   });
@@ -123,7 +126,10 @@ const Edit = (props: Props) => {
                   properties: {
                     remove: {
                       type: 'void',
-                      'x-component': 'ArrayTable.Remove',
+                      'x-component': 'RemoveData',
+                      // 'x-component-props': {
+                      //   tags: tags,
+                      // },
                     },
                   },
                 },
@@ -152,12 +158,17 @@ const Edit = (props: Props) => {
       width={1000}
       onOk={async () => {
         const values: any = (await form.submit()) as any;
-        const list = (values?.tags || []).filter((item: any) => item?.id);
-        const resp = await service.saveTags(InstanceModel.detail?.id || '', list);
-        if (resp.status === 200) {
-          InstanceModel.detail = { ...InstanceModel.detail, tags: values.tags };
-          onlyMessage('操作成功!');
+        if (values?.tags.length === 0) {
           props.close();
+        } else {
+          const list = (values?.tags || []).filter((item: any) => item?.key);
+          const resp = await service.saveTags(InstanceModel.detail?.id || '', list);
+          if (resp.status === 200) {
+            props.refresh();
+            // InstanceModel.detail = { ...InstanceModel.detail, tags: values.tags };
+            onlyMessage('操作成功!');
+            props.close();
+          }
         }
       }}
     >

+ 39 - 0
src/pages/device/Instance/Detail/Tags/RemoveData.tsx

@@ -0,0 +1,39 @@
+import { DeleteOutlined } from '@ant-design/icons';
+import { ArrayItems } from '@formily/antd';
+import { Popconfirm } from 'antd';
+import { useField } from '@formily/react';
+import { InstanceModel, service } from '@/pages/device/Instance';
+
+const RemoveData = () => {
+  const index = ArrayItems.useIndex!();
+  const self = useField();
+  const array = ArrayItems.useArray!();
+  if (!array) return null;
+  if (array.field?.pattern !== 'editable') return null;
+
+  return (
+    <div>
+      <Popconfirm
+        title={'确认删除'}
+        onConfirm={async () => {
+          if (self?.disabled) return;
+          const row = array.field.value[index];
+          if (row.id) {
+            const resp = await service.delTags(InstanceModel.detail?.id || '', row.id);
+            if (resp.status === 200) {
+              array.field?.remove?.(index);
+              array.props?.onRemove?.(index);
+            }
+          } else {
+            array.field?.remove?.(index);
+            array.props?.onRemove?.(index);
+          }
+        }}
+      >
+        <DeleteOutlined />
+      </Popconfirm>
+    </div>
+  );
+};
+
+export default RemoveData;

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

@@ -1,6 +1,6 @@
 import { Button, Descriptions, Tooltip } from 'antd';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import { InstanceModel } from '@/pages/device/Instance';
+import { InstanceModel, service } from '@/pages/device/Instance';
 import { useEffect, useState } from 'react';
 import { EditOutlined } from '@ant-design/icons';
 import Edit from './Edit';
@@ -12,6 +12,13 @@ const Tags = () => {
 
   const tag = InstanceModel.detail?.tags;
 
+  const getDetail = async () => {
+    const response = await service.detail(InstanceModel.detail?.id || '');
+    if (response.status === 200) {
+      InstanceModel.detail = { ...InstanceModel.detail, ...response?.result };
+    }
+  };
+
   useEffect(() => {
     if (tag) {
       setTags([...tag] || []);
@@ -55,6 +62,9 @@ const Tags = () => {
       </Descriptions>
       {visible && (
         <Edit
+          refresh={() => {
+            getDetail();
+          }}
           close={() => {
             setVisible(false);
           }}

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

@@ -168,6 +168,10 @@ class Service extends BaseService<DeviceInstance> {
       method: 'PATCH',
       data,
     });
+  public delTags = (deviceId: string, id: string) =>
+    request(`/${SystemConst.API_BASE}/device-instance/${deviceId}/tag/${id}`, {
+      method: 'DELETE',
+    });
   //产品状态
   public queryProductState = (id: string) =>
     request(`/${SystemConst.API_BASE}/device/product/${id}`, {

+ 2 - 1
src/pages/system/Role/Detail/Permission/index.tsx

@@ -5,6 +5,7 @@ import { history, useParams } from 'umi';
 import { service } from '@/pages/system/Role';
 import { flattenArray, onlyMessage } from '@/utils/util';
 import TitleComponent from '@/components/TitleComponent';
+import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
 
 const Permission = () => {
   const params = useParams<{ id: string }>();
@@ -84,7 +85,7 @@ const Permission = () => {
             .subscribe((resp) => {
               if (resp.status === 200) {
                 onlyMessage('操作成功');
-                history.goBack();
+                history.replace(`${getMenuPathByCode(MENUS_CODE['system/Role'])}`);
               }
             });
         }}

+ 138 - 0
src/pages/system/Role/Save/index.tsx

@@ -0,0 +1,138 @@
+import { useIntl } from 'umi';
+import { createForm } from '@formily/core';
+import { createSchemaField } from '@formily/react';
+import React from 'react';
+import * as ICONS from '@ant-design/icons';
+import { Form, FormItem, Input } from '@formily/antd';
+import type { ISchema } from '@formily/json-schema';
+import { service } from '@/pages/system/Role';
+import { Modal } from '@/components';
+import { onlyMessage } from '@/utils/util';
+import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import useHistory from '@/hooks/route/useHistory';
+
+interface Props {
+  model: 'add' | 'edit' | 'query';
+  close: () => void;
+}
+
+const Save = (props: Props) => {
+  const { model } = props;
+  const intl = useIntl();
+
+  const history = useHistory();
+
+  const form = createForm({
+    validateFirst: true,
+  });
+
+  const SchemaField = createSchemaField({
+    components: {
+      FormItem,
+      Input,
+    },
+    scope: {
+      icon(name: any) {
+        return React.createElement(ICONS[name]);
+      },
+    },
+  });
+
+  const schema: ISchema = {
+    type: 'object',
+    properties: {
+      name: {
+        title: intl.formatMessage({
+          id: 'pages.table.name',
+          defaultMessage: '角色名称',
+        }),
+        type: 'string',
+        'x-decorator': 'FormItem',
+        'x-component': 'Input',
+        'x-decorator-props': {},
+        name: 'name',
+        required: true,
+        'x-component-props': {
+          placeholder: '请输入角色名称',
+        },
+        'x-validator': [
+          {
+            max: 64,
+            message: '最多可输入64个字符',
+          },
+          {
+            required: true,
+            message: '请输入名称',
+          },
+        ],
+      },
+      description: {
+        type: 'string',
+        title: intl.formatMessage({
+          id: 'pages.table.describe',
+          defaultMessage: '描述',
+        }),
+        'x-decorator': 'FormItem',
+        'x-component': 'Input.TextArea',
+        'x-component-props': {
+          checkStrength: true,
+          placeholder: '请输入说明',
+        },
+        'x-decorator-props': {},
+        name: 'password',
+        required: false,
+        'x-validator': [
+          {
+            max: 200,
+            message: '最多可输入200个字符',
+          },
+        ],
+      },
+    },
+  };
+
+  const save = async () => {
+    const value = await form.submit<RoleItem>();
+    const response: any = await service.save(value);
+    if (response.status === 200) {
+      onlyMessage(
+        intl.formatMessage({
+          id: 'pages.data.option.success',
+          defaultMessage: '操作成功',
+        }),
+      );
+      if ((window as any).onTabSaveSuccess) {
+        (window as any).onTabSaveSuccess(response.result);
+        setTimeout(() => window.close(), 300);
+      } else {
+        history.push(
+          `${getMenuPathByParams(MENUS_CODE['system/Role/Detail'], response.result.id)}`,
+        );
+      }
+      props.close();
+    } else {
+      onlyMessage('操作失败!', 'error');
+    }
+  };
+
+  return (
+    <Modal
+      title={intl.formatMessage({
+        id: `pages.data.option.${model}`,
+        defaultMessage: '编辑',
+      })}
+      maskClosable={false}
+      visible={model !== 'query'}
+      onCancel={props.close}
+      onOk={save}
+      width="35vw"
+      permissionCode={'system/Role'}
+      permission={['add']}
+    >
+      <Form form={form} layout="vertical">
+        <SchemaField schema={schema} />
+      </Form>
+    </Modal>
+  );
+};
+export default Save;

+ 228 - 0
src/pages/system/Role/index copy.tsx

@@ -0,0 +1,228 @@
+import { PageContainer } from '@ant-design/pro-layout';
+import React, { useEffect, useRef } from 'react';
+import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
+import type { ActionType, ProColumns } from '@jetlinks/pro-table';
+import BaseCrud from '@/components/BaseCrud';
+import Service from './service';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import { observer } from '@formily/react';
+import { history, useLocation } from 'umi';
+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';
+import { onlyMessage } from '@/utils/util';
+
+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>[] = [
+    // {
+    //   dataIndex: 'index',
+    //   valueType: 'indexBorder',
+    //   width: 48,
+    // },
+    {
+      title: intl.formatMessage({
+        id: 'pages.system.role.id',
+        defaultMessage: '标识',
+      }),
+      dataIndex: 'id',
+      // copyable: true,
+      ellipsis: true,
+      // sorter: true,
+      // defaultSortOrder: 'ascend',
+      formItemProps: {
+        rules: [
+          {
+            required: true,
+            message: '此项为必填项',
+          },
+        ],
+      },
+    },
+    {
+      title: intl.formatMessage({
+        id: 'pages.table.name',
+        defaultMessage: '名称',
+      }),
+      dataIndex: 'name',
+      // copyable: true,
+      ellipsis: true,
+      // tip: intl.formatMessage({
+      //   id: 'pages.system.userName.tips',
+      //   defaultMessage: '用户名过长会自动收缩',
+      // }),
+      formItemProps: {
+        rules: [
+          {
+            required: true,
+            message: '此项为必填项',
+          },
+        ],
+      },
+    },
+    {
+      title: intl.formatMessage({
+        id: 'pages.table.describe',
+        defaultMessage: '描述',
+      }),
+      ellipsis: true,
+      dataIndex: 'description',
+      filters: true,
+      onFilter: true,
+    },
+    {
+      title: intl.formatMessage({
+        id: 'pages.data.option',
+        defaultMessage: '操作',
+      }),
+      valueType: 'option',
+      width: 200,
+      render: (text, record) => [
+        <PermissionButton
+          key="editable"
+          tooltip={{
+            title: intl.formatMessage({
+              id: 'pages.data.option.edit',
+              defaultMessage: '编辑',
+            }),
+          }}
+          isPermission={permission.update}
+          style={{ padding: 0 }}
+          type="link"
+          onClick={() => {
+            history.push(`${getMenuPathByParams(MENUS_CODE['system/Role/Detail'], record.id)}`);
+          }}
+        >
+          <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);
+              onlyMessage(
+                intl.formatMessage({
+                  id: 'pages.data.option.success',
+                  defaultMessage: '操作成功!',
+                }),
+              );
+              actionRef.current?.reload();
+            },
+          }}
+          tooltip={{
+            title: intl.formatMessage({
+              id: 'pages.data.option.delete',
+              defaultMessage: '删除',
+            }),
+          }}
+          isPermission={permission.delete}
+        >
+          <DeleteOutlined />
+        </PermissionButton>,
+      ],
+    },
+  ];
+
+  const schema = {
+    type: 'object',
+    properties: {
+      name: {
+        title: intl.formatMessage({
+          id: 'pages.table.name',
+          defaultMessage: '角色名称',
+        }),
+        type: 'string',
+        'x-decorator': 'FormItem',
+        'x-component': 'Input',
+        'x-decorator-props': {},
+        name: 'name',
+        required: true,
+        'x-component-props': {
+          placeholder: '请输入角色名称',
+        },
+        'x-validator': [
+          {
+            max: 64,
+            message: '最多可输入64个字符',
+          },
+          {
+            required: true,
+            message: '请输入名称',
+          },
+        ],
+      },
+      description: {
+        type: 'string',
+        title: intl.formatMessage({
+          id: 'pages.table.describe',
+          defaultMessage: '描述',
+        }),
+        'x-decorator': 'FormItem',
+        'x-component': 'Input.TextArea',
+        'x-component-props': {
+          checkStrength: true,
+          placeholder: '请输入说明',
+        },
+        'x-decorator-props': {},
+        name: 'password',
+        required: false,
+        'x-validator': [
+          {
+            max: 200,
+            message: '最多可输入200个字符',
+          },
+        ],
+      },
+    },
+  };
+
+  const location = useLocation();
+
+  useEffect(() => {
+    if ((location as any).query?.save === 'true') {
+      CurdModel.add();
+    }
+    const subscription = Store.subscribe(SystemConst.BASE_UPDATE_DATA, (data) => {
+      if ((window as any).onTabSaveSuccess) {
+        (window as any).onTabSaveSuccess(data);
+        setTimeout(() => window.close(), 300);
+      } else {
+        history.push(`${getMenuPathByParams(MENUS_CODE['system/Role/Detail'], data.id)}`);
+      }
+    });
+    return () => subscription.unsubscribe();
+  }, []);
+
+  return (
+    <PageContainer>
+      <BaseCrud<RoleItem>
+        disableAdd={getButtonPermission('system/Role', ['add'])}
+        actionRef={actionRef}
+        moduleName="role"
+        columns={columns}
+        service={service}
+        search={false}
+        title={intl.formatMessage({
+          id: 'pages.system.role',
+          defaultMessage: '角色列表',
+        })}
+        schema={schema}
+      />
+    </PageContainer>
+  );
+});
+export default Role;

+ 53 - 91
src/pages/system/Role/index.tsx

@@ -1,18 +1,18 @@
 import { PageContainer } from '@ant-design/pro-layout';
-import React, { useEffect, useRef } from 'react';
-import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
+import React, { useRef, useState } from 'react';
+import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
-import BaseCrud from '@/components/BaseCrud';
 import Service from './service';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { observer } from '@formily/react';
-import { history, useLocation } from 'umi';
-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 { history } from 'umi';
+import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { PermissionButton } from '@/components';
 import { onlyMessage } from '@/utils/util';
+import ProTable from '@jetlinks/pro-table';
+import SearchComponent from '@/components/SearchComponent';
+import { useDomFullHeight } from '@/hooks';
+import Save from './Save';
 
 export const service = new Service('role');
 
@@ -21,13 +21,10 @@ const Role: React.FC = observer(() => {
   const actionRef = useRef<ActionType>();
   const permissionCode = 'system/Role';
   const { permission } = PermissionButton.usePermission(permissionCode);
+  const { minHeight } = useDomFullHeight(`.role`, 24);
+  const [model, setMode] = useState<'add' | 'edit' | 'query'>('query');
 
   const columns: ProColumns<RoleItem>[] = [
-    // {
-    //   dataIndex: 'index',
-    //   valueType: 'indexBorder',
-    //   width: 48,
-    // },
     {
       title: intl.formatMessage({
         id: 'pages.system.role.id',
@@ -36,6 +33,7 @@ const Role: React.FC = observer(() => {
       dataIndex: 'id',
       // copyable: true,
       ellipsis: true,
+      fixed: 'left',
       // sorter: true,
       // defaultSortOrder: 'ascend',
       formItemProps: {
@@ -85,6 +83,7 @@ const Role: React.FC = observer(() => {
       }),
       valueType: 'option',
       width: 200,
+      fixed: 'right',
       render: (text, record) => [
         <PermissionButton
           key="editable"
@@ -137,90 +136,53 @@ const Role: React.FC = observer(() => {
     },
   ];
 
-  const schema = {
-    type: 'object',
-    properties: {
-      name: {
-        title: intl.formatMessage({
-          id: 'pages.table.name',
-          defaultMessage: '角色名称',
-        }),
-        type: 'string',
-        'x-decorator': 'FormItem',
-        'x-component': 'Input',
-        'x-decorator-props': {},
-        name: 'name',
-        required: true,
-        'x-component-props': {
-          placeholder: '请输入角色名称',
-        },
-        'x-validator': [
-          {
-            max: 64,
-            message: '最多可输入64个字符',
-          },
-          {
-            required: true,
-            message: '请输入名称',
-          },
-        ],
-      },
-      description: {
-        type: 'string',
-        title: intl.formatMessage({
-          id: 'pages.table.describe',
-          defaultMessage: '描述',
-        }),
-        'x-decorator': 'FormItem',
-        'x-component': 'Input.TextArea',
-        'x-component-props': {
-          checkStrength: true,
-          placeholder: '请输入说明',
-        },
-        'x-decorator-props': {},
-        name: 'password',
-        required: false,
-        'x-validator': [
-          {
-            max: 200,
-            message: '最多可输入200个字符',
-          },
-        ],
-      },
-    },
-  };
-
-  const location = useLocation();
-
-  useEffect(() => {
-    if ((location as any).query?.save === 'true') {
-      CurdModel.add();
-    }
-    const subscription = Store.subscribe(SystemConst.BASE_UPDATE_DATA, (data) => {
-      if ((window as any).onTabSaveSuccess) {
-        (window as any).onTabSaveSuccess(data);
-        setTimeout(() => window.close(), 300);
-      } else {
-        history.push(`${getMenuPathByParams(MENUS_CODE['system/Role/Detail'], data.id)}`);
-      }
-    });
-    return () => subscription.unsubscribe();
-  }, []);
+  const [param, setParam] = useState({});
 
   return (
     <PageContainer>
-      <BaseCrud<RoleItem>
-        disableAdd={getButtonPermission('system/Role', ['add'])}
+      <SearchComponent<RoleItem>
+        field={columns}
+        target="role"
+        onSearch={(data) => {
+          // 重置分页数据
+          actionRef.current?.reset?.();
+          setParam(data);
+        }}
+      />
+      <ProTable<RoleItem>
         actionRef={actionRef}
-        moduleName="role"
+        params={param}
         columns={columns}
-        service={service}
+        scroll={{ x: 1366 }}
+        tableClassName={'role'}
+        tableStyle={{ minHeight }}
         search={false}
-        title={intl.formatMessage({
-          id: 'pages.system.role',
-          defaultMessage: '角色列表',
-        })}
-        schema={schema}
+        headerTitle={
+          <PermissionButton
+            onClick={() => {
+              setMode('add');
+            }}
+            isPermission={permission.add}
+            key="button"
+            icon={<PlusOutlined />}
+            type="primary"
+          >
+            {intl.formatMessage({
+              id: 'pages.data.option.add',
+              defaultMessage: '新增',
+            })}
+          </PermissionButton>
+        }
+        request={async (params) =>
+          service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+        }
+      />
+      <Save
+        model={model}
+        close={() => {
+          setMode('query');
+          actionRef.current?.reload();
+        }}
       />
     </PageContainer>
   );