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

Merge branch 'next' into next-xyh

xieyonghong 3 лет назад
Родитель
Сommit
c6aedd8250
90 измененных файлов с 1288 добавлено и 648 удалено
  1. BIN
      public/images/init-home/data-disabled.png
  2. BIN
      public/images/init-home/data-enabled.png
  3. BIN
      public/images/init-home/menu.png
  4. 1 0
      src/components/BaseCrud/index.tsx
  5. 1 0
      src/components/BindParentDevice/index.tsx
  6. 1 0
      src/components/BindUser/Bound.tsx
  7. 1 0
      src/components/BindUser/Unbound.tsx
  8. 1 0
      src/components/FSelectDevice/index.tsx
  9. 29 15
      src/components/FSelectDevices/index.tsx
  10. 1 1
      src/components/FUpload/index.tsx
  11. 2 6
      src/components/ProTableCard/CardItems/device.tsx
  12. 1 3
      src/components/ProTableCard/CardItems/noticeConfig.tsx
  13. 1 3
      src/components/ProTableCard/CardItems/product.tsx
  14. 1 0
      src/components/ProTableCard/index.tsx
  15. 1 0
      src/pages/Log/Access/index.tsx
  16. 1 0
      src/pages/Log/System/index.tsx
  17. 1 0
      src/pages/account/NotificationRecord/index.tsx
  18. 1 0
      src/pages/account/NotificationSubscription/index.tsx
  19. 1 0
      src/pages/device/Alarm/index.tsx
  20. 1 0
      src/pages/device/Category/index.tsx
  21. 1 0
      src/pages/device/Command/index.tsx
  22. 1 0
      src/pages/device/Firmware/Task/Detail/index.tsx
  23. 40 31
      src/pages/device/Firmware/Task/Save/index.tsx
  24. 19 4
      src/pages/device/Firmware/Task/index.tsx
  25. 21 2
      src/pages/device/Firmware/index.tsx
  26. 5 2
      src/pages/device/Firmware/service.ts
  27. 1 0
      src/pages/device/Instance/Detail/ChildDevice/BindChildDevice/index.tsx
  28. 1 0
      src/pages/device/Instance/Detail/ChildDevice/index.tsx
  29. 1 0
      src/pages/device/Instance/Detail/Log/index.tsx
  30. 1 0
      src/pages/device/Instance/Detail/MetadataLog/Event/index.tsx
  31. 1 0
      src/pages/device/Instance/Detail/Modbus/index.tsx
  32. 1 0
      src/pages/device/Instance/Detail/Opcua/index.tsx
  33. 1 0
      src/pages/device/Instance/Detail/Running/Event/index.tsx
  34. 1 0
      src/pages/device/components/Alarm/Record/index.tsx
  35. 6 1
      src/pages/document.ejs
  36. 1 0
      src/pages/home/components/DeviceChoose.tsx
  37. 88 0
      src/pages/init-home/components/basis.tsx
  38. 37 0
      src/pages/init-home/components/data/index.tsx
  39. 219 0
      src/pages/init-home/components/data/save/index.tsx
  40. 12 0
      src/pages/init-home/components/menu.tsx
  41. 5 0
      src/pages/init-home/components/role.tsx
  42. 13 7
      src/pages/init-home/index.less
  43. 48 14
      src/pages/init-home/index.tsx
  44. 50 0
      src/pages/init-home/service.ts
  45. 1 0
      src/pages/link/Certificate/index.tsx
  46. 1 0
      src/pages/link/Channel/Modbus/Access/bindDevice/index.tsx
  47. 1 0
      src/pages/link/Channel/Modbus/Access/index.tsx
  48. 1 0
      src/pages/link/Channel/Modbus/index.tsx
  49. 1 0
      src/pages/link/Channel/Opcua/Access/bindDevice/index.tsx
  50. 1 0
      src/pages/link/Channel/Opcua/Access/index.tsx
  51. 1 0
      src/pages/link/Channel/Opcua/index.tsx
  52. 1 0
      src/pages/link/Channel/new.tsx
  53. 1 0
      src/pages/media/Cascade/Channel/BindChannel/index.tsx
  54. 1 0
      src/pages/media/Cascade/Channel/index.tsx
  55. 1 0
      src/pages/media/Device/Channel/index.tsx
  56. 1 0
      src/pages/media/Home/deviceModal.tsx
  57. 1 0
      src/pages/notice/Config/Log/index.tsx
  58. 1 0
      src/pages/notice/Config/SyncUser/index.tsx
  59. 1 0
      src/pages/notice/Template/Log/index.tsx
  60. 19 13
      src/pages/rule-engine/Alarm/Config/Save/input.tsx
  61. 20 17
      src/pages/rule-engine/Alarm/Config/Save/output.tsx
  62. 38 10
      src/pages/rule-engine/Alarm/Config/index.tsx
  63. 30 0
      src/pages/rule-engine/Alarm/Configuration/index.tsx
  64. 1 0
      src/pages/rule-engine/Alarm/Log/Detail/index.tsx
  65. 1 0
      src/pages/rule-engine/Alarm/Log/SolveLog/index.tsx
  66. 1 0
      src/pages/rule-engine/Scene/Save/action/device/deviceModal.tsx
  67. 1 0
      src/pages/system/DataSource/index.tsx
  68. 2 2
      src/pages/system/Department/Assets/permissionModal.tsx
  69. 1 0
      src/pages/system/Department/Assets/productCategory/bind.tsx
  70. 1 0
      src/pages/system/Department/Assets/productCategory/index.tsx
  71. 1 0
      src/pages/system/Department/Member/bind.tsx
  72. 1 0
      src/pages/system/Department/Member/index.tsx
  73. 1 0
      src/pages/system/Menu/Detail/buttons.tsx
  74. 2 3
      src/pages/system/Menu/Setting/DragItem.less
  75. 293 293
      src/pages/system/Menu/Setting/baseMenu.ts
  76. 51 46
      src/pages/system/Menu/Setting/dragItem.tsx
  77. 2 2
      src/pages/system/Menu/Setting/index.less
  78. 103 101
      src/pages/system/Menu/Setting/index.tsx
  79. 71 69
      src/pages/system/Menu/Setting/tree.tsx
  80. 1 0
      src/pages/system/Menu/index.tsx
  81. 1 1
      src/pages/system/Menu/service.ts
  82. 2 1
      src/pages/system/Permission/index.tsx
  83. 1 0
      src/pages/system/Platforms/index.tsx
  84. 1 0
      src/pages/system/Relationship/index.tsx
  85. 1 0
      src/pages/system/Role/Detail/UserManage/BindUser.tsx
  86. 1 0
      src/pages/system/Role/Detail/UserManage/index.tsx
  87. 2 1
      src/pages/system/Role/index.tsx
  88. 1 0
      src/pages/system/Tenant/Detail/Member/Bind.tsx
  89. 1 0
      src/pages/system/Tenant/Detail/Member/index.tsx
  90. 1 0
      src/pages/system/User/index.tsx

BIN
public/images/init-home/data-disabled.png


BIN
public/images/init-home/data-enabled.png


BIN
public/images/init-home/menu.png


+ 1 - 0
src/components/BaseCrud/index.tsx

@@ -96,6 +96,7 @@ const BaseCrud = <T extends Record<string, any>>(props: Props<T>) => {
           columns={columns}
           actionRef={actionRef}
           scroll={scroll}
+          columnEmptyText={''}
           options={{ fullScreen: true }}
           request={
             request ||

+ 1 - 0
src/components/BindParentDevice/index.tsx

@@ -178,6 +178,7 @@ const BindParentDevice = (props: Props) => {
         actionRef={actionRef}
         params={searchParams}
         rowKey="id"
+        columnEmptyText={''}
         toolBarRender={false}
         pagination={{
           pageSize: 10,

+ 1 - 0
src/components/BindUser/Bound.tsx

@@ -128,6 +128,7 @@ const Bound = observer(() => {
         pagination={{
           pageSize: 10,
         }}
+        columnEmptyText={''}
         request={async (params) => service.query(params)}
         defaultParams={{
           [`id$in-dimension$${BindModel.dimension.type}`]: BindModel.dimension.id,

+ 1 - 0
src/components/BindUser/Unbound.tsx

@@ -112,6 +112,7 @@ const Unbound = observer(() => {
             }));
           },
         }}
+        columnEmptyText={''}
         tableAlertRender={({ selectedRowKeys, onCleanSelected }) => (
           <Space size={24}>
             <span>

+ 1 - 0
src/components/FSelectDevice/index.tsx

@@ -105,6 +105,7 @@ const FSelectDevice = connect((props: Props) => {
             pagination={{
               pageSize: 10,
             }}
+            columnEmptyText={''}
             columns={columns}
             actionRef={actionRef}
             request={(params) => service.query(params)}

+ 29 - 15
src/components/FSelectDevices/index.tsx

@@ -9,6 +9,7 @@ import type { DeviceInstance } from '@/pages/device/Instance/typings';
 import moment from 'moment';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import Service from '@/pages/device/Instance/service';
+import SearchComponent from '../SearchComponent';
 
 interface Props {
   value: Partial<DeviceInstance>[];
@@ -21,12 +22,13 @@ const FSelectDevices = connect((props: Props) => {
   const [visible, setVisible] = useState<boolean>(false);
   const intl = useIntl();
   const actionRef = useRef<ActionType>();
+  const [searchParam, setSearchParam] = useState({});
   const columns: ProColumns<DeviceInstance>[] = [
-    {
-      dataIndex: 'index',
-      valueType: 'indexBorder',
-      width: 48,
-    },
+    // {
+    //   dataIndex: 'index',
+    //   valueType: 'indexBorder',
+    //   width: 48,
+    // },
     {
       title: 'ID',
       dataIndex: 'id',
@@ -54,18 +56,18 @@ const FSelectDevices = connect((props: Props) => {
       }),
       dataIndex: 'registryTime',
       width: '200px',
-      render: (text: any) => (text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
+      render: (text: any) => (text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : ''),
       sorter: true,
     },
-    {
-      title: intl.formatMessage({
-        id: 'pages.table.description',
-        defaultMessage: '说明',
-      }),
-      dataIndex: 'description',
-      width: '15%',
-      ellipsis: true,
-    },
+    // {
+    //   title: intl.formatMessage({
+    //     id: 'pages.table.description',
+    //     defaultMessage: '说明',
+    //   }),
+    //   dataIndex: 'description',
+    //   width: '15%',
+    //   ellipsis: true,
+    // },
   ];
 
   const [data, setData] = useState<Partial<DeviceInstance>[]>(props.value);
@@ -95,17 +97,29 @@ const FSelectDevices = connect((props: Props) => {
             props.onChange(data);
           }}
         >
+          <SearchComponent<DeviceInstance>
+            field={columns}
+            enableSave={false}
+            model="simple"
+            onSearch={async (data1) => {
+              setSearchParam(data1);
+            }}
+            target="choose-device"
+          />
           <ProTable<DeviceInstance>
             tableAlertRender={false}
             rowSelection={{
               type: 'checkbox',
               ...rowSelection,
             }}
+            search={false}
+            columnEmptyText={''}
             toolBarRender={false}
             rowKey="id"
             pagination={{
               pageSize: 10,
             }}
+            params={searchParam}
             columns={columns}
             actionRef={actionRef}
             request={(params) => service.query(params)}

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

@@ -22,7 +22,7 @@ const FUpload = connect((props: Props) => {
       const result = info.file.response?.result;
       const f = {
         ...result,
-        url: `${location.protocol}://${SystemConst.API_BASE}/file/${result?.id}?accessKey=${result?.others?.accessKey}`,
+        url: `${location.protocol}//${SystemConst.API_BASE}/file/${result?.id}?accessKey=${result?.others?.accessKey}`,
       };
       setUrl(f.url);
       props.onChange(f);

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

@@ -87,9 +87,7 @@ export const ExtraDeviceCard = (props: DeviceCardProps) => {
             ) : (
               <div className={'flex-auto'}>
                 <label>资产权限</label>
-                <Ellipsis
-                  title={handlePermissionsMap(props.grantedPermissions)}
-                />
+                <Ellipsis title={handlePermissionsMap(props.grantedPermissions)} />
                 {/*<div className={'ellipsis'}>*/}
                 {/*  <Tooltip title={handlePermissionsMap(props.grantedPermissions)}>*/}
                 {/*    {handlePermissionsMap(props.grantedPermissions)}*/}
@@ -133,9 +131,7 @@ export default (props: DeviceCardProps) => {
           <div className={'card-item-content'}>
             <div>
               <label>设备类型</label>
-              <Ellipsis
-                title={props.deviceType ? props.deviceType.text : ''}
-              />
+              <Ellipsis title={props.deviceType ? props.deviceType.text : ''} />
               {/*<div className={'ellipsis'}>{props.deviceType ? props.deviceType.text : ''}</div>*/}
             </div>
             <div>

+ 1 - 3
src/components/ProTableCard/CardItems/noticeConfig.tsx

@@ -29,9 +29,7 @@ export default (props: NoticeCardProps) => {
           <div className={'card-item-content'}>
             <div>
               <label>通知方式</label>
-              <Ellipsis
-                title={typeList[props.type][props.provider] || '暂无'}
-              />
+              <Ellipsis title={typeList[props.type][props.provider] || '暂无'} />
               {/*<div className={'ellipsis'}>{typeList[props.type][props.provider] || '暂无'}</div>*/}
             </div>
             <div>

+ 1 - 3
src/components/ProTableCard/CardItems/product.tsx

@@ -91,9 +91,7 @@ export const ExtraProductCard = (props: ProductCardProps) => {
             ) : (
               <div className={'flex-auto'}>
                 <label>资产权限</label>
-                <Ellipsis
-                  title={handlePermissionsMap(props.grantedPermissions)}
-                />
+                <Ellipsis title={handlePermissionsMap(props.grantedPermissions)} />
               </div>
             )}
           </div>

+ 1 - 0
src/components/ProTableCard/index.tsx

@@ -172,6 +172,7 @@ const ProTableCard = <
             pageSize,
           } as any
         }
+        columnEmptyText={''}
         className={'pro-table-card-body'}
         options={model === ModelEnum.CARD ? false : props.options}
         request={async (param, sort, filter) => {

+ 1 - 0
src/pages/Log/Access/index.tsx

@@ -132,6 +132,7 @@ const Access = () => {
       <ProTable<AccessLogItem>
         columns={columns}
         params={param}
+        columnEmptyText={''}
         tableClassName={'accessLog'}
         tableStyle={{ minHeight }}
         scroll={{ x: 1366 }}

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

@@ -123,6 +123,7 @@ const System = () => {
       <ProTable<SystemLogItem>
         columns={columns}
         params={param}
+        columnEmptyText={''}
         scroll={{ x: 1366 }}
         tableClassName={'systemLog'}
         tableStyle={{ minHeight }}

+ 1 - 0
src/pages/account/NotificationRecord/index.tsx

@@ -186,6 +186,7 @@ const NotificationRecord = observer(() => {
         search={false}
         tableClassName={'record'}
         tableStyle={{ minHeight }}
+        columnEmptyText={''}
         request={async (params) =>
           service.queryList(encodeQuery({ ...params, sorts: { notifyTime: 'desc' } }))
         }

+ 1 - 0
src/pages/account/NotificationSubscription/index.tsx

@@ -185,6 +185,7 @@ const NotificationSubscription = observer(() => {
         columns={columns}
         scroll={{ x: 1366 }}
         search={false}
+        columnEmptyText={''}
         tableClassName={'subscription'}
         tableStyle={{ minHeight }}
         rowKey="id"

+ 1 - 0
src/pages/device/Alarm/index.tsx

@@ -175,6 +175,7 @@ const Alarm = () => {
         pagination={{
           pageSize: 10,
         }}
+        columnEmptyText={''}
         actionRef={actionRef}
       />
     </PageContainer>

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

@@ -179,6 +179,7 @@ const Category = observer(() => {
       <ProTable
         params={param}
         search={false}
+        columnEmptyText={''}
         request={async (params) => {
           const response = await service.queryTree({
             paging: false,

+ 1 - 0
src/pages/device/Command/index.tsx

@@ -198,6 +198,7 @@ const Command = observer(() => {
         columns={columns}
         actionRef={actionRef}
         rowKey="id"
+        columnEmptyText={''}
       />
       <Create
         visible={state.visible}

+ 1 - 0
src/pages/device/Firmware/Task/Detail/index.tsx

@@ -157,6 +157,7 @@ const Detail = observer(() => {
         tableClassName={'firmware-task-detail'}
         tableStyle={{ minHeight }}
         search={false}
+        columnEmptyText={''}
         params={param}
         request={async (params) =>
           service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })

+ 40 - 31
src/pages/device/Firmware/Task/Save/index.tsx

@@ -1,48 +1,43 @@
 import { Modal } from 'antd';
 import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 import { createSchemaField } from '@formily/react';
-import {
-  Form,
-  FormGrid,
-  FormItem,
-  Input,
-  Select,
-  ArrayTable,
-  NumberPicker,
-  Radio,
-} from '@formily/antd';
-import { createForm, onFieldValueChange } from '@formily/core';
+import { Form, FormGrid, FormItem, Input, Select, NumberPicker, Radio } from '@formily/antd';
+import { createForm, onFieldValueChange, onFormInit } from '@formily/core';
 import type { ISchema } from '@formily/json-schema';
-import FUpload from '@/components/Upload';
 import { service } from '@/pages/device/Firmware';
-import type { Response } from '@/utils/typings';
-import { useRef } from 'react';
-import type { ProductItem } from '@/pages/device/Product/typings';
+import { useEffect, useRef } from 'react';
 import { onlyMessage } from '@/utils/util';
 import FSelectDevices from '@/components/FSelectDevices';
+import type { DeviceInstance } from '@/pages/device/Instance/typings';
 
 interface Props {
+  ids: { id: string; productId: string };
   data?: FirmwareItem;
   close: () => void;
+  save: () => void;
   visible: boolean;
 }
 
 const Save = (props: Props) => {
-  const { data, close, visible } = props;
+  const { data, close, visible, ids } = props;
 
   const form = createForm({
     validateFirst: true,
     initialValues: data,
     effects() {
+      onFormInit(async (form1) => {
+        if (!data?.id) return;
+        form1.setInitialValues({ ...data, upload: { url: data?.url } });
+      });
       onFieldValueChange('mode', async (field) => {
         field
-          .query('timeoutSeconds1')
+          .query('timeoutSeconds')
           .take()
           .setDecoratorProps({
             gridSpan: field.value === 'push' ? 1 : 2,
           });
         field
-          .query('timeoutSeconds')
+          .query('responseTimeoutSeconds')
           .take()
           .setDecoratorProps({
             gridSpan: field.value === 'push' ? 1 : 2,
@@ -56,33 +51,47 @@ const Save = (props: Props) => {
     },
   });
 
-  const products = useRef<ProductItem[]>([]);
+  const devices = useRef<DeviceInstance[]>([]);
 
   const SchemaField = createSchemaField({
     components: {
       FormItem,
       FormGrid,
       Input,
-      FUpload,
       Select,
-      ArrayTable,
       NumberPicker,
       Radio,
       FSelectDevices,
     },
   });
 
+  useEffect(() => {
+    if (visible) {
+      service.queryDevice().then((resp) => {
+        if (resp.status === 200) {
+          devices.current = resp.result;
+        }
+      });
+    }
+  }, [visible]);
+
   const save = async () => {
-    const values: FirmwareItem = await form.submit();
-    const product = products.current?.find((item) => item.id === values.productId);
-    values.productName = product?.name || '';
-    const resp = (await service.save(values)) as Response<FirmwareItem>;
+    const values: any = await form.submit();
+    if (values?.releaseType === 'all') {
+      values.deviceId = devices.current.map((item) => item.id);
+    }
+    const resp = await service.saveTask({
+      ...values,
+      firmwareId: ids?.id,
+      productId: ids?.productId,
+    });
     if (resp.status === 200) {
       onlyMessage('保存成功!');
     } else {
       onlyMessage('保存失败!', 'error');
     }
   };
+
   const schema: ISchema = {
     type: 'object',
     properties: {
@@ -138,10 +147,10 @@ const Save = (props: Props) => {
               },
             ],
           },
-          timeoutSeconds: {
+          responseTimeoutSeconds: {
             title: '响应超时时间',
             'x-decorator': 'FormItem',
-            'x-component': 'Input',
+            'x-component': 'NumberPicker',
             'x-component-props': {
               placeholder: '请输入响应超时时间(秒)',
             },
@@ -166,10 +175,10 @@ const Save = (props: Props) => {
               },
             },
           },
-          timeoutSeconds1: {
+          timeoutSeconds: {
             title: '升级超时时间',
             'x-decorator': 'FormItem',
-            'x-component': 'Input',
+            'x-component': 'NumberPicker',
             'x-component-props': {
               placeholder: '请输入升级超时时间(秒)',
             },
@@ -221,7 +230,7 @@ const Save = (props: Props) => {
               },
             },
           },
-          part: {
+          deviceId: {
             title: '选择设备',
             'x-decorator': 'FormItem',
             'x-component': 'FSelectDevices',
@@ -265,7 +274,7 @@ const Save = (props: Props) => {
     <Modal
       maskClosable={false}
       width="50vw"
-      title="新增任务"
+      title={data?.id ? '编辑任务' : '新增任务'}
       onCancel={() => close()}
       onOk={() => save()}
       visible={visible}

+ 19 - 4
src/pages/device/Firmware/Task/index.tsx

@@ -4,8 +4,8 @@ import ProTable from '@jetlinks/pro-table';
 import { Popconfirm, Tooltip } from 'antd';
 import { useRef, useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import { EditOutlined, EyeOutlined, MinusOutlined, PlusOutlined } from '@ant-design/icons';
-import { Link, useHistory } from 'umi';
+import { DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined } from '@ant-design/icons';
+import { Link, useHistory, useLocation } from 'umi';
 import { model } from '@formily/reactive';
 import { observer } from '@formily/react';
 import type { FirmwareItem } from '@/pages/device/Firmware/typings';
@@ -31,6 +31,9 @@ const Task = observer(() => {
   const { permission } = usePermissions('device/Firmware');
   const [param, setParam] = useState({});
   const history = useHistory<Record<string, string>>();
+  const location = useLocation<{ id: string }>();
+  const id = (location as any).query?.id || '';
+  const productId = (location as any).query?.productId || '';
 
   const columns: ProColumns<FirmwareItem>[] = [
     {
@@ -89,6 +92,7 @@ const Task = observer(() => {
           key="editable"
           onClick={() => {
             state.visible = true;
+            state.current = record;
           }}
         >
           <Tooltip
@@ -123,7 +127,7 @@ const Task = observer(() => {
                 defaultMessage: '删除',
               })}
             >
-              <MinusOutlined />
+              <DeleteOutlined />
             </Tooltip>
           </Popconfirm>
         </a>,
@@ -141,6 +145,7 @@ const Task = observer(() => {
           actionRef.current?.reset?.();
           setParam(data);
         }}
+        defaultParam={[{ column: 'firmwareId', value: id }]}
       />
       <ProTable<FirmwareItem>
         scroll={{ x: 1366 }}
@@ -148,6 +153,8 @@ const Task = observer(() => {
         tableStyle={{ minHeight }}
         search={false}
         params={param}
+        rowKey="id"
+        columnEmptyText={''}
         headerTitle={
           <div>
             <PermissionButton
@@ -167,14 +174,22 @@ const Task = observer(() => {
           </div>
         }
         request={async (params) =>
-          service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+          service.task({
+            ...params,
+            sorts: [{ name: 'createTime', order: 'desc' }],
+          })
         }
         columns={columns}
         actionRef={actionRef}
       />
       <Save
         data={state.current}
+        ids={{ id: id, productId: productId }}
         visible={state.visible}
+        save={() => {
+          state.visible = false;
+          actionRef.current?.reload?.();
+        }}
         close={() => {
           state.visible = false;
         }}

+ 21 - 2
src/pages/device/Firmware/index.tsx

@@ -58,6 +58,14 @@ const Firmware = observer(() => {
       }),
       ellipsis: true,
       dataIndex: 'productName',
+      valueType: 'select',
+      request: () =>
+        service.queryProduct().then((resp: any) =>
+          (resp?.result || []).map((item: any) => ({
+            label: item.name,
+            value: item.id,
+          })),
+        ),
     },
     {
       title: intl.formatMessage({
@@ -65,7 +73,18 @@ const Firmware = observer(() => {
         defaultMessage: '签名方式',
       }),
       ellipsis: true,
+      valueType: 'select',
       dataIndex: 'signMethod',
+      valueEnum: {
+        md5: {
+          text: 'MD5',
+          status: 'md5',
+        },
+        sha256: {
+          text: 'SHA256',
+          status: 'sha256',
+        },
+      },
     },
     {
       title: intl.formatMessage({
@@ -105,8 +124,8 @@ const Firmware = observer(() => {
           isPermission={permission.action}
           key="upgrade"
           onClick={() => {
-            const url = getMenuPathByParams(MENUS_CODE['device/Firmware/Task'], record?.id);
-            history.push(url);
+            const url = `${getMenuPathByParams(MENUS_CODE['device/Firmware/Task'])}`;
+            history.push(`${url}?id=${record?.id}&productId=${record?.productId}`);
           }}
           tooltip={{
             title: '升级任务',

+ 5 - 2
src/pages/device/Firmware/service.ts

@@ -6,8 +6,8 @@ import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 class Service extends BaseService<FirmwareItem> {
   task = (params: Record<string, unknown>) =>
     request(`/${SystemConst.API_BASE}/firmware/upgrade/task/_query`, {
-      method: 'GET',
-      params,
+      method: 'POST',
+      data: params,
     });
 
   saveTask = (data: Record<string, unknown>) =>
@@ -39,6 +39,9 @@ class Service extends BaseService<FirmwareItem> {
 
   queryProduct = () =>
     request(`/${SystemConst.API_BASE}/device/product/_query/no-paging?paging=false`);
+
+  queryDevice = () =>
+    request(`/${SystemConst.API_BASE}/device/instance/_query/no-paging?paging=false`);
 }
 
 export default Service;

+ 1 - 0
src/pages/device/Instance/Detail/ChildDevice/BindChildDevice/index.tsx

@@ -164,6 +164,7 @@ const BindChildDevice = (props: Props) => {
         search={false}
         columns={columns}
         size="small"
+        columnEmptyText={''}
         rowSelection={{
           selectedRowKeys: bindKeys,
           onChange: (selectedRowKeys, selectedRows) => {

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

@@ -164,6 +164,7 @@ const ChildDevice = () => {
         actionRef={actionRef}
         params={searchParams}
         rowKey="id"
+        columnEmptyText={''}
         rowSelection={{
           selectedRowKeys: bindKeys,
           onChange: (selectedRowKeys, selectedRows) => {

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

@@ -99,6 +99,7 @@ const Log = () => {
         search={false}
         columns={columns}
         size="small"
+        columnEmptyText={''}
         actionRef={actionRef}
         params={searchParams}
         toolBarRender={false}

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

@@ -47,6 +47,7 @@ const EventLog = (props: Props) => {
       <ProTable
         size="small"
         rowKey="id"
+        columnEmptyText={''}
         toolBarRender={false}
         request={async (param) =>
           service.getEventCount(params.id, data.id!, {

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

@@ -345,6 +345,7 @@ const Modbus = () => {
             params={param}
             columns={columns}
             rowKey="id"
+            columnEmptyText={''}
             search={false}
             headerTitle={
               <>

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

@@ -362,6 +362,7 @@ const Opcua = () => {
             params={param}
             columns={columns}
             rowKey="id"
+            columnEmptyText={''}
             search={false}
             headerTitle={
               <>

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

@@ -132,6 +132,7 @@ const EventLog = (props: Props) => {
         rowKey="id"
         actionRef={actionRef}
         search={false}
+        columnEmptyText={''}
         params={searchParams}
         request={async (param) => {
           param.pageIndex = param.current - 1;

+ 1 - 0
src/pages/device/components/Alarm/Record/index.tsx

@@ -111,6 +111,7 @@ const Record = (props: Props) => {
         actionRef={actionRef}
         columns={columns}
         rowKey="id"
+        columnEmptyText={''}
         request={(param) => service.record(param)}
         pagination={{
           pageSize: 10,

+ 6 - 1
src/pages/document.ejs

@@ -13,7 +13,12 @@
       content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
     />
     <title>Jetlinks</title>
-    <link rel="icon" id="ico" href="<%= context.config.publicPath + 'favicon.ico' %>" type="image/x-icon" />
+    <link
+      rel="icon"
+      id="ico"
+      href="<%= context.config.publicPath + 'favicon.ico' %>"
+      type="image/x-icon"
+    />
   </head>
   <body>
     <noscript>

+ 1 - 0
src/pages/home/components/DeviceChoose.tsx

@@ -134,6 +134,7 @@ export default (props: DeviceModalProps) => {
         columns={columns}
         rowKey={'id'}
         search={false}
+        columnEmptyText={''}
         request={(params) =>
           service.query({
             ...params,

+ 88 - 0
src/pages/init-home/components/basis.tsx

@@ -0,0 +1,88 @@
+import { UploadImage } from '@/components';
+import { Col, Form, Input, Row, Select } from 'antd';
+import { useEffect } from 'react';
+
+interface Props {
+  getData: Function;
+}
+
+const Basis = (props: Props) => {
+  const [form] = Form.useForm();
+
+  useEffect(() => {
+    props.getData(form);
+  }, []);
+
+  return (
+    <Form layout="vertical" form={form}>
+      <Row gutter={[24, 24]}>
+        <Col span={10}>
+          <Form.Item label="系统名称" name="title">
+            <Input />
+          </Form.Item>
+          <Form.Item
+            label="主题色"
+            name="headerTheme"
+            initialValue="light"
+            rules={[{ required: true, message: '请选择主题色' }]}
+          >
+            <Select>
+              <Select.Option value="light">白色</Select.Option>
+              <Select.Option value="dark">黑色</Select.Option>
+            </Select>
+          </Form.Item>
+          <Form.Item label="高德API Key" name="apikey" tooltip="配置后平台可调用高德地图GIS服务">
+            <Input />
+          </Form.Item>
+          <Row gutter={[24, 24]}>
+            <Col>
+              <Form.Item
+                name={'logo'}
+                label="系统logo"
+                extra={
+                  <>
+                    <div>推荐尺寸200*200</div>
+                    <div>支持jpg,png</div>
+                  </>
+                }
+              >
+                <UploadImage />
+              </Form.Item>
+            </Col>
+            <Col>
+              <Form.Item
+                name={'ico'}
+                label="浏览器页签"
+                tooltip="浏览器tab页中显示的图片元素"
+                extra={
+                  <>
+                    <div>推荐尺寸64*64</div>
+                    <div>支持ico格式</div>
+                  </>
+                }
+              >
+                <UploadImage size={1} types={['image/x-icon']} backgroundSize={'inherit'} />
+              </Form.Item>
+            </Col>
+          </Row>
+        </Col>
+        <Col span={14}>
+          <Form.Item
+            name={'backgroud'}
+            label="登录背景图"
+            extra={
+              <>
+                <div>支持4M以内的图片:支持jpg、png</div>
+                <div>建议尺寸1400x1080</div>
+              </>
+            }
+            rules={[{ required: true, message: '请上传背景图' }]}
+          >
+            <UploadImage size={4} style={{ width: 570, height: 415 }} />
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form>
+  );
+};
+export default Basis;

+ 37 - 0
src/pages/init-home/components/data/index.tsx

@@ -0,0 +1,37 @@
+import { useState } from 'react';
+// import { service } from '../index';
+import Save from './save';
+
+const Data = () => {
+  const [flag, setFlag] = useState<boolean>(false);
+  const [visible, setVisible] = useState<boolean>(false);
+
+  return (
+    <div>
+      <img
+        style={{ width: 300 }}
+        onClick={() => {
+          setVisible(true);
+        }}
+        src={
+          flag
+            ? require('/public/images/init-home/data-enabled.png')
+            : require('/public/images/init-home/data-disabled.png')
+        }
+      />
+      {visible && (
+        <Save
+          close={() => {
+            setVisible(false);
+          }}
+          save={() => {
+            setVisible(false);
+            setFlag(true);
+          }}
+        />
+      )}
+    </div>
+  );
+};
+
+export default Data;

+ 219 - 0
src/pages/init-home/components/data/save/index.tsx

@@ -0,0 +1,219 @@
+import { Modal } from 'antd';
+import { createSchemaField } from '@formily/react';
+import { Form, FormGrid, FormItem, Input, Select, NumberPicker } from '@formily/antd';
+import { onFormInit } from '@formily/core';
+import { createForm } from '@formily/core';
+import type { ISchema } from '@formily/json-schema';
+import { service } from '../../../index';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+
+interface Props {
+  data?: any;
+  close: () => void;
+  save: () => void;
+}
+
+const Save = (props: Props) => {
+  const { close } = props;
+
+  const form = createForm({
+    validateFirst: true,
+    effects: () => {
+      onFormInit(async (form1) => {
+        const resp = await service.getResourcesCurrent();
+        const current = resp?.result;
+        const _host = current.find((item: any) => item.host === '0.0.0.0')?.ports['TCP'] || [];
+        form1.setFieldState('port', (state) => {
+          state.dataSource = _host?.map((p: any) => ({ label: p, value: p }));
+        });
+      });
+    },
+  });
+
+  const SchemaField = createSchemaField({
+    components: {
+      FormItem,
+      FormGrid,
+      Input,
+      NumberPicker,
+      Select,
+    },
+  });
+
+  const save = async () => {
+    const values: any = await form.submit();
+    // 新增网络组件
+    const network = await service.saveNetwork({
+      type: 'MQTT_SERVER',
+      shareCluster: true,
+      name: 'MQTT网络组件',
+      configuration: {
+        host: '0.0.0.0',
+        secure: false,
+        port: values.port,
+        publicHost: values.publicHost,
+        publicPort: values.publicPort,
+      },
+    });
+    // 保存协议
+    const protocol = await service.saveProtocol();
+    let protocolItem: any = undefined;
+    if (protocol.status === 200) {
+      const proid = await service.getProtocol();
+      if (proid.status === 200) {
+        protocolItem = (proid?.result || []).find((it: any) => it.name === 'Jetlinks官方协议');
+      }
+    }
+    // 新增设备接入网关
+    const accessConfig = await service.saveAccessConfig({
+      name: 'MQTT类型设备接入网关',
+      provider: 'mqtt-server-gateway',
+      protocol: protocolItem?.id,
+      transport: 'MQTT',
+      channel: 'network',
+      channelId: network?.result?.id,
+    });
+    if (accessConfig) {
+    }
+    // 新增产品
+
+    // 新增设备
+
+    // values.productName = product?.name || '';
+    // const { upload, ...extra } = values;
+    // const params = {
+    //   ...extra,
+    //   url: upload.url || data?.url,
+    //   size: upload.length || data?.size,
+    // };
+    // const resp = (await service.update(params)) as any;
+    // if (resp.status === 200) {
+    //   onlyMessage('保存成功!');
+    //   close();
+    // }
+  };
+  const schema: ISchema = {
+    type: 'object',
+    properties: {
+      grid: {
+        type: 'void',
+        'x-component': 'FormGrid',
+        'x-component-props': {
+          minColumns: 2,
+          maxColumns: 2,
+        },
+        properties: {
+          host: {
+            title: '本地地址',
+            'x-decorator': 'FormItem',
+            'x-component': 'Select',
+            'x-component-props': {
+              placeholder: '请选择本地地址',
+            },
+            'x-disabled': true,
+            default: '0.0.0.0',
+            'x-decorator-props': {
+              gridSpan: 1,
+              labelAlign: 'left',
+              layout: 'vertical',
+              tooltip: '绑定到服务器上的网卡地址,绑定到所有网卡:0.0.0.0',
+            },
+            required: true,
+            'x-validator': ['ipv4'],
+          },
+          port: {
+            title: '本地端口',
+            'x-decorator-props': {
+              gridSpan: 1,
+              labelAlign: 'left',
+              tooltip: '监听指定端口的请求',
+              layout: 'vertical',
+            },
+            required: true,
+            type: 'number',
+            'x-decorator': 'FormItem',
+            'x-component': 'Select',
+            'x-component-props': {
+              placeholder: '请选择本地端口',
+            },
+            'x-validator': [
+              {
+                max: 65535,
+                message: '请输入1-65535之间的整整数',
+              },
+              {
+                min: 1,
+                message: '请输入1-65535之间的整整数',
+              },
+            ],
+          },
+          publicHost: {
+            title: '公网地址',
+            'x-decorator-props': {
+              gridSpan: 1,
+              labelAlign: 'left',
+              tooltip: '对外提供访问的地址,内网环境是填写服务器的内网IP地址',
+              layout: 'vertical',
+            },
+            required: true,
+            'x-decorator': 'FormItem',
+            'x-component': 'Input',
+            'x-validator': ['ipv4'],
+            'x-component-props': {
+              placeholder: '请输入公网地址',
+            },
+          },
+          publicPort: {
+            title: '公网端口',
+            'x-decorator-props': {
+              gridSpan: 1,
+              tooltip: '对外提供访问的端口',
+              layout: 'vertical',
+              labelAlign: 'left',
+            },
+            'x-component-props': {
+              placeholder: '请输入公网端口',
+            },
+            required: true,
+            'x-decorator': 'FormItem',
+            'x-component': 'NumberPicker',
+            'x-validator': [
+              {
+                max: 65535,
+                message: '请输入1-65535之间的整整数',
+              },
+              {
+                min: 1,
+                message: '请输入1-65535之间的整整数',
+              },
+            ],
+          },
+        },
+      },
+    },
+  };
+
+  return (
+    <Modal
+      maskClosable={false}
+      width="52vw"
+      title={'初始数据'}
+      onCancel={() => close()}
+      onOk={() => save()}
+      visible
+    >
+      <div style={{ background: 'rgb(236, 237, 238)' }}>
+        <p style={{ padding: 10 }}>
+          <ExclamationCircleOutlined style={{ marginRight: 5 }} />
+          初始化数据包括MQTT产品、MQTT设备、MQTT类型设备接入网关、MQTT网络组件、Jetlinks 官方协议
+        </p>
+      </div>
+      <div style={{ marginTop: '20px' }}>
+        <Form form={form} labelCol={5} wrapperCol={16} layout="vertical">
+          <SchemaField schema={schema} />
+        </Form>
+      </div>
+    </Modal>
+  );
+};
+export default Save;

+ 12 - 0
src/pages/init-home/components/menu.tsx

@@ -0,0 +1,12 @@
+const Menu = () => {
+  return (
+    <div style={{ display: 'flex' }}>
+      <div>
+        <img src={require('/public/images/init-home/menu.png')} />
+      </div>
+      <div>系统将初始化XXX个菜单 初始化后的菜单可在“菜单管理”页面进行维护管理</div>
+    </div>
+  );
+};
+
+export default Menu;

+ 5 - 0
src/pages/init-home/components/role.tsx

@@ -0,0 +1,5 @@
+const Role = () => {
+  return <div>系统将初始化XXX个菜单 初始化后的菜单可在“菜单管理”页面进行维护管理</div>;
+};
+
+export default Role;

+ 13 - 7
src/pages/init-home/index.less

@@ -29,13 +29,19 @@
         width: calc(100% - 50px);
         height: 1200px;
 
-        // .collapseTitle {
-
-        // }
-
-        // .collapseDesc {
-
-        // }
+        .collapseTitle {
+          display: flex;
+          font-size: 14px;
+          opacity: 0.85;
+
+          .collapseDesc {
+            margin-top: 2px;
+            margin-left: 8px;
+            color: #666;
+            font-size: 12px;
+            opacity: 0.85;
+          }
+        }
       }
     }
   }

+ 48 - 14
src/pages/init-home/index.tsx

@@ -1,13 +1,15 @@
 import { TitleComponent } from '@/components';
-import { Collapse, Steps } from 'antd';
+import { Button, Collapse, Steps } from 'antd';
 import styles from './index.less';
+import Basis from './components/basis';
+import Menu from './components/menu';
+import Role from './components/role';
+import Data from './components/data';
+import Service from './service';
+
+export const service = new Service();
 
 const InitHome = () => {
-  const text = `
-        A dog is a type of domesticated animal.
-        Known for its loyalty and faithfulness,
-        it can be found as a welcome guest in many households across the world.
-    `;
   return (
     <div className={styles.init}>
       <TitleComponent data={'系统初始化'} />
@@ -23,19 +25,51 @@ const InitHome = () => {
           </div>
           <div className={styles.right}>
             <Collapse defaultActiveKey={['1', '2', '3', '4']}>
-              <Collapse.Panel header={<div>基本信息</div>} key="1">
-                <p>{text}</p>
+              <Collapse.Panel
+                header={
+                  <div className={styles.collapseTitle}>
+                    基本信息
+                    <div className={styles.collapseDesc}>
+                      配置平台名称、登录背景图、主题色等基本信息
+                    </div>
+                  </div>
+                }
+                key="1"
+              >
+                <Basis getData={() => {}} />
               </Collapse.Panel>
-              <Collapse.Panel header="This is panel header 2" key="2">
-                <p>{text}</p>
+              <Collapse.Panel
+                header={
+                  <div className={styles.collapseTitle}>
+                    菜单初始化<div className={styles.collapseDesc}>初始化菜单数据</div>
+                  </div>
+                }
+                key="2"
+              >
+                <Menu />
               </Collapse.Panel>
-              <Collapse.Panel header="This is panel header 3" key="3">
-                <p>{text}</p>
+              <Collapse.Panel
+                header={
+                  <div className={styles.collapseTitle}>
+                    角色初始化<div className={styles.collapseDesc}>初始化内置角色与权限数据</div>
+                  </div>
+                }
+                key="3"
+              >
+                <Role />
               </Collapse.Panel>
-              <Collapse.Panel header="This is panel header 3" key="4">
-                <p>{text}</p>
+              <Collapse.Panel
+                header={
+                  <div className={styles.collapseTitle}>
+                    初始数据<div className={styles.collapseDesc}>初始化设备接入示例数据</div>
+                  </div>
+                }
+                key="4"
+              >
+                <Data />
               </Collapse.Panel>
             </Collapse>
+            <Button type="primary">确认</Button>
           </div>
         </div>
       </div>

+ 50 - 0
src/pages/init-home/service.ts

@@ -0,0 +1,50 @@
+import BaseService from '@/utils/BaseService';
+import { request } from 'umi';
+import SystemConst from '@/utils/const';
+
+class Service extends BaseService<any> {
+  save = (data?: any) =>
+    request(`/${SystemConst.API_BASE}/system/config/scope/_save`, {
+      method: 'POST',
+      data,
+    });
+  detail = (data?: any) =>
+    request(`/${SystemConst.API_BASE}/system/config/scopes`, {
+      method: 'POST',
+      data,
+    });
+  getResourcesCurrent = () =>
+    request(`${SystemConst.API_BASE}/network/resources/alive/_current`, {
+      method: 'GET',
+    });
+  saveNetwork = (data: any) =>
+    request(`${SystemConst.API_BASE}/network/config`, {
+      method: 'POST',
+      data,
+    });
+  saveProtocol = () =>
+    request(`${SystemConst.API_BASE}/protocol/default-protocol/_save`, {
+      method: 'POST',
+    });
+  getProtocol = () =>
+    request(`${SystemConst.API_BASE}/protocol/default-protocol/_query/no-paging?paging=false`, {
+      method: 'GET',
+    });
+  saveAccessConfig = (data: any) =>
+    request(`${SystemConst.API_BASE}/gateway/device`, {
+      method: 'POST',
+      data,
+    });
+  saveProduct = (data: any) =>
+    request(`${SystemConst.API_BASE}/device/product`, {
+      method: 'POST',
+      data,
+    });
+  saveDevice = (data: any) =>
+    request(`${SystemConst.API_BASE}/device/instance`, {
+      method: 'POST',
+      data,
+    });
+}
+
+export default Service;

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

@@ -123,6 +123,7 @@ const Certificate = () => {
         search={false}
         rowKey="id"
         tableClassName={'link-certificate'}
+        columnEmptyText={''}
         tableStyle={{ minHeight }}
         headerTitle={
           <PermissionButton

+ 1 - 0
src/pages/link/Channel/Modbus/Access/bindDevice/index.tsx

@@ -118,6 +118,7 @@ const BindDevice = (props: Props) => {
         params={param}
         columns={columns}
         rowKey="id"
+        columnEmptyText={''}
         search={false}
         request={async (params) =>
           service.getDevice({

+ 1 - 0
src/pages/link/Channel/Modbus/Access/index.tsx

@@ -333,6 +333,7 @@ const Access = () => {
               params={param}
               columns={columns}
               rowKey="id"
+              columnEmptyText={''}
               search={false}
               headerTitle={
                 <>

+ 1 - 0
src/pages/link/Channel/Modbus/index.tsx

@@ -349,6 +349,7 @@ const NewModbus = () => {
               params={param}
               columns={columns}
               rowKey="id"
+              columnEmptyText={''}
               // scroll={{ x: 1000 }}
               search={false}
               headerTitle={

+ 1 - 0
src/pages/link/Channel/Opcua/Access/bindDevice/index.tsx

@@ -129,6 +129,7 @@ const BindDevice = (props: Props) => {
         columns={columns}
         rowKey="id"
         search={false}
+        columnEmptyText={''}
         request={async (params) =>
           service.getDevice({
             ...params,

+ 1 - 0
src/pages/link/Channel/Opcua/Access/index.tsx

@@ -340,6 +340,7 @@ const Access = () => {
               params={param}
               columns={columns}
               rowKey="id"
+              columnEmptyText={''}
               search={false}
               headerTitle={
                 <>

+ 1 - 0
src/pages/link/Channel/Opcua/index.tsx

@@ -255,6 +255,7 @@ const Opcua = () => {
         columns={columns}
         rowKey="id"
         search={false}
+        columnEmptyText={''}
         tableClassName={'opcua'}
         tableStyle={{ minHeight }}
         headerTitle={

+ 1 - 0
src/pages/link/Channel/new.tsx

@@ -335,6 +335,7 @@ const NewModbus = () => {
             rowKey="id"
             // scroll={{ x: 1000 }}
             search={false}
+            columnEmptyText={''}
             headerTitle={
               <>
                 <PermissionButton

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

@@ -126,6 +126,7 @@ const BindChannel = (props: Props) => {
         params={param}
         columns={columns}
         search={false}
+        columnEmptyText={''}
         headerTitle={'通道列表'}
         request={async (params) => {
           return service.queryChannel({ ...params, sorts: [{ name: 'name', order: 'desc' }] });

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

@@ -208,6 +208,7 @@ const Channel = () => {
         columns={columns}
         scroll={{ x: 1366 }}
         search={false}
+        columnEmptyText={''}
         tableClassName={'cascadeDevice'}
         tableStyle={{ minHeight }}
         headerTitle={'通道列表'}

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

@@ -251,6 +251,7 @@ export default () => {
             columns={columns}
             actionRef={actionRef}
             // scroll={{x:1366}}
+            columnEmptyText={''}
             tableClassName={'channelDevice'}
             tableStyle={{ minHeight }}
             options={{ fullScreen: true }}

+ 1 - 0
src/pages/media/Home/deviceModal.tsx

@@ -127,6 +127,7 @@ export default (props: DeviceModalProps) => {
         columns={columns}
         rowKey={'id'}
         search={false}
+        columnEmptyText={''}
         request={(params) =>
           service.query({
             ...params,

+ 1 - 0
src/pages/notice/Config/Log/index.tsx

@@ -113,6 +113,7 @@ const Log = observer(() => {
         pagination={{
           pageSize: 5,
         }}
+        columnEmptyText={''}
         columns={columns}
         request={async (params) =>
           service.getHistoryLog(state.current?.id || '', {

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

@@ -196,6 +196,7 @@ const SyncUser = observer(() => {
                 actionRef={actionRef}
                 search={false}
                 columns={columns}
+                columnEmptyText={''}
                 params={{ dept: dept }}
                 request={(params) =>
                   service

+ 1 - 0
src/pages/notice/Template/Log/index.tsx

@@ -116,6 +116,7 @@ const Log = observer(() => {
             // pageSize: 5,
           }
         }
+        columnEmptyText={''}
         params={param}
         columns={columns}
         request={async (params) =>

+ 19 - 13
src/pages/rule-engine/Alarm/Config/Save/input.tsx

@@ -1,16 +1,15 @@
 import { Modal } from 'antd';
-import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 import { createSchemaField } from '@formily/react';
 import { Form, FormGrid, FormItem, Input, Switch } from '@formily/antd';
 import { createForm, onFormInit } from '@formily/core';
 import type { ISchema } from '@formily/json-schema';
 import { service } from '@/pages/rule-engine/Alarm/Config';
 import { onlyMessage } from '@/utils/util';
-import type { IOConfigItem } from '../typing';
 
 interface Props {
-  data?: FirmwareItem;
+  data?: any;
   close: () => void;
+  save: () => void;
 }
 
 const InputSave = (props: Props) => {
@@ -18,14 +17,16 @@ const InputSave = (props: Props) => {
 
   const form = createForm({
     validateFirst: true,
-    initialValues: data,
+    // initialValues: data,
     effects() {
-      onFormInit(async (f) => {
-        const resp = await service.getDataExchange('consume');
-        if (resp.status === 200) {
-          f.setInitialValues(resp.result?.config.config);
-          f.setValuesIn('id', resp.result?.id);
-          f.setValuesIn('state', resp.result?.state?.value === 'enabled' ? true : false);
+      onFormInit((f) => {
+        if (data) {
+          f.setInitialValues({
+            ...data?.data?.config?.config,
+            address: data?.data?.config?.config?.address,
+            topic: data?.data?.config?.config?.topic,
+            state: data?.data?.state?.value === 'enabled' ? true : false,
+          });
         }
       });
     },
@@ -42,19 +43,24 @@ const InputSave = (props: Props) => {
 
   const save = async () => {
     form.validate();
-    const inputConfig: IOConfigItem = await form.submit();
+    const inputConfig: any = await form.submit();
     const res = await service.saveOutputData({
       config: {
         sourceType: 'kafka',
-        config: inputConfig,
+        config: {
+          ...inputConfig,
+          state: inputConfig?.state ? 'enabled' : 'disable',
+        },
       },
-      id: inputConfig.id,
+      state: inputConfig?.state ? 'enabled' : 'disable',
+      id: data?.data?.id,
       sourceType: 'kafka',
       exchangeType: 'consume',
     });
 
     if (res.status === 200) {
       onlyMessage('操作成功');
+      props.save();
     }
   };
 

+ 20 - 17
src/pages/rule-engine/Alarm/Config/Save/output.tsx

@@ -1,16 +1,15 @@
 import { Modal } from 'antd';
-import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 import { createSchemaField } from '@formily/react';
 import { Form, FormGrid, FormItem, Input, Switch } from '@formily/antd';
 import { createForm, onFormInit } from '@formily/core';
 import type { ISchema } from '@formily/json-schema';
 import { service } from '@/pages/rule-engine/Alarm/Config';
 import { onlyMessage } from '@/utils/util';
-import type { IOConfigItem } from '../typing';
 
 interface Props {
-  data?: FirmwareItem;
+  data?: any;
   close: () => void;
+  save: () => void;
 }
 
 const OutputSave = (props: Props) => {
@@ -18,14 +17,16 @@ const OutputSave = (props: Props) => {
 
   const form = createForm({
     validateFirst: true,
-    initialValues: data,
+    // initialValues: data,
     effects() {
       onFormInit(async (f) => {
-        const resp = await service.getDataExchange('producer');
-        if (resp.status === 200) {
-          f.setInitialValues(resp.result?.config.config);
-          f.setValuesIn('id', resp.result?.id);
-          f.setValuesIn('state', resp.result?.state?.value === 'enabled' ? true : false);
+        if (data) {
+          f.setInitialValues({
+            // ...data?.data?.config?.config,
+            address: data?.data?.config?.config?.address,
+            topic: data?.data?.config?.config?.topic,
+            state: data?.data?.state?.value === 'enabled' ? true : false,
+          });
         }
       });
     },
@@ -42,29 +43,31 @@ const OutputSave = (props: Props) => {
 
   const save = async () => {
     form.validate();
-    const inputConfig: IOConfigItem = await form.submit();
+    const inputConfig: any = await form.submit();
+    console.log(inputConfig);
     const res = await service.saveOutputData({
       config: {
         sourceType: 'kafka',
-        config: inputConfig,
+        config: {
+          ...inputConfig,
+          state: inputConfig?.state ? 'enabled' : 'disable',
+        },
       },
-      id: inputConfig.id,
+      state: inputConfig?.state ? 'enabled' : 'disable',
+      id: data?.data?.id,
       sourceType: 'kafka',
-      exchangeType: 'consume',
+      exchangeType: 'producer',
     });
 
     if (res.status === 200) {
       onlyMessage('操作成功');
+      props.save();
     }
   };
 
   const outputSchema: ISchema = {
     type: 'object',
     properties: {
-      id: {
-        'x-component': 'Input',
-        'x-hidden': true,
-      },
       address: {
         title: 'kafka地址',
         type: 'string',

+ 38 - 10
src/pages/rule-engine/Alarm/Config/index.tsx

@@ -248,17 +248,25 @@ const Config = () => {
     }
   };
 
-  useEffect(() => {
+  const handleInputSearch = () => {
     service.getDataExchange('consume').then((resp) => {
       if (resp.status === 200) {
         setInput(resp.result);
       }
     });
+  };
+
+  const handleOutputSearch = () => {
     service.getDataExchange('producer').then((resp) => {
       if (resp.status === 200) {
         setOutput(resp.result);
       }
     });
+  };
+
+  useEffect(() => {
+    handleOutputSearch();
+    handleInputSearch();
   }, []);
 
   const outputText = `
@@ -343,14 +351,19 @@ const Config = () => {
             />
             <Descriptions bordered column={2}>
               <Descriptions.Item label="kafka地址">
-                {output?.config?.config?.kafka || ''}
+                {output?.data?.config?.config?.address && (
+                  <Badge status={output?.running ? 'success' : 'error'} />
+                )}
+                {output?.data?.config?.config?.address || ''}
               </Descriptions.Item>
               <Descriptions.Item label="topic">
-                {output?.config?.config?.topic || ''}
+                {output?.data?.config?.config?.topic || ''}
               </Descriptions.Item>
               <Descriptions.Item label="状态" span={2}>
-                <Badge status={output?.state?.value === 'enabled' ? 'success' : 'error'} />
-                {output?.state?.text || ''}
+                {output?.data?.state && (
+                  <Badge status={output?.data?.state?.value === 'enabled' ? 'success' : 'error'} />
+                )}
+                {output?.data?.state?.text || ''}
               </Descriptions.Item>
             </Descriptions>
             <Divider />
@@ -374,21 +387,26 @@ const Config = () => {
             />
             <Descriptions bordered column={2}>
               <Descriptions.Item label="kafka地址">
-                {input?.config?.config?.kafka || ''}
+                {input?.data?.config?.config?.address && (
+                  <Badge status={input?.running ? 'success' : 'error'} />
+                )}
+                {input?.data?.config?.config?.address || ''}
               </Descriptions.Item>
               <Descriptions.Item label="topic">
-                {input?.config?.config?.topic || ''}
+                {input?.data?.config?.config?.topic || ''}
               </Descriptions.Item>
               <Descriptions.Item label="状态" span={2}>
-                <Badge status={input?.state?.value === 'enabled' ? 'success' : 'error'} />
-                {input?.state?.text || ''}
+                {input?.data?.state && (
+                  <Badge status={input?.data?.state?.value === 'enabled' ? 'success' : 'error'} />
+                )}
+                {input?.data?.state?.text || ''}
               </Descriptions.Item>
             </Descriptions>
           </Card>
         </div>
       </Col>
       <Col span={10}>
-        <div style={{ height: 560, marginLeft: 20, paddingBottom: 24 }}>
+        <div style={{ height: 650, marginLeft: 20, paddingBottom: 24 }}>
           <div className={styles.doc}>
             <h1>功能图示</h1>
             <div className={styles.image}>
@@ -431,16 +449,26 @@ const Config = () => {
       {list.find((k) => k.key === tab)?.component}
       {inputVisible && (
         <InputSave
+          data={input}
           close={() => {
             setInputVisible(false);
           }}
+          save={() => {
+            setInputVisible(false);
+            handleInputSearch();
+          }}
         />
       )}
       {outputVisible && (
         <OutputSave
+          data={output}
           close={() => {
             setOutputVisible(false);
           }}
+          save={() => {
+            setOutputVisible(false);
+            handleOutputSearch();
+          }}
         />
       )}
     </PageContainer>

+ 30 - 0
src/pages/rule-engine/Alarm/Configuration/index.tsx

@@ -51,6 +51,25 @@ const Configuration = () => {
         };
         return map[text];
       },
+      valueType: 'select',
+      valueEnum: {
+        product: {
+          text: '产品',
+          status: 'product',
+        },
+        device: {
+          text: '设备',
+          status: 'device',
+        },
+        org: {
+          text: '部门',
+          status: 'org',
+        },
+        other: {
+          text: '其他',
+          status: 'other',
+        },
+      },
     },
     {
       title: '告警级别',
@@ -69,6 +88,17 @@ const Configuration = () => {
           </div>
         </Tooltip>
       ),
+      valueType: 'select',
+      request: async () => {
+        const res = await service.queryDefaultLevel();
+        if (res.status === 200) {
+          return (res?.result?.levels || []).map((item: any) => ({
+            label: item.title,
+            value: item.level,
+          }));
+        }
+        return [];
+      },
     },
     {
       title: '关联场景联动',

+ 1 - 0
src/pages/rule-engine/Alarm/Log/Detail/index.tsx

@@ -130,6 +130,7 @@ const Detail = observer(() => {
         params={param}
         columns={AlarmLogModel.columns}
         search={false}
+        columnEmptyText={''}
         tableClassName={'alarm-log'}
         tableStyle={{ minHeight }}
         scroll={{ x: 1366 }}

+ 1 - 0
src/pages/rule-engine/Alarm/Log/SolveLog/index.tsx

@@ -107,6 +107,7 @@ const SolveLog = (props: Props) => {
         params={param}
         columns={columns}
         search={false}
+        columnEmptyText={''}
         headerTitle={'记录列表'}
         request={async (params) => {
           return service.queryHandleHistory({

+ 1 - 0
src/pages/rule-engine/Scene/Save/action/device/deviceModal.tsx

@@ -158,6 +158,7 @@ export default (props: DeviceModelProps) => {
             columns={columns}
             rowKey="id"
             search={false}
+            columnEmptyText={''}
             rowSelection={{
               selectedRowKeys: selectKeys.map((item) => item.value),
               onSelect: (selectedRow: any, selected: any) => {

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

@@ -236,6 +236,7 @@ const DataSource = observer(() => {
         columns={columns}
         search={false}
         rowKey="id"
+        columnEmptyText={''}
         scroll={{ x: 1366 }}
         tableClassName={'datasource'}
         tableStyle={{ minHeight }}

+ 2 - 2
src/pages/system/Department/Assets/permissionModal.tsx

@@ -34,7 +34,7 @@ const Permission = forwardRef((props: PerModalProps, ref) => {
   const form = createForm({
     validateFirst: true,
     initialValues: {
-      permission: ['read']
+      permission: ['read'],
     },
   });
 
@@ -50,7 +50,7 @@ const Permission = forwardRef((props: PerModalProps, ref) => {
 
   const saveData = async () => {
     const formData: any = await form.submit();
-    console.log(formData)
+    console.log(formData);
     service
       .bind(props.type, [
         {

+ 1 - 0
src/pages/system/Department/Assets/productCategory/bind.tsx

@@ -121,6 +121,7 @@ const Bind = observer((props: Props) => {
         rowKey="id"
         search={false}
         pagination={false}
+        columnEmptyText={''}
         rowSelection={{
           selectedRowKeys: Models.bindKeys,
           onSelect: (record, selected, selectedRows) => {

+ 1 - 0
src/pages/system/Department/Assets/productCategory/index.tsx

@@ -212,6 +212,7 @@ export default observer((props: { parentId: string }) => {
         params={searchParam}
         search={false}
         rowKey="id"
+        columnEmptyText={''}
         request={async (params) => {
           if (!props.parentId) {
             return {

+ 1 - 0
src/pages/system/Department/Member/bind.tsx

@@ -100,6 +100,7 @@ const Bind = observer((props: Props) => {
         actionRef={actionRef}
         columns={columns}
         rowKey="id"
+        columnEmptyText={''}
         search={false}
         params={searchParam}
         rowSelection={{

+ 1 - 0
src/pages/system/Department/Member/index.tsx

@@ -195,6 +195,7 @@ const Member = observer((props: { parentId: string }) => {
         columns={columns}
         search={false}
         rowKey="id"
+        columnEmptyText={''}
         request={(params) => {
           params.sorts = [{ name: 'createTime', order: 'desc' }];
           if (!props.parentId) {

+ 1 - 0
src/pages/system/Menu/Detail/buttons.tsx

@@ -248,6 +248,7 @@ export default (props: ButtonsProps) => {
         columns={columns}
         dataSource={buttonItems}
         search={false}
+        columnEmptyText={''}
         pagination={false}
         toolBarRender={() => [
           <PermissionButton

+ 2 - 3
src/pages/system/Menu/Setting/DragItem.less

@@ -1,4 +1,3 @@
-
 .menu-setting-drag-tree {
   .ant-tree-treenode.ant-tree-treenode-draggable {
     width: 100%;
@@ -12,9 +11,9 @@
     display: flex;
     align-items: center;
 
-    & >span:first-child {
+    & > span:first-child {
       flex: 1;
       padding-right: 4px;
     }
   }
-}
+}

Разница между файлами не показана из-за своего большого размера
+ 293 - 293
src/pages/system/Menu/Setting/baseMenu.ts


+ 51 - 46
src/pages/system/Menu/Setting/dragItem.tsx

@@ -1,5 +1,5 @@
-import {useDrag, useDrop} from 'react-dnd';
-import {useEffect, useRef, useState} from "react";
+import { useDrag, useDrop } from 'react-dnd';
+import { useEffect, useRef, useState } from 'react';
 import { CloseOutlined } from '@ant-design/icons';
 import classNames from 'classnames';
 import { DragType } from './tree';
@@ -10,89 +10,94 @@ interface DragItemProps {
   type: string;
   canDrag: boolean;
   isSearch?: boolean;
-  onDrop?: (item: any,dropIndex: string, type?: 'source' | 'menu') => void
-  removeDragItem?: (id: string | number) => void
+  onDrop?: (item: any, dropIndex: string, type?: 'source' | 'menu') => void;
+  removeDragItem?: (id: string | number) => void;
 }
 
 const DragItem = (props: DragItemProps) => {
-
-  const ref = useRef<HTMLDivElement>(null)
-  const [isDrag, setIsDrag] = useState(props.type === 'source')
+  const ref = useRef<HTMLDivElement>(null);
+  const [isDrag, setIsDrag] = useState(props.type === 'source');
 
   useEffect(() => {
-    setIsDrag(props.type === 'source' && props.canDrag)
-  }, [props.canDrag])
+    setIsDrag(props.type === 'source' && props.canDrag);
+  }, [props.canDrag]);
 
   const [, drop] = useDrop(() => ({
     accept: DragType,
     drop(item: any) {
-      props.onDrop?.(item.data, props.data.code, item.type)
-      return undefined
+      props.onDrop?.(item.data, props.data.code, item.type);
+      return undefined;
     },
     collect: (monitor) => {
       const { index } = monitor.getItem() || {};
       if (index === props.data.code) {
-        return {}
+        return {};
       }
       return {
         isOver: monitor.isOver(),
         canDrop: monitor.canDrop(),
-      }
+      };
     },
-  }))
+  }));
 
-  const [, drag] = useDrag(() => (
-    {
+  const [, drag] = useDrag(
+    () => ({
       type: DragType,
       item: {
         index: props.data.code,
         data: props.data,
-        type: props.type
+        type: props.type,
       },
       collect: (monitor) => {
         return {
           isDragging: monitor.isDragging(),
-        }
+        };
       },
-      canDrag: isDrag
-    }
-  ), [isDrag, props.data]);
-
+      canDrag: isDrag,
+    }),
+    [isDrag, props.data],
+  );
 
-  drag(drop(ref))
+  drag(drop(ref));
 
-  const style = props.type === 'source' ? isDrag ? {
-    border: '1px solid #E0E0E0',
-    padding: '0px 4px',
-    backgroundColor: '#F6F6F6',
-    borderRadius: 4,
-    color: '#2F54EB',
-    width: 'fit-content'
-  } : {
-    color: '#666666',
-    cursor: 'not-allowed',
-    width: 'fit-content'
-  } : {}
+  const style =
+    props.type === 'source'
+      ? isDrag
+        ? {
+            border: '1px solid #E0E0E0',
+            padding: '0px 4px',
+            backgroundColor: '#F6F6F6',
+            borderRadius: 4,
+            color: '#2F54EB',
+            width: 'fit-content',
+          }
+        : {
+            color: '#666666',
+            cursor: 'not-allowed',
+            width: 'fit-content',
+          }
+      : {};
 
   return (
-    <div ref={ref} style={style} className={classNames({'tree-drag-item': props.type === 'menu'})}>
-      <span style={props.isSearch ? { color: '#f50' }: {}}>
-       {props.data.name}
-      </span>
-      {
-        props.type === 'menu' && 
+    <div
+      ref={ref}
+      style={style}
+      className={classNames({ 'tree-drag-item': props.type === 'menu' })}
+    >
+      <span style={props.isSearch ? { color: '#f50' } : {}}>{props.data.name}</span>
+      {props.type === 'menu' && (
         <Popconfirm
-          title='确认删除?'
+          title="确认删除?"
           onConfirm={(e: any) => {
-            e?.stopPropagation()
-            props.removeDragItem?.(props.data.code)
+            e?.stopPropagation();
+            props.removeDragItem?.(props.data.code);
           }}
         >
-          <Tooltip title='删除' >
+          <Tooltip title="删除">
             <CloseOutlined />
           </Tooltip>
         </Popconfirm>
-      }
+      )}
     </div>
   );
 };

+ 2 - 2
src/pages/system/Menu/Setting/index.less

@@ -28,14 +28,14 @@
 
       .menu-tree-title {
         display: flex;
+        align-items: center;
         justify-content: space-between;
         margin-bottom: 16px;
         padding: 14px 16px;
         font-weight: 400;
         font-size: 16px;
         background-color: #f3f4f4;
-        align-items: center;
-        
+
         > span {
           margin-left: 16px;
         }

+ 103 - 101
src/pages/system/Menu/Setting/index.tsx

@@ -1,5 +1,5 @@
-import {PageContainer} from '@ant-design/pro-layout';
-import {useDomFullHeight} from '@/hooks';
+import { PageContainer } from '@ant-design/pro-layout';
+import { useDomFullHeight } from '@/hooks';
 import {
   ExclamationCircleOutlined,
   QuestionCircleOutlined,
@@ -7,37 +7,40 @@ import {
 } from '@ant-design/icons';
 import Tree from './tree';
 import './index.less';
-import {Button, Tooltip} from 'antd';
+import { Button, Tooltip } from 'antd';
 import BaseTreeData from './baseMenu';
-import { useEffect, useState} from 'react';
-import {HTML5Backend} from 'react-dnd-html5-backend';
-import {DndProvider} from 'react-dnd';
-import {cloneDeep} from 'lodash'
+import { useEffect, useState } from 'react';
+import { HTML5Backend } from 'react-dnd-html5-backend';
+import { DndProvider } from 'react-dnd';
+import { cloneDeep } from 'lodash';
 import { observable } from '@formily/reactive';
-import { Observer, observer } from '@formily/react'
-import { service } from '../index'
-import type {TreeProps, DataNode} from 'antd/es/tree'
+import { Observer, observer } from '@formily/react';
+import { service } from '../index';
+import type { TreeProps, DataNode } from 'antd/es/tree';
 
 type MenuSettingModelType = {
-  menuData: any[]
-  notDragKeys: (string | number)[]
-}
+  menuData: any[];
+  notDragKeys: (string | number)[];
+};
 
 export const MenuSettingModel = observable<MenuSettingModelType>({
   menuData: [],
-  notDragKeys: []
-})
+  notDragKeys: [],
+});
 
 export default observer(() => {
-  const {minHeight} = useDomFullHeight(`.menu-setting-warp`);
+  const { minHeight } = useDomFullHeight(`.menu-setting-warp`);
   const [baseMenu, setBaseMenu] = useState<any[]>(BaseTreeData);
-  const [loading, setLoading] = useState(false)
-
-  const finedObject = (data: any[], code: string | number, callback: (index: number, arr: any[], item: any) => void) => {
+  const [loading, setLoading] = useState(false);
 
+  const finedObject = (
+    data: any[],
+    code: string | number,
+    callback: (index: number, arr: any[], item: any) => void,
+  ) => {
     data.forEach((item, index) => {
       if (item.code === code) {
-        return callback(index, data, item)
+        return callback(index, data, item);
       }
 
       if (item.children) {
@@ -53,7 +56,7 @@ export default observer(() => {
     const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
 
     const data = [...MenuSettingModel.menuData];
-    let dragObj: DataNode & {parentId: string};
+    let dragObj: DataNode & { parentId: string };
 
     finedObject(data, dragKey, (index, arr, item) => {
       arr.splice(index, 1);
@@ -64,19 +67,19 @@ export default observer(() => {
     if (!info.dropToGap) {
       finedObject(data, dropKey, (_i, _arr, item) => {
         item.children = item.children || [];
-        dragObj.parentId = item.id
-        
+        dragObj.parentId = item.id;
+
         item.children.unshift(dragObj);
       });
     } else if (
-      ((info.node as any).props.children || []).length > 0 && 
-      (info.node as any).props.expanded && 
-      dropPosition === 1 
+      ((info.node as any).props.children || []).length > 0 &&
+      (info.node as any).props.expanded &&
+      dropPosition === 1
     ) {
       finedObject(data, dropKey, (_i, _arr, item) => {
         item.children = item.children || [];
-        dragObj.parentId = item.id 
-      
+        dragObj.parentId = item.id;
+
         item.children.unshift(dragObj);
       });
     } else {
@@ -93,105 +96,106 @@ export default observer(() => {
         ar.splice(i! + 1, 0, dragObj!);
       }
     }
-    MenuSettingModel.menuData = [...data]
-  }
+    MenuSettingModel.menuData = [...data];
+  };
 
-  const getKeys = (data: any[]): (string|number)[] => {
-    return data.reduce((pre: (string|number)[] , next: any) => {
-      const childrenKeys = next.children ? getKeys(next.children) : []
-      return [...pre, next.code, ...childrenKeys]
-    }, [])
-  }
+  const getKeys = (data: any[]): (string | number)[] => {
+    return data.reduce((pre: (string | number)[], next: any) => {
+      const childrenKeys = next.children ? getKeys(next.children) : [];
+      return [...pre, next.code, ...childrenKeys];
+    }, []);
+  };
 
   const filterItem = (data: any[], dragKeys: (string | number)[]) => {
-    return data.filter(item => {
+    return data.filter((item) => {
       if (dragKeys.includes(item.code)) {
-        return false
+        return false;
       } else if (item.children) {
-        item.children = filterItem(item.children, dragKeys)
+        item.children = filterItem(item.children, dragKeys);
       }
-      return true
-    })
-  }
+      return true;
+    });
+  };
 
   const onDrop = (item: any, dropIndex: string, type?: string) => {
-      const newItem = cloneDeep(item);
-      
-      if (dropIndex) { // 切换层级或者挪动
-        // const newMenus = cloneDeep(menuData);
-        if (type === 'source') {
-          finedObject(MenuSettingModel.menuData, dropIndex, (index, arr) => {
-            arr.splice(index + 1, 0, newItem);
-          });
-          MenuSettingModel.menuData = [...MenuSettingModel.menuData];
-        }
-      } else { // 新增
-        newItem.parentId = ''
-        // 过滤掉内部已选择的节点
-        if (newItem.children && MenuSettingModel.notDragKeys.length) {
-          newItem.children = filterItem(newItem.children, MenuSettingModel.notDragKeys)
-        }
-        MenuSettingModel.menuData.push(newItem)
-        MenuSettingModel.notDragKeys = getKeys(MenuSettingModel.menuData)
+    const newItem = cloneDeep(item);
+
+    if (dropIndex) {
+      // 切换层级或者挪动
+      // const newMenus = cloneDeep(menuData);
+      if (type === 'source') {
+        finedObject(MenuSettingModel.menuData, dropIndex, (index, arr) => {
+          arr.splice(index + 1, 0, newItem);
+        });
+        MenuSettingModel.menuData = [...MenuSettingModel.menuData];
+      }
+    } else {
+      // 新增
+      newItem.parentId = '';
+      // 过滤掉内部已选择的节点
+      if (newItem.children && MenuSettingModel.notDragKeys.length) {
+        newItem.children = filterItem(newItem.children, MenuSettingModel.notDragKeys);
       }
+      MenuSettingModel.menuData.push(newItem);
+      MenuSettingModel.notDragKeys = getKeys(MenuSettingModel.menuData);
     }
+  };
 
   const removeDragItem = (id: string | number) => {
     finedObject(MenuSettingModel.menuData, id, (index, arr) => {
       arr.splice(index, 1);
     });
-    MenuSettingModel.menuData = [...MenuSettingModel.menuData]
-    MenuSettingModel.notDragKeys = getKeys(MenuSettingModel.menuData)
-  }
+    MenuSettingModel.menuData = [...MenuSettingModel.menuData];
+    MenuSettingModel.notDragKeys = getKeys(MenuSettingModel.menuData);
+  };
 
   const getSystemMenu = () => {
-    service.queryMenuThree({ paging: false }).then(res => {
+    service.queryMenuThree({ paging: false }).then((res) => {
       if (res.status === 200) {
-        MenuSettingModel.menuData = [...res.result]
-        MenuSettingModel.notDragKeys = getKeys(res.result)
+        MenuSettingModel.menuData = [...res.result];
+        MenuSettingModel.notDragKeys = getKeys(res.result);
       }
-    })
-  }
+    });
+  };
 
   useEffect(() => {
-    getSystemMenu()
+    getSystemMenu();
     setBaseMenu(BaseTreeData);
   }, []);
 
   const updateMenu = () => {
-    setLoading(true)
-    service.updateMenus(MenuSettingModel.menuData).then(res => {
-      setLoading(false)
+    setLoading(true);
+    service.updateMenus(MenuSettingModel.menuData).then((res) => {
+      setLoading(false);
       if (res.status === 200) {
-
       }
-    })
-  }
+    });
+  };
 
   return (
     <PageContainer>
-      <div className={'menu-setting-warp'} style={{minHeight}}>
+      <div className={'menu-setting-warp'} style={{ minHeight }}>
         <div className={'menu-setting-tip'}>
-          <ExclamationCircleOutlined/>
-          <span style={{paddingLeft: 12}}>
-            基于系统源代码中的菜单数据,配置系统菜单。
-          </span>
+          <ExclamationCircleOutlined />
+          <span style={{ paddingLeft: 12 }}>基于系统源代码中的菜单数据,配置系统菜单。</span>
         </div>
         <div className={'menu-tree-content'}>
           <DndProvider backend={HTML5Backend}>
             <div className={'menu-tree left-tree'}>
-              <div className={'menu-tree-title'} style={{padding: '10px 16px'}}>
+              <div className={'menu-tree-title'} style={{ padding: '10px 16px' }}>
                 <div>
-                  <span style={{paddingRight: 12}}>
-                  源菜单
-                  </span>
+                  <span style={{ paddingRight: 12 }}>源菜单</span>
                   <Tooltip title={'根据系统代码自动读取的菜单数据'}>
-                    <QuestionCircleOutlined/>
+                    <QuestionCircleOutlined />
                   </Tooltip>
                 </div>
-                <Button type={'primary'} ghost onClick={() => {
-                  MenuSettingModel.menuData = cloneDeep(baseMenu)
-                }}>
+                <Button
+                  type={'primary'}
+                  ghost
+                  onClick={() => {
+                    MenuSettingModel.menuData = cloneDeep(baseMenu);
+                  }}
+                >
                   一键拷贝
                 </Button>
               </div>
@@ -206,34 +210,32 @@ export default observer(() => {
                 )}
               </Observer>
             </div>
-            <div style={{display: 'flex', alignItems: 'center'}}>
+            <div style={{ display: 'flex', alignItems: 'center' }}>
               <div className={'menu-tree-drag-btn'}>
                 请拖动至右侧
-                <RightOutlined/>
+                <RightOutlined />
               </div>
             </div>
 
             <div className={'menu-tree right-tree'}>
               <div className={'menu-tree-title'}>
                 <div>
-                  <span style={{paddingRight: 12}}>
-                  系统菜单
-                  </span>
+                  <span style={{ paddingRight: 12 }}>系统菜单</span>
                   <Tooltip title={'菜单管理页面配置的菜单数据'}>
-                    <QuestionCircleOutlined/>
+                    <QuestionCircleOutlined />
                   </Tooltip>
                 </div>
               </div>
               <Observer>
                 {() => (
                   <>
-                  <Tree
-                    onTreeDrop={onTreeDrop}
-                    onDrop={onDrop}
-                    treeData={MenuSettingModel.menuData}
-                    droppableId={'menu'}
-                    removeDragItem={removeDragItem}
-                  />
+                    <Tree
+                      onTreeDrop={onTreeDrop}
+                      onDrop={onDrop}
+                      treeData={MenuSettingModel.menuData}
+                      droppableId={'menu'}
+                      removeDragItem={removeDragItem}
+                    />
                   </>
                 )}
               </Observer>

+ 71 - 69
src/pages/system/Menu/Setting/tree.tsx

@@ -2,111 +2,115 @@ import { Input, Tree } from 'antd';
 import { SearchOutlined } from '@ant-design/icons';
 import DragItem from '@/pages/system/Menu/Setting/dragItem';
 import { useDrop } from 'react-dnd';
-import {useEffect, useState} from 'react'
-import type {TreeProps} from 'antd'
-import { cloneDeep, debounce } from 'lodash'
-import './DragItem.less'
+import { useEffect, useState } from 'react';
+import type { TreeProps } from 'antd';
+import { cloneDeep, debounce } from 'lodash';
+import './DragItem.less';
 
 interface TreeBodyProps {
   treeData: any[];
   droppableId: string;
-  notDragKeys?: (string| number)[]
-  onDrop?: (item: any,dropIndex: string, type?: string) => void
-  onTreeDrop?: TreeProps['onDrop']
-  removeDragItem?: (id: string | number) => void
-  className?: string
+  notDragKeys?: (string | number)[];
+  onDrop?: (item: any, dropIndex: string, type?: string) => void;
+  onTreeDrop?: TreeProps['onDrop'];
+  removeDragItem?: (id: string | number) => void;
+  className?: string;
 }
 
-export const DragType = 'DragBox'
+export const DragType = 'DragBox';
 
 const { TreeNode } = Tree;
 
 export default (props: TreeBodyProps) => {
-  const [newData, setNewData] = useState(props.treeData)
-  const [searchKeys, setSearchKeys] = useState<(string| number)[]>([])
-  const [expandedKeys, setExpandedKeys] = useState<(string| number)[]>([])
-  
+  const [newData, setNewData] = useState(props.treeData);
+  const [searchKeys, setSearchKeys] = useState<(string | number)[]>([]);
+  const [expandedKeys, setExpandedKeys] = useState<(string | number)[]>([]);
+
   useEffect(() => {
-    setNewData(cloneDeep(props.treeData))
-  }, [props.treeData])
+    setNewData(cloneDeep(props.treeData));
+  }, [props.treeData]);
 
   const [, drop] = useDrop(() => ({
     accept: DragType,
     drop(item: any, monitor) {
-      const result = monitor.getDropResult()
+      const result = monitor.getDropResult();
       if (!result && props.onDrop) {
-        props.onDrop(item.data, '')
+        props.onDrop(item.data, '');
       }
-      return undefined
+      return undefined;
     },
     collect: (monitor) => {
       return {
         isOver: monitor.isOver(),
         canDrop: monitor.canDrop(),
         draggingColor: monitor.getItemType(),
-      }
+      };
     },
-  }))
+  }));
 
   const createTreeNode = (data: any[], type: string): React.ReactNode => {
     return data.map((item: any) => {
-      const isCanDrag = !props.notDragKeys?.includes(item.code)
+      const isCanDrag = !props.notDragKeys?.includes(item.code);
 
       if (item.children) {
         return (
           <TreeNode
-          selectable={false}
-          key={item.code}
-          title={
-          <DragItem 
-            onDrop={props.onDrop}
-            data={item}
-            type={type}
-            canDrag={isCanDrag}
-            removeDragItem={props.removeDragItem}
-            isSearch={searchKeys.includes(item.code)}
-            />
-           }>
+            selectable={false}
+            key={item.code}
+            title={
+              <DragItem
+                onDrop={props.onDrop}
+                data={item}
+                type={type}
+                canDrag={isCanDrag}
+                removeDragItem={props.removeDragItem}
+                isSearch={searchKeys.includes(item.code)}
+              />
+            }
+          >
             {createTreeNode(item.children, type)}
           </TreeNode>
         );
       }
-      return <TreeNode
-      selectable={false}
-      key={item.code}
-      title={
-      <DragItem 
-        onDrop={props.onDrop}
-        data={item}
-        type={type}
-        canDrag={isCanDrag}
-        removeDragItem={props.removeDragItem}
-        isSearch={searchKeys.includes(item.code)}
+      return (
+        <TreeNode
+          selectable={false}
+          key={item.code}
+          title={
+            <DragItem
+              onDrop={props.onDrop}
+              data={item}
+              type={type}
+              canDrag={isCanDrag}
+              removeDragItem={props.removeDragItem}
+              isSearch={searchKeys.includes(item.code)}
+            />
+          }
         />
-     } />;
+      );
     });
-  }
+  };
 
   const findAllItem = (data: any[], value: string): string[] => {
     return data.reduce((pre, next) => {
-      const childrenKeys = next.children ? findAllItem(next.children, value) : []
-      return next.name.includes(value) ? [...pre, next.code, ...childrenKeys] : [...pre, ...childrenKeys]
-    }, [])
-
-  }
+      const childrenKeys = next.children ? findAllItem(next.children, value) : [];
+      return next.name.includes(value)
+        ? [...pre, next.code, ...childrenKeys]
+        : [...pre, ...childrenKeys];
+    }, []);
+  };
 
   const searchValue = (e: any) => {
-    const value = e.target.value
+    const value = e.target.value;
 
     if (value) {
-      const sKeys = findAllItem(props.treeData, value)
-      setSearchKeys(sKeys)
-      setExpandedKeys(sKeys)
+      const sKeys = findAllItem(props.treeData, value);
+      setSearchKeys(sKeys);
+      setExpandedKeys(sKeys);
     } else {
-      setSearchKeys([])
+      setSearchKeys([]);
     }
-  }
-
+  };
 
   return (
     <div className={'tree-content'}>
@@ -118,36 +122,34 @@ export default (props: TreeBodyProps) => {
           onChange={debounce(searchValue, 500)}
         />
       </div>
-      {
-        props.droppableId === 'source' ?
+      {props.droppableId === 'source' ? (
         <div className={'tree-body'}>
           <Tree
             expandedKeys={expandedKeys}
             onExpand={(_expandedKeys) => {
-              setExpandedKeys(_expandedKeys)
+              setExpandedKeys(_expandedKeys);
             }}
           >
             {createTreeNode(newData, props.droppableId)}
           </Tree>
         </div>
-          :
-        <div className={'tree-body'} ref={drop} >
+      ) : (
+        <div className={'tree-body'} ref={drop}>
           <Tree
             expandedKeys={expandedKeys}
             onExpand={(_expandedKeys) => {
-              setExpandedKeys(_expandedKeys)
+              setExpandedKeys(_expandedKeys);
             }}
             draggable={{
-              icon: false
+              icon: false,
             }}
             onDrop={props.onTreeDrop}
-            className='menu-setting-drag-tree'
+            className="menu-setting-drag-tree"
           >
             {createTreeNode(props.treeData, props.droppableId)}
           </Tree>
         </div>
-
-      }
+      )}
     </div>
   );
 };

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

@@ -253,6 +253,7 @@ export default observer(() => {
         columns={columns}
         actionRef={actionRef}
         rowKey="id"
+        columnEmptyText={''}
         scroll={{ x: 1366 }}
         tableClassName={'menu'}
         tableStyle={{ minHeight }}

+ 1 - 1
src/pages/system/Menu/service.ts

@@ -29,7 +29,7 @@ class Service extends BaseService<MenuItem> {
   queryAssetsType = () => request(`${SystemConst.API_BASE}/asset/types`, { method: 'GET' });
 
   // 更新全部菜单
-  updateMenus = (data: any) => request(`${this.uri}`, {method: 'PATCH', data})
+  updateMenus = (data: any) => request(`${this.uri}`, { method: 'PATCH', data });
 }
 
 export default Service;

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

@@ -243,7 +243,7 @@ const Permission: React.FC = observer(() => {
                     );
                     actionRef.current?.reload();
                   }
-                })
+                });
               }
             },
           }}
@@ -270,6 +270,7 @@ const Permission: React.FC = observer(() => {
         params={param}
         columns={columns}
         search={false}
+        columnEmptyText={''}
         scroll={{ x: 1366 }}
         tableClassName={'permission'}
         tableStyle={{ minHeight }}

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

@@ -272,6 +272,7 @@ export default () => {
         params={param}
         columns={columns}
         actionRef={actionRef}
+        columnEmptyText={''}
         tableClassName={'platform'}
         tableStyle={{ minHeight }}
         request={(params: any) =>

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

@@ -119,6 +119,7 @@ const Relationship = () => {
         columns={columns}
         search={false}
         rowKey="id"
+        columnEmptyText={''}
         scroll={{ x: 1366 }}
         tableClassName={'relation'}
         tableStyle={{ minHeight }}

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

@@ -102,6 +102,7 @@ const BindUser = (props: Props) => {
         pagination={{
           pageSize: 10,
         }}
+        columnEmptyText={''}
         request={async (params: any) => {
           const response = await service.query({
             pageSize: params.pageSize,

+ 1 - 0
src/pages/system/Role/Detail/UserManage/index.tsx

@@ -116,6 +116,7 @@ const UserManage = () => {
             </a>
           </Space>
         )}
+        columnEmptyText={''}
         toolBarRender={() => [
           <Button
             onClick={() => {

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

@@ -122,7 +122,7 @@ const Role: React.FC = observer(() => {
                   );
                   actionRef.current?.reload();
                 }
-              })
+              });
             },
           }}
           tooltip={{
@@ -160,6 +160,7 @@ const Role: React.FC = observer(() => {
         tableClassName={'role'}
         tableStyle={{ minHeight }}
         search={false}
+        columnEmptyText={''}
         headerTitle={
           <PermissionButton
             onClick={() => {

+ 1 - 0
src/pages/system/Tenant/Detail/Member/Bind.tsx

@@ -70,6 +70,7 @@ const Bind = observer((props: Props) => {
           </span>
         </Space>
       )}
+      columnEmptyText={''}
       tableAlertOptionRender={() => (
         <Space size={16}>
           <a onClick={handleBind}>批量绑定</a>

+ 1 - 0
src/pages/system/Tenant/Detail/Member/index.tsx

@@ -88,6 +88,7 @@ const Member = observer(() => {
                 </span>
               </Space>
             )}
+            columnEmptyText={''}
             tableAlertOptionRender={() => (
               <Space size={16}>
                 <a onClick={handleUnBind}>批量解绑</a>

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

@@ -267,6 +267,7 @@ const User = observer(() => {
         tableClassName={'user'}
         tableStyle={{ minHeight }}
         search={false}
+        columnEmptyText={''}
         headerTitle={
           <PermissionButton
             onClick={() => {