wzyyy 3 лет назад
Родитель
Сommit
eecc73d970

+ 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}

+ 4 - 4
src/components/SearchComponent/index.tsx

@@ -545,17 +545,18 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
     }
 
     if (type) {
-      setUrl({ q: JSON.stringify(value) });
+      setUrl({ q: JSON.stringify(value), target: props.target });
     }
     onSearch({ terms: _temp });
   };
 
   useEffect(() => {
-    if (url.q) {
+    // 防止页面下多个TabsTabPane中的查询组件共享路由中的参数
+    if (url.q && url.target && props.target && url.target === props.target) {
       form.setValues(JSON.parse(url.q));
       handleSearch(false);
     }
-  }, [url]);
+  }, [url, props.target]);
 
   useEffect(() => {
     if (defaultParam) {
@@ -579,7 +580,6 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
   };
 
   const resetForm = async (type: boolean) => {
-    console.log('resetForm', type);
     const value = form.values;
     if (!expand) {
       value.terms1 = [defaultTerms(0), defaultTerms(1), defaultTerms(2)];

+ 1 - 1
src/pages/Northbound/DuerOS/Detail/index.tsx

@@ -61,7 +61,7 @@ const Save = () => {
     return _productTypes?.find((item: any) => item.id === _id);
   };
 
-  const getProduct = (f: Field) => {
+  const getProduct = (f?: Field) => {
     return service.getProduct(f?.value).then((resp) => {
       const _temp = resp.result.map((item: any) => ({ label: item.name, value: item.id }));
       Store.set('product-list', _temp);

+ 167 - 173
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 {
@@ -21,7 +22,7 @@ import { InstanceModel, service } from '@/pages/device/Instance';
 import _ from 'lodash';
 import { onlyMessage, randomString } from '@/utils/util';
 import { getMenuPathByCode, getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
-import PermissionButton from '@/components/PermissionButton';
+// import PermissionButton from '@/components/PermissionButton';
 import ManualInspection from './ManualInspection';
 import useHistory from '@/hooks/route/useHistory';
 interface Props {
@@ -34,10 +35,10 @@ const Status = observer((props: Props) => {
   const device = { ...InstanceModel.detail };
   const history = useHistory();
 
-  const productPermission = PermissionButton.usePermission('device/Product').permission;
-  const networkPermission = PermissionButton.usePermission('link/Type').permission;
-  const devicePermission = PermissionButton.usePermission('device/Instance').permission;
-  const accessPermission = PermissionButton.usePermission('link/AccessConfig').permission;
+  // const productPermission = PermissionButton.usePermission('device/Product').permission;
+  // const networkPermission = PermissionButton.usePermission('link/Type').permission;
+  // const devicePermission = PermissionButton.usePermission('device/Instance').permission;
+  // const accessPermission = PermissionButton.usePermission('link/AccessConfig').permission;
 
   const [artificialVisible, setArtificialVisible] = useState<boolean>(false);
   const [artificiaData, setArtificiaData] = useState<any>({});
@@ -135,37 +136,37 @@ const Status = observer((props: Props) => {
                           <Badge
                             status="default"
                             text={
-                              networkPermission.action ? (
-                                <span>
-                                  网络组件已禁用,请先
-                                  <Popconfirm
-                                    title="确认启用"
-                                    onConfirm={async () => {
-                                      const res = await service.startNetwork(
-                                        DiagnoseStatusModel.gateway?.channelId,
+                              // networkPermission.action ? (
+                              <span>
+                                网络组件已禁用,请先
+                                <Popconfirm
+                                  title="确认启用"
+                                  onConfirm={async () => {
+                                    const res = await service.startNetwork(
+                                      DiagnoseStatusModel.gateway?.channelId,
+                                    );
+                                    if (res.status === 200) {
+                                      onlyMessage('操作成功!');
+                                      DiagnoseStatusModel.list = modifyArrayList(
+                                        DiagnoseStatusModel.list,
+                                        {
+                                          key: 'network',
+                                          name: '网络组件',
+                                          desc: '诊断网络组件配置是否正确,配置错误将导致设备连接失败',
+                                          status: 'success',
+                                          text: '正常',
+                                          info: null,
+                                        },
                                       );
-                                      if (res.status === 200) {
-                                        onlyMessage('操作成功!');
-                                        DiagnoseStatusModel.list = modifyArrayList(
-                                          DiagnoseStatusModel.list,
-                                          {
-                                            key: 'network',
-                                            name: '网络组件',
-                                            desc: '诊断网络组件配置是否正确,配置错误将导致设备连接失败',
-                                            status: 'success',
-                                            text: '正常',
-                                            info: null,
-                                          },
-                                        );
-                                      }
-                                    }}
-                                  >
-                                    <a>启用</a>
-                                  </Popconfirm>
-                                </span>
-                              ) : (
-                                '暂无权限,请联系管理员'
-                              )
+                                    }
+                                  }}
+                                >
+                                  <a>启用</a>
+                                </Popconfirm>
+                              </span>
+                              // ) : (
+                              //   '暂无权限,请联系管理员'
+                              // )
                             }
                           />
                         </div>
@@ -248,37 +249,35 @@ const Status = observer((props: Props) => {
                           <Badge
                             status="default"
                             text={
-                              accessPermission.action ? (
-                                <span>
-                                  设备接入网关已禁用,请先
-                                  <Popconfirm
-                                    title="确认启用"
-                                    onConfirm={async () => {
-                                      const resp = await service.startGateway(
-                                        device.accessId || '',
+                              // accessPermission.action ? (
+                              <span>
+                                设备接入网关已禁用,请先
+                                <Popconfirm
+                                  title="确认启用"
+                                  onConfirm={async () => {
+                                    const resp = await service.startGateway(device.accessId || '');
+                                    if (resp.status === 200) {
+                                      onlyMessage('操作成功!');
+                                      DiagnoseStatusModel.list = modifyArrayList(
+                                        DiagnoseStatusModel.list,
+                                        {
+                                          key: 'gateway',
+                                          name: '设备接入网关',
+                                          desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+                                          status: 'success',
+                                          text: '正常',
+                                          info: null,
+                                        },
                                       );
-                                      if (resp.status === 200) {
-                                        onlyMessage('操作成功!');
-                                        DiagnoseStatusModel.list = modifyArrayList(
-                                          DiagnoseStatusModel.list,
-                                          {
-                                            key: 'gateway',
-                                            name: '设备接入网关',
-                                            desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
-                                            status: 'success',
-                                            text: '正常',
-                                            info: null,
-                                          },
-                                        );
-                                      }
-                                    }}
-                                  >
-                                    <a>启用</a>
-                                  </Popconfirm>
-                                </span>
-                              ) : (
-                                '暂无权限,请联系管理员处理'
-                              )
+                                    }
+                                  }}
+                                >
+                                  <a>启用</a>
+                                </Popconfirm>
+                              </span>
+                              // ) : (
+                              //   '暂无权限,请联系管理员处理'
+                              // )
                             }
                           />
                         </div>
@@ -321,35 +320,35 @@ const Status = observer((props: Props) => {
                     <Badge
                       status="default"
                       text={
-                        accessPermission.action ? (
-                          <span>
-                            设备接入网关已禁用,请先
-                            <Popconfirm
-                              title="确认启用"
-                              onConfirm={async () => {
-                                const resp = await service.startGateway(device.accessId || '');
-                                if (resp.status === 200) {
-                                  onlyMessage('操作成功!');
-                                  DiagnoseStatusModel.list = modifyArrayList(
-                                    DiagnoseStatusModel.list,
-                                    {
-                                      key: 'gateway',
-                                      name: '设备接入网关',
-                                      desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
-                                      status: 'success',
-                                      text: '正常',
-                                      info: null,
-                                    },
-                                  );
-                                }
-                              }}
-                            >
-                              <a>启用</a>
-                            </Popconfirm>
-                          </span>
-                        ) : (
-                          '暂无权限,请联系管理员处理'
-                        )
+                        // accessPermission.action ? (
+                        <span>
+                          设备接入网关已禁用,请先
+                          <Popconfirm
+                            title="确认启用"
+                            onConfirm={async () => {
+                              const resp = await service.startGateway(device.accessId || '');
+                              if (resp.status === 200) {
+                                onlyMessage('操作成功!');
+                                DiagnoseStatusModel.list = modifyArrayList(
+                                  DiagnoseStatusModel.list,
+                                  {
+                                    key: 'gateway',
+                                    name: '设备接入网关',
+                                    desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+                                    status: 'success',
+                                    text: '正常',
+                                    info: null,
+                                  },
+                                );
+                              }
+                            }}
+                          >
+                            <a>启用</a>
+                          </Popconfirm>
+                        </span>
+                        // ) : (
+                        //   '暂无权限,请联系管理员处理'
+                        // )
                       }
                     />
                   </div>
@@ -456,38 +455,36 @@ const Status = observer((props: Props) => {
                         <Badge
                           status="default"
                           text={
-                            productPermission.action ? (
-                              <span>
-                                产品已禁用,请
-                                <Popconfirm
-                                  title="确认启用"
-                                  onConfirm={async () => {
-                                    const resp = await service.deployProduct(
-                                      device.productId || '',
+                            // productPermission.action ? (
+                            <span>
+                              产品已禁用,请
+                              <Popconfirm
+                                title="确认启用"
+                                onConfirm={async () => {
+                                  const resp = await service.deployProduct(device.productId || '');
+                                  if (resp.status === 200) {
+                                    onlyMessage('操作成功!');
+                                    DiagnoseStatusModel.list = modifyArrayList(
+                                      DiagnoseStatusModel.list,
+                                      {
+                                        key: 'product',
+                                        name: '产品状态',
+                                        desc: '诊断产品状态是否正常,禁用状态将导致设备连接失败',
+                                        status: 'success',
+                                        text: '正常',
+                                        info: null,
+                                      },
                                     );
-                                    if (resp.status === 200) {
-                                      onlyMessage('操作成功!');
-                                      DiagnoseStatusModel.list = modifyArrayList(
-                                        DiagnoseStatusModel.list,
-                                        {
-                                          key: 'product',
-                                          name: '产品状态',
-                                          desc: '诊断产品状态是否正常,禁用状态将导致设备连接失败',
-                                          status: 'success',
-                                          text: '正常',
-                                          info: null,
-                                        },
-                                      );
-                                    }
-                                  }}
-                                >
-                                  <a>启用</a>
-                                </Popconfirm>
-                                产品
-                              </span>
-                            ) : (
-                              '暂无权限,请联系管理员处理'
-                            )
+                                  }
+                                }}
+                              >
+                                <a>启用</a>
+                              </Popconfirm>
+                              产品
+                            </span>
+                            // ) : (
+                            //   '暂无权限,请联系管理员处理'
+                            // )
                           }
                         />
                       </div>
@@ -541,36 +538,33 @@ const Status = observer((props: Props) => {
                   <Badge
                     status="default"
                     text={
-                      devicePermission.action ? (
-                        <span>
-                          设备已禁用,请
-                          <Popconfirm
-                            title="确认启用"
-                            onConfirm={async () => {
-                              const resp = await service.deployDevice(device?.id || '');
-                              if (resp.status === 200) {
-                                onlyMessage('操作成功!');
-                                DiagnoseStatusModel.list = modifyArrayList(
-                                  DiagnoseStatusModel.list,
-                                  {
-                                    key: 'device',
-                                    name: '设备状态',
-                                    desc: '诊断设备状态是否正常,禁用状态将导致设备连接失败',
-                                    status: 'success',
-                                    text: '正常',
-                                    info: null,
-                                  },
-                                );
-                              }
-                            }}
-                          >
-                            <a>启用</a>
-                          </Popconfirm>
-                          设备
-                        </span>
-                      ) : (
-                        '暂无权限,请联系管理员处理'
-                      )
+                      // devicePermission.action ? (
+                      <span>
+                        设备已禁用,请
+                        <Popconfirm
+                          title="确认启用"
+                          onConfirm={async () => {
+                            const resp = await service.deployDevice(device?.id || '');
+                            if (resp.status === 200) {
+                              onlyMessage('操作成功!');
+                              DiagnoseStatusModel.list = modifyArrayList(DiagnoseStatusModel.list, {
+                                key: 'device',
+                                name: '设备状态',
+                                desc: '诊断设备状态是否正常,禁用状态将导致设备连接失败',
+                                status: 'success',
+                                text: '正常',
+                                info: null,
+                              });
+                            }
+                          }}
+                        >
+                          <a>启用</a>
+                        </Popconfirm>
+                        设备
+                      </span>
+                      // ) : (
+                      //   '暂无权限,请联系管理员处理'
+                      // )
                     }
                   />
                 </div>
@@ -1096,23 +1090,23 @@ const Status = observer((props: Props) => {
                   <Badge
                     status="default"
                     text={
-                      accessPermission.view ? (
-                        <span>
-                          请根据
-                          <a
-                            onClick={() => {
-                              jumpAccessConfig();
-                            }}
-                          >
-                            设备接入配置
-                          </a>
-                          中${urlMap.get(device?.accessProvider) || ''}信息,任意上报一条数据
-                        </span>
-                      ) : (
-                        `请联系管理员提供${
-                          urlMap.get(device?.accessProvider) || ''
-                        }信息,并根据URL信息任意上报一条数据)`
-                      )
+                      // accessPermission.view ? (
+                      <span>
+                        请根据
+                        <a
+                          onClick={() => {
+                            jumpAccessConfig();
+                          }}
+                        >
+                          设备接入配置
+                        </a>
+                        中${urlMap.get(device?.accessProvider) || ''}信息,任意上报一条数据
+                      </span>
+                      // ) : (
+                      //   `请联系管理员提供${
+                      //     urlMap.get(device?.accessProvider) || ''
+                      //   }信息,并根据URL信息任意上报一条数据)`
+                      // )
                     }
                   />,
                 );

+ 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}`, {

+ 5 - 1
src/pages/system/Department/Detail/index.tsx

@@ -11,5 +11,9 @@ export default () => {
   const location = useLocation<LocationType>();
   const params: any = new URLSearchParams(location.search);
 
-  return <PageContainer>{params.get('type') === 'assets' ? <Assets /> : <Member />}</PageContainer>;
+  return (
+    <PageContainer>
+      {params.get('type') === 'assets' ? <Assets parentId={''} /> : <Member parentId={''} />}
+    </PageContainer>
+  );
 };

+ 1 - 1
src/pages/system/Department/index.less

@@ -14,7 +14,6 @@
 
       .border-left {
         padding-right: 24px;
-        border-right: 1px solid #f0f0f0;
       }
 
       .left-tree-content {
@@ -69,6 +68,7 @@
       flex-grow: 1;
       width: 0;
       padding-left: 24px;
+      border-left: 1px solid #f0f0f0;
     }
   }
 }

+ 5 - 5
src/pages/system/Menu/components/permission.tsx

@@ -161,8 +161,8 @@ export default (props: PermissionType) => {
   // };
 
   const parentChange = (value: ParentNodeChange) => {
-    let indeterminateCount = 0;
-    let _checkAll = 0;
+    // let indeterminateCount = 0;
+    // let _checkAll = 0;
     const list = checkListRef.current.map((item) => {
       const _checked = item.id === value.id ? value.checkedAll : item.checked;
       const _state = item.id === value.id ? value.state : item.state;
@@ -172,11 +172,11 @@ export default (props: PermissionType) => {
           : item.actions;
       if (_checked) {
         // 父checkbox为全选或者有子节点被选中
-        _checkAll += 1;
-        indeterminateCount += 1;
+        // _checkAll += 1;
+        // indeterminateCount += 1;
       } else if (_state) {
         // 父checkbox下
-        indeterminateCount += 1;
+        // indeterminateCount += 1;
       }
 
       return {

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

@@ -21,6 +21,7 @@ import moment from 'moment';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { PermissionButton } from '@/components';
 import { useDomFullHeight } from '@/hooks';
+import { onlyMessage } from '@/utils/util';
 
 export const service = new Service('menu');
 

+ 5 - 3
src/pages/system/Platforms/save.tsx

@@ -25,6 +25,7 @@ import { action } from '@formily/reactive';
 import type { Response } from '@/utils/typings';
 import { service } from '@/pages/system/Platforms/index';
 import { onlyMessage, randomString } from '@/utils/util';
+import { getMenuPathByCode } from '@/utils/menu';
 
 interface SaveProps {
   visible: boolean;
@@ -36,7 +37,7 @@ interface SaveProps {
 
 export default (props: SaveProps) => {
   const [loading, setLoading] = useState(false);
-  const { permission: deptPermission } = usePermissions('system/Department');
+  const { permission: RolePermission } = usePermissions('system/Role');
 
   const SchemaField = createSchemaField({
     components: {
@@ -320,9 +321,10 @@ export default (props: SaveProps) => {
                 <PermissionButton
                   type="link"
                   style={{ padding: 0 }}
-                  isPermission={deptPermission.add}
+                  isPermission={RolePermission.add}
                   onClick={() => {
-                    const tab: any = window.open(`${origin}/#/system/role?save=true`);
+                    const router = getMenuPathByCode('system/Role');
+                    const tab: any = window.open(`${origin}/#${router}?save=true`);
                     tab!.onTabSaveSuccess = (value: any) => {
                       form.setFieldState('roleIdList', async (state) => {
                         state.dataSource = await getRole().then((resp: any) =>

+ 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>
   );