Browse Source

fix: bug#6097、6099

xieyonghong 3 years atrás
parent
commit
d0fcb45121

+ 4 - 4
config/proxy.ts

@@ -12,11 +12,11 @@ export default {
       // target: 'http://192.168.32.8:8844/',
       // ws: 'ws://192.168.32.8:8844/',
       // 开发环境
-      target: 'http://120.79.18.123:8844/',
-      ws: 'ws://120.79.18.123:8844/',
+      // target: 'http://120.79.18.123:8844/',
+      // ws: 'ws://120.79.18.123:8844/',
       // 测试环境
-      // target: 'http://120.77.179.54:8844/',
-      // ws: 'ws://120.77.179.54:8844/',
+      target: 'http://120.77.179.54:8844/',
+      ws: 'ws://120.77.179.54:8844/',
       // target: 'http://192.168.66.5:8844/',
       // ws: 'ws://192.168.66.5:8844/',
       // ws: 'ws://demo.jetlinks.cn/jetlinks',

+ 1 - 1
src/hooks/websocket/useSendWebsocketMessage.ts

@@ -47,7 +47,7 @@ export const useSendWebsocketMessage = () => {
     // reconnectInterval: 1000,
     // reconnectLimit: 1,
     onClose: () => console.error('websocket 链接关闭'),
-    onOpen: (event) => console.log('打开链接', event),
+    // onOpen: (event) => console.log('打开链接', event),
     onError: (event) => console.log('报错了', event),
     onReconnect: () => {
       if (Object.keys(messageCache).length && sendMessage) {

+ 1 - 0
src/hooks/websocket/useWebSocket.ts

@@ -78,6 +78,7 @@ export default function useWebSocket(socketUrl: string, options: Options = {}):
           if (isReconnect.current && onReconnect) {
             // 是否为重连
             onReconnect();
+            return
           }
           onOpen?.(event);
           reconnectTimesRef.current = 0;

+ 15 - 0
src/pages/device/Instance/index.tsx

@@ -117,6 +117,21 @@ const Instance = () => {
     </Button>,
     <PermissionButton
       type={'link'}
+      onClick={() => {
+        setCurrent(record);
+        setVisible(true);
+      }}
+      tooltip={{
+        title: '编辑',
+      }}
+      style={{ padding: 0 }}
+      key={'edit'}
+      isPermission={permission.update}
+    >
+      <EditOutlined />
+    </PermissionButton>,
+    <PermissionButton
+      type={'link'}
       key={'state'}
       style={{ padding: 0 }}
       popConfirm={{

+ 2 - 3
src/pages/init-home/components/basis.tsx

@@ -58,7 +58,7 @@ const Basis = forwardRef((props: Props, ref) => {
       <Row gutter={[24, 24]}>
         <Col span={10}>
           <Form.Item label="系统名称" name="title">
-            <Input />
+            <Input placeholder={'请输入系统名称'} />
           </Form.Item>
           <Form.Item
             label="主题色"
@@ -72,7 +72,7 @@ const Basis = forwardRef((props: Props, ref) => {
             </Select>
           </Form.Item>
           <Form.Item label="高德API Key" name="apikey" tooltip="配置后平台可调用高德地图GIS服务">
-            <Input />
+            <Input placeholder={'请输入高德API Key'} />
           </Form.Item>
           <Row gutter={[24, 24]}>
             <Col>
@@ -116,7 +116,6 @@ const Basis = forwardRef((props: Props, ref) => {
                 <div>建议尺寸1400x1080</div>
               </>
             }
-            rules={[{ required: true, message: '请上传背景图' }]}
           >
             <UploadImage size={4} style={{ width: 570, height: 415 }} />
           </Form.Item>

+ 1 - 1
src/pages/init-home/index.tsx

@@ -51,7 +51,7 @@ const InitHome = () => {
           {/*</div>*/}
           <div className={styles.right}>
             <Spin spinning={loadings}>
-              <Collapse defaultActiveKey={['1', '2', '3', '4']}>
+              <Collapse defaultActiveKey={['1']} accordion>
                 <Collapse.Panel
                   header={
                     <div className={styles.collapseTitle}>

+ 2 - 1
src/pages/notice/Config/Debug/index.tsx

@@ -57,8 +57,10 @@ const Debug = observer(() => {
             const value = (field as Field).value;
             const format = field.query('.value').take() as any;
             const _id = field.query('.id').take() as Field;
+
             switch (value) {
               case 'date':
+                // const a = variableRef.current?.find((i: any) => i.id === _id.value);
                 format.setComponent(DatePicker);
                 break;
               case 'string':
@@ -76,7 +78,6 @@ const Debug = observer(() => {
                 format.setComponent(Input);
                 break;
             }
-            console.log(variableRef.current);
             if (variableRef.current) {
               const a = variableRef.current?.find((i: any) => i.id === _id.value);
               const businessType = a?.expands?.businessType;

+ 2 - 2
src/pages/notice/Config/SyncUser/index.tsx

@@ -62,7 +62,7 @@ const SyncUser = observer(() => {
       dataIndex: 'action',
       title: '操作',
       render: (text: any, record: any) => [
-        <Tooltip title={'绑定用户'} key="bind">
+        <Tooltip title={'编辑'} key="bind">
           <Button
             type="link"
             onClick={() => {
@@ -73,7 +73,7 @@ const SyncUser = observer(() => {
             <EditOutlined />
           </Button>
         </Tooltip>,
-        <Tooltip title={'解绑用户'} key="unbind">
+        <Tooltip title={'解绑'} key="unbind">
           {record?.status === 1 && (
             <Button type="link">
               <Popconfirm

+ 13 - 10
src/pages/notice/Template/Detail/doc/DingTalk.tsx

@@ -3,8 +3,8 @@ import './index.less';
 
 const DingTalk = () => {
   const agentId = require('/public/images/notice/doc/template/dingTalk-message/01-Agentid.jpg');
-  const userId = require('/public/images/notice/doc/template/dingTalk-message/02-user-id.jpg');
-  const dept = require('/public/images/notice/doc/template/dingTalk-message/03-dept.jpg');
+  // const userId = require('/public/images/notice/doc/template/dingTalk-message/02-user-id.jpg');
+  // const dept = require('/public/images/notice/doc/template/dingTalk-message/03-dept.jpg');
   const a = '{name}';
   return (
     <div className="doc">
@@ -22,26 +22,29 @@ const DingTalk = () => {
       <h1>1. 概述</h1>
       <div>
         通知模板结合通知配置为告警消息通知提供支撑。通知模板只能调用同一类型的通知配置服务。
+        <div>
+          使用钉钉消息通知时需在钉钉开放平台中创建好对应的应用
+        </div>
       </div>
       <h1> 2.模板配置说明</h1>
       <h2> 1、绑定配置</h2>
       <div> 使用固定的通知配置发送此通知模板</div>
       <h2> 2、Agentid</h2>
       <div> 应用唯一标识</div>
+      <div> 获取路径:“钉钉开发平台”--“应用开发”--“查看应用”</div>
       <div className="image">
         <Image width="100%" src={agentId} />
       </div>
-      <div> 获取路径:“钉钉开发平台”--“应用开发”--“查看应用”</div>
       <h2> 3、收信人ID、收信部门ID</h2>
       <div>
-        接收通知的2种方式,2个字段若在此页面都没有填写,则在模板调试和配置告警通知时需要手动填写
-      </div>
-      <div> 收信人ID获取路径:“钉钉管理后台”--“通讯录”--“查看用户”</div>
-      <div> 收信部门ID获取路径:“钉钉管理后台”--“通讯录”--“编辑部门”</div>
-      <div className="image">
-        <Image width="100%" src={userId} />
-        <Image width="100%" src={dept} />
+        若不填写收信人,则在模板调试和配置告警通知时手动填写。
       </div>
+      {/*<div> 收信人ID获取路径:“钉钉管理后台”--“通讯录”--“查看用户”</div>*/}
+      {/*<div> 收信部门ID获取路径:“钉钉管理后台”--“通讯录”--“编辑部门”</div>*/}
+      {/*<div className="image">*/}
+      {/*  <Image width="100%" src={userId} />*/}
+      {/*  <Image width="100%" src={dept} />*/}
+      {/*</div>*/}
       <h2> 4、模板内容</h2>
       <div>
         支持填写带变量的动态模板。变量填写规范示例:${a}

+ 2 - 2
src/pages/notice/Template/Detail/doc/DingTalkRebot.tsx

@@ -6,8 +6,8 @@ const DingTalkRebot = () => {
     <div className="doc">
       <div className="url">
         钉钉管理后台:
-        <a href="https://www.dingtalk.com" target="_blank" rel="noopener noreferrer">
-          https://www.dingtalk.com
+        <a href="https://open-dev.dingtalk.com" target="_blank" rel="noopener noreferrer">
+          https://open-dev.dingtalk.com
         </a>
       </div>
       <h1>1. 概述</h1>

+ 1 - 1
src/pages/rule-engine/DashBoard/index.tsx

@@ -126,7 +126,7 @@ const Dashboard = observer(() => {
         series: [
           {
             name: '告警数',
-            data: fifteenData.map((item) => item.value),
+            data: fifteenData.sort((a,b) => b.timestamp - a.timestamp).map((item) => item.value),
             type: 'bar',
             itemStyle: {
               color: '#2F54EB',

+ 1 - 1
src/pages/rule-engine/Instance/index.tsx

@@ -231,7 +231,7 @@ const Instance = () => {
           style={{ padding: 0 }}
           disabled={record.state.value !== 'disable'}
           tooltip={{
-            title: record.state.value !== 'disable' ? '请先禁用,再删除' : '',
+            title: record.state.value !== 'disable' ? '请先禁用,再删除' : '删除',
           }}
           popConfirm={{
             title: '确认删除',

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

@@ -218,7 +218,7 @@ export default observer((props: { parentId: string }) => {
             <Tooltip
               title={intl.formatMessage({
                 id: 'pages.system.role.option.unBindUser',
-                defaultMessage: '删除',
+                defaultMessage: '解绑',
               })}
             >
               <DisconnectOutlined />

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

@@ -140,7 +140,7 @@ const Member = observer((props: { parentId: string }) => {
             <Tooltip
               title={intl.formatMessage({
                 id: 'pages.system.role.option.unBindUser',
-                defaultMessage: '解',
+                defaultMessage: '解绑',
               })}
             >
               <DisconnectOutlined />

+ 95 - 92
src/pages/system/Menu/Detail/buttons.tsx

@@ -250,7 +250,7 @@ export default (props: ButtonsProps) => {
         search={false}
         columnEmptyText={''}
         pagination={false}
-        toolBarRender={() => [
+        headerTitle={[
           <PermissionButton
             onClick={() => {
               if (!props.data) {
@@ -272,102 +272,105 @@ export default (props: ButtonsProps) => {
           </PermissionButton>,
         ]}
       />
-      <Modal
-        maskClosable={false}
-        width={660}
-        visible={visible}
-        title={handleTitle()}
-        onOk={() => {
-          if (!disabled) {
-            saveData();
-          } else {
+      {
+        visible &&
+        <Modal
+          maskClosable={false}
+          width={660}
+          visible={visible}
+          title={handleTitle()}
+          onOk={() => {
+            if (!disabled) {
+              saveData();
+            } else {
+              resetForm();
+              setVisible(false);
+            }
+          }}
+          onCancel={() => {
             resetForm();
             setVisible(false);
-          }
-        }}
-        onCancel={() => {
-          resetForm();
-          setVisible(false);
-        }}
-        confirmLoading={loading}
-      >
-        <Form form={form} layout={'vertical'}>
-          <Form.Item
-            name="id"
-            label={intl.formatMessage({
-              id: 'pages.system.org.encoding',
-              defaultMessage: '编码',
-            })}
-            required={true}
-            rules={[
-              { required: true, message: '请输入编码' },
-              { max: 64, message: '最多可输入64个字符' },
-              {
-                pattern: /^[a-zA-Z0-9`!@#$%^&*()_+\-={}|\\\]\[;':",.\/<>?]+$/,
-                message: '请输入英文+数字+特殊字符(`!@#$%^&*()_+-={}|\\][;\':",./<>?)',
-              },
-              {
-                validator: (_, value, callback) => {
-                  if (!(!disabled && id) && buttonItems.some((item) => item.id === value)) {
-                    // 判断是否为新增
-                    callback('重复编码');
-                  }
-                  callback();
+          }}
+          confirmLoading={loading}
+        >
+          <Form form={form} layout={'vertical'}>
+            <Form.Item
+              name="id"
+              label={intl.formatMessage({
+                id: 'pages.system.org.encoding',
+                defaultMessage: '编码',
+              })}
+              required={true}
+              rules={[
+                { required: true, message: '请输入编码' },
+                { max: 64, message: '最多可输入64个字符' },
+                {
+                  pattern: /^[a-zA-Z0-9`!@#$%^&*()_+\-={}|\\\]\[;':",.\/<>?]+$/,
+                  message: '请输入英文+数字+特殊字符(`!@#$%^&*()_+-={}|\\][;\':",./<>?)',
                 },
-              },
-            ]}
-          >
-            <Input disabled={!!(disabled || id)} placeholder={'请输入编码'} />
-          </Form.Item>
-          <Form.Item
-            name="name"
-            label={intl.formatMessage({
-              id: 'pages.table.name',
-              defaultMessage: '名称',
-            })}
-            required={true}
-            rules={[
-              { required: true, message: '请输入名称' },
-              { max: 64, message: '最多可输入64个字符' },
-            ]}
-          >
-            <Input disabled={disabled} placeholder={'请输入名称'} />
-          </Form.Item>
-          <Form.Item
-            label={intl.formatMessage({
-              id: 'page.system.menu.permissions',
-              defaultMessage: '权限',
-            })}
-            required={true}
-          >
-            <Input
-              allowClear
-              onChange={debounce(filterThree, 500)}
-              style={{ width: 300, marginBottom: 12 }}
-              placeholder={'请输入权限名称'}
-            />
-            <Form.Item name="permissions" rules={[{ required: true, message: '请选择权限' }]}>
-              <Permission
-                title={intl.formatMessage({
-                  id: 'page.system.menu.permissions.operate',
-                  defaultMessage: '权限操作',
-                })}
-                disabled={disabled}
-                data={permissions}
+                {
+                  validator: (_, value, callback) => {
+                    if (!(!disabled && id) && buttonItems.some((item) => item.id === value)) {
+                      // 判断是否为新增
+                      callback('重复编码');
+                    }
+                    callback();
+                  },
+                },
+              ]}
+            >
+              <Input disabled={!!(disabled || id)} placeholder={'请输入编码'} />
+            </Form.Item>
+            <Form.Item
+              name="name"
+              label={intl.formatMessage({
+                id: 'pages.table.name',
+                defaultMessage: '名称',
+              })}
+              required={true}
+              rules={[
+                { required: true, message: '请输入名称' },
+                { max: 64, message: '最多可输入64个字符' },
+              ]}
+            >
+              <Input disabled={disabled} placeholder={'请输入名称'} />
+            </Form.Item>
+            <Form.Item
+              label={intl.formatMessage({
+                id: 'page.system.menu.permissions',
+                defaultMessage: '权限',
+              })}
+              required={true}
+            >
+              <Input
+                allowClear
+                onChange={debounce(filterThree, 500)}
+                style={{ width: 300, marginBottom: 12 }}
+                placeholder={'请输入权限名称'}
               />
+              <Form.Item name="permissions" rules={[{ required: true, message: '请选择权限' }]}>
+                <Permission
+                  title={intl.formatMessage({
+                    id: 'page.system.menu.permissions.operate',
+                    defaultMessage: '权限操作',
+                  })}
+                  disabled={disabled}
+                  data={permissions}
+                />
+              </Form.Item>
             </Form.Item>
-          </Form.Item>
-          <Form.Item
-            name="description"
-            label={intl.formatMessage({
-              id: 'pages.table.describe',
-              defaultMessage: '说明',
-            })}
-          >
-            <Input.TextArea disabled={disabled} placeholder={'请输入说明'} />
-          </Form.Item>
-        </Form>
-      </Modal>
+            <Form.Item
+              name="description"
+              label={intl.formatMessage({
+                id: 'pages.table.describe',
+                defaultMessage: '说明',
+              })}
+            >
+              <Input.TextArea disabled={disabled} placeholder={'请输入说明'} />
+            </Form.Item>
+          </Form>
+        </Modal>
+      }
     </>
   );
 };

+ 60 - 11
src/pages/system/Menu/Setting/baseMenu.ts

@@ -6,6 +6,7 @@ export default [
     id: '1',
     url: '/iot',
     icon: 'icon-wulianwang',
+    sortIndex: 1,
     permissions: [
       {
         actions: ['query', 'save', 'delete'],
@@ -20,6 +21,7 @@ export default [
         id: '1-1',
         url: '/iot/home',
         icon: 'icon-keshihua',
+        sortIndex: 1,
         permissions: [
           { permission: 'device-instance', actions: ['query'] },
           { permission: 'dashboard', actions: ['query'] },
@@ -33,6 +35,7 @@ export default [
         id: '1-2',
         url: '/iot/notice/Type',
         icon: 'icon-shebei',
+        sortIndex: 2,
         permissions: [
           { permission: 'template', actions: ['query', 'save', 'delete'] },
           { permission: 'user-third-party-manager', actions: ['query', 'save'] },
@@ -58,6 +61,7 @@ export default [
         id: '1-3',
         url: '/iot/device',
         icon: 'icon-shebei',
+        sortIndex: 3,
         permissions: [],
         children: [
           {
@@ -67,6 +71,7 @@ export default [
             id: '1-3-1',
             url: '/iot/device/DashBoard',
             icon: 'icon-keshihua',
+            sortIndex: 1,
             permissions: [
               { permission: 'device-product', actions: ['query'] },
               { permission: 'dashboard', actions: ['query'] },
@@ -81,6 +86,7 @@ export default [
             id: '1-3-2',
             url: '/iot/device/Product',
             icon: 'icon-chanpin',
+            sortIndex: 2,
             permissions: [
               { permission: 'device-mapping', actions: ['query', 'save'] },
               { permission: 'device-gateway', actions: ['query', 'save', 'delete'] },
@@ -153,6 +159,7 @@ export default [
             id: '1-3-3',
             url: '/iot/device/Instance',
             icon: 'icon-shebei',
+            sortIndex: 3,
             permissions: [
               { permission: 'transparent-codec', actions: ['query'] },
               { permission: 'device-api', actions: ['query-device-events'] },
@@ -224,6 +231,7 @@ export default [
             name: '产品分类',
             parentId: '1-3',
             id: '1-3-4',
+            sortIndex: 4,
             url: '/iot/device/Category',
             icon: 'icon-chanpinfenlei1',
             permissions: [{ permission: 'device-category', actions: ['query', 'save'] }],
@@ -261,12 +269,14 @@ export default [
         url: '/iot/link',
         icon: 'icon-yunweiguanli-1',
         permissions: [],
+        sortIndex: 4,
         children: [
           {
             code: 'link/DashBoard',
             name: '仪表盘',
             parentId: '1-4',
             id: '1-4-1',
+            sortIndex: 1,
             url: '/iot/link/dashboard',
             icon: 'icon-keshihua',
             permissions: [
@@ -279,6 +289,7 @@ export default [
             name: '设备接入网关',
             parentId: '1-4',
             id: '1-4-2',
+            sortIndex: 2,
             url: '/iot/link/accessConfig',
             icon: 'icon-wangguanzishebei',
             permissions: [
@@ -347,6 +358,7 @@ export default [
             name: '协议管理',
             parentId: '1-4',
             id: '1-4-3',
+            sortIndex: 3,
             url: '/iot/link/protocol',
             icon: 'icon-tongzhiguanli',
             permissions: [
@@ -400,6 +412,7 @@ export default [
             name: '日志管理',
             parentId: '1-4',
             id: '1-4-4',
+            sortIndex: 4,
             url: '/iot/link/Log',
             icon: 'icon-rizhifuwu',
             permissions: [
@@ -422,6 +435,7 @@ export default [
             name: '网络组件',
             parentId: '1-4',
             id: '1-4-5',
+            sortIndex: 5,
             url: '/iot/link/type',
             icon: 'icon-wangluozujian',
             permissions: [{ permission: 'network-config', actions: ['query', 'delete'] }],
@@ -460,6 +474,7 @@ export default [
             name: '证书管理',
             parentId: '1-4',
             id: '1-4-6',
+            sortIndex: 6,
             url: '/iot/link/Certificate',
             icon: 'icon-rizhifuwu',
             permissions: [],
@@ -486,6 +501,7 @@ export default [
             name: '流媒体服务',
             parentId: '1-4',
             id: '1-4-7',
+            sortIndex: 7,
             url: '/iot/link/Stream',
             icon: 'icon-xuanzetongdao1',
             permissions: [{ permission: 'media-server', actions: ['query', 'save', 'delete'] }],
@@ -517,6 +533,7 @@ export default [
             name: '通道配置',
             parentId: '1-4',
             id: '1-4-8',
+            sortIndex: 8,
             url: '/iot/link/Channel',
             icon: 'icon-zidingyiguize',
             permissions: [],
@@ -526,6 +543,7 @@ export default [
                 name: 'OPC UA',
                 parentId: '1-4-8',
                 id: '1-4-8-1',
+                sortIndex: 1,
                 url: '/iot/link/Channel/Opcua',
                 icon: 'icon-zhilianshebei',
                 permissions: [
@@ -585,6 +603,7 @@ export default [
                 name: 'Modbus',
                 parentId: '1-4-8',
                 id: '1-4-8-2',
+                sortIndex: 2,
                 url: '/iot/link/Channel/Modbus',
                 icon: 'icon-changjingliandong',
                 permissions: [],
@@ -603,6 +622,7 @@ export default [
             name: '远程升级',
             parentId: '1-4',
             id: '1-4-9',
+            sortIndex: 9,
             url: '/iot/link/firmware',
             icon: 'icon-wangluozujian',
             permissions: [
@@ -643,6 +663,7 @@ export default [
         name: '告警中心',
         parentId: '1',
         id: '1-5',
+        sortIndex: 1,
         url: '/iot/Alarm',
         icon: 'icon-zidingyiguize',
         permissions: [],
@@ -653,6 +674,7 @@ export default [
             name: '仪表盘',
             parentId: '1-5',
             id: '1-5-1',
+            sortIndex: 1,
             url: '/iot/Alarm/dashboard',
             icon: 'icon-shujumoni',
             permissions: [
@@ -667,6 +689,7 @@ export default [
             name: '基础配置',
             parentId: '1-5',
             id: '1-5-3',
+            sortIndex: 2,
             url: '/iot/Alarm/Config',
             icon: 'icon-chajianguanli',
             permissions: [{ permission: 'alarm-config', actions: ['query', 'save', 'delete'] }],
@@ -686,6 +709,7 @@ export default [
             name: '告警配置',
             parentId: '1-5',
             id: '1-5-2',
+            sortIndex: 3,
             url: '/iot/Alarm/Configuration',
             icon: 'icon-chajianguanli',
             permissions: [
@@ -733,6 +757,7 @@ export default [
             name: '告警记录',
             parentId: '1-5',
             id: '1-5-4',
+            sortIndex: 4,
             url: '/iot/Alarm/Log',
             icon: 'icon-changjingliandong',
             permissions: [{ permission: 'alarm-record', actions: ['query', 'save'] }],
@@ -757,6 +782,7 @@ export default [
         name: '北向输出',
         parentId: '1',
         id: '1-6',
+        sortIndex: 6,
         url: '/iot/northbound',
         icon: 'icon-yunyunjieru',
         permissions: [],
@@ -767,6 +793,7 @@ export default [
             name: 'DuerOS',
             parentId: '1-6',
             id: '1-6-1',
+            sortIndex: 1,
             url: '/iot/northbound/DuerOS',
             icon: 'icon-yunyunjieru',
             permissions: [],
@@ -800,6 +827,7 @@ export default [
             name: '阿里云',
             parentId: '1-6',
             id: '1-6-2',
+            sortIndex: 2,
             url: '/iot/northbound/AliCloud',
             icon: 'icon-yunyunjieru',
             permissions: [],
@@ -834,6 +862,7 @@ export default [
         name: '规则引擎',
         parentId: '1',
         id: '1-7',
+        sortIndex: 7,
         url: '/iot/rule-engine',
         icon: 'icon-zidingyiguize',
         permissions: [],
@@ -844,6 +873,7 @@ export default [
             name: '规则编排',
             parentId: '1-7',
             id: '1-7-1',
+            sortIndex: 1,
             url: '/iot/rule-engine/Instance',
             icon: 'icon-changjingliandong',
             permissions: [
@@ -895,6 +925,7 @@ export default [
             name: '场景联动',
             parentId: '1-7',
             id: '1-7-2',
+            sortIndex: 2,
             url: '/iot/rule-engine/scene',
             icon: 'icon-yunweiguanli-1',
             permissions: [{ permission: 'rule-scene', actions: ['query', 'save', 'delete'] }],
@@ -933,6 +964,7 @@ export default [
     id: '2',
     url: '/media',
     icon: 'icon-shipinwangguan',
+    sortIndex: 2,
     permissions: [],
     buttons: [],
     children: [
@@ -941,6 +973,7 @@ export default [
         name: '首页',
         parentId: '2',
         id: '2-1',
+        sortIndex: 1,
         url: '/media/home',
         icon: 'icon-zhihuishequ',
         permissions: [],
@@ -951,6 +984,7 @@ export default [
         name: '仪表盘',
         parentId: '2',
         id: '2-2',
+        sortIndex: 2,
         url: '/media/dashboard',
         icon: 'icon-keshihua',
         permissions: [],
@@ -961,6 +995,7 @@ export default [
         name: '视频设备',
         parentId: '2',
         id: '2-3',
+        sortIndex: 3,
         url: '/media/device',
         icon: 'icon-keshihua',
         permissions: [
@@ -1025,6 +1060,7 @@ export default [
         name: '分屏展示',
         parentId: '2',
         id: '2-4',
+        sortIndex: 4,
         url: '/media/SplitScreen',
         icon: 'icon-fenpingzhanshi1',
         permissions: [
@@ -1047,6 +1083,7 @@ export default [
         name: '国标级联',
         parentId: '2',
         id: '2-5',
+        sortIndex: 5,
         url: '/media/Cascade',
         icon: 'icon-guojijilian',
         permissions: [
@@ -1118,6 +1155,7 @@ export default [
     id: '3',
     url: '/system',
     icon: 'icon-xitongguanli1',
+    sortIndex: 3,
     permissions: [{ permission: 'menu', actions: ['query', 'save', 'grant', 'delete'] }],
     buttons: [],
     children: [
@@ -1126,6 +1164,7 @@ export default [
         name: '基础配置',
         parentId: '3',
         id: '3-1',
+        sortIndex: 1,
         url: '/system/Basis',
         icon: 'icon-shezhi',
         permissions: [
@@ -1145,6 +1184,7 @@ export default [
         name: '用户管理',
         parentId: '3',
         id: '3-2',
+        sortIndex: 2,
         url: '/system/user',
         icon: 'icon-yonghuguanli',
         permissions: [
@@ -1201,9 +1241,22 @@ export default [
         name: '部门管理',
         parentId: '3',
         id: '3-3',
+        sortIndex: 3,
         url: '/system/Department',
         icon: 'icon-bumenguanli',
         permissions: [
+
+          { permission: 'assets-bind', actions: ['bind', 'unbind', 'query', 'permission'] },
+          { permission: 'role', actions: ['query', 'save', 'delete'] },
+          { permission: 'device-category', actions: ['query', 'save', 'delete'] },
+          { permission: 'device-instance', actions: ['query', 'save', 'delete'] },
+          {
+            permission: 'user',
+            actions: ['query', 'save', 'update-self-info', 'update-self-pwd', 'delete'],
+          },
+          { permission: 'device-product', actions: ['query', 'save', 'delete'] },
+        ],
+        buttons: [
           {
             id: 'view',
             name: '查看',
@@ -1243,23 +1296,13 @@ export default [
             permissions: [{ permission: 'organization', actions: ['query', 'save'] }],
           },
         ],
-        buttons: [
-          { permission: 'assets-bind', actions: ['bind', 'unbind', 'query', 'permission'] },
-          { permission: 'role', actions: ['query', 'save', 'delete'] },
-          { permission: 'device-category', actions: ['query', 'save', 'delete'] },
-          { permission: 'device-instance', actions: ['query', 'save', 'delete'] },
-          {
-            permission: 'user',
-            actions: ['query', 'save', 'update-self-info', 'update-self-pwd', 'delete'],
-          },
-          { permission: 'device-product', actions: ['query', 'save', 'delete'] },
-        ],
       },
       {
         code: 'system/Role',
         name: '角色管理',
         parentId: '3',
         id: '3-4',
+        sortIndex: 4,
         url: '/system/Role',
         icon: 'icon-jiaoseguanli',
         permissions: [
@@ -1302,6 +1345,7 @@ export default [
         name: '菜单管理',
         parentId: '3',
         id: '3-5',
+        sortIndex: 5,
         url: '/system/Menu',
         icon: 'icon-caidanguanli',
         permissions: [
@@ -1350,6 +1394,7 @@ export default [
         name: '权限管理',
         parentId: '3',
         id: '3-6',
+        sortIndex: 6,
         url: '/system/Permission',
         icon: 'icon-quanxianguanli',
         permissions: [
@@ -1404,6 +1449,7 @@ export default [
         name: '第三方平台',
         parentId: '3',
         id: '3-7',
+        sortIndex: 7,
         url: '/system/platforms',
         icon: 'icon-xitongguanli1',
         permissions: [{ permission: 'open-api', actions: ['query', 'save', 'delete'] }],
@@ -1436,6 +1482,7 @@ export default [
         name: '关系配置',
         parentId: '3',
         id: '3-8',
+        sortIndex: 8,
         url: '/system/Relationship',
         icon: 'icon-renyuan',
         permissions: [{ permission: 'relation', actions: ['query', 'save', 'delete'] }],
@@ -1463,6 +1510,7 @@ export default [
         name: '数据源管理',
         parentId: '3',
         id: '3-9',
+        sortIndex: 9,
         url: '/system/DataSource',
         icon: 'icon-shebei',
         permissions: [],
@@ -1499,6 +1547,7 @@ export default [
         name: 'API配置',
         parentId: '3',
         id: '3-10',
+        sortIndex: 10,
         url: '/system/Api',
         icon: 'icon-rizhifuwu',
         permissions: [{ permission: 'open-api', actions: ['query'] }],

+ 16 - 2
src/pages/system/Menu/Setting/index.tsx

@@ -7,7 +7,7 @@ import {
 } from '@ant-design/icons';
 import Tree from './tree';
 import './index.less';
-import { Button, message, Tooltip } from 'antd';
+import {Button, message, Modal, Tooltip} from 'antd';
 import BaseTreeData from './baseMenu';
 import { useEffect, useState } from 'react';
 import { HTML5Backend } from 'react-dnd-html5-backend';
@@ -32,6 +32,7 @@ export default observer(() => {
   const { minHeight } = useDomFullHeight(`.menu-setting-warp`);
   const [baseMenu, setBaseMenu] = useState<any[]>(BaseTreeData);
   const [loading, setLoading] = useState(false);
+  const [visible, setVisible] = useState(false);
 
   const finedObject = (
     data: any[],
@@ -180,6 +181,19 @@ export default observer(() => {
 
   return (
     <PageContainer>
+      <Modal
+        title={'一键拷贝'}
+        visible={visible}
+        onOk={() => {
+          MenuSettingModel.menuData = cloneDeep(baseMenu);
+          setVisible(false)
+        }}
+        onCancel={() => {
+          setVisible(false)
+        }}
+      >
+        源数据将会覆盖当前的系统菜单数据,确定要一键拷贝吗?
+      </Modal>
       <div className={'menu-setting-warp'} style={{ minHeight }}>
         <div className={'menu-setting-tip'}>
           <ExclamationCircleOutlined />
@@ -199,7 +213,7 @@ export default observer(() => {
                   type={'primary'}
                   ghost
                   onClick={() => {
-                    MenuSettingModel.menuData = cloneDeep(baseMenu);
+                    setVisible(true)
                   }}
                 >
                   一键拷贝

+ 37 - 4
src/pages/system/Menu/Setting/tree.tsx

@@ -2,7 +2,7 @@ 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 {useEffect, useState} from 'react';
 import type { TreeProps } from 'antd';
 import { cloneDeep, debounce } from 'lodash';
 import './DragItem.less';
@@ -21,15 +21,24 @@ export const DragType = 'DragBox';
 
 const { TreeNode } = Tree;
 
+const defaultExpandedKeys = ['iot', 'media', 'system', 'device', 'link', 'link/Channel', 'rule-engine/Alarm', 'Northbound', 'rule-engine']
+
 export default (props: TreeBodyProps) => {
   const [newData, setNewData] = useState(props.treeData);
   const [searchKeys, setSearchKeys] = useState<(string | number)[]>([]);
   const [expandedKeys, setExpandedKeys] = useState<(string | number)[]>([]);
+  const [autoExpandParent, setAutoExpandParent] = useState(true);
 
   useEffect(() => {
     setNewData(cloneDeep(props.treeData));
   }, [props.treeData]);
 
+  useEffect(() => {
+    setTimeout(() => {
+      setExpandedKeys(defaultExpandedKeys)
+    }, 300)
+  }, [])
+
   const [, drop] = useDrop(() => ({
     accept: DragType,
     drop(item: any, monitor) {
@@ -91,6 +100,21 @@ export default (props: TreeBodyProps) => {
     });
   };
 
+  const getParentKey = (key: string | number, data: any): string => {
+    let parentKey: string;
+    data.forEach((item: any) => {
+      if (item.children) {
+        if (item.children.some((cItem: any) => cItem.code === key)) {
+          parentKey = item.code
+        } else if (!!getParentKey(key, item.children)) {
+          parentKey = getParentKey(key, item.children)
+        }
+      }
+    })
+    // @ts-ignore
+    return parentKey
+  }
+
   const findAllItem = (data: any[], value: string): string[] => {
     return data.reduce((pre, next) => {
       const childrenKeys = next.children ? findAllItem(next.children, value) : [];
@@ -104,12 +128,17 @@ export default (props: TreeBodyProps) => {
     const value = e.target.value;
 
     if (value) {
-      const sKeys = findAllItem(props.treeData, value);
-      setSearchKeys(sKeys);
-      setExpandedKeys(sKeys);
+
+      const newKeys = findAllItem(props.treeData, value);
+      const newExpandedKeys = newKeys.map(key => {
+        return getParentKey(key, props.treeData)
+      })
+      setSearchKeys(newKeys);
+      setExpandedKeys(newExpandedKeys);
     } else {
       setSearchKeys([]);
     }
+    setAutoExpandParent(true)
   };
 
   return (
@@ -128,7 +157,9 @@ export default (props: TreeBodyProps) => {
             expandedKeys={expandedKeys}
             onExpand={(_expandedKeys) => {
               setExpandedKeys(_expandedKeys);
+              setAutoExpandParent(false)
             }}
+            autoExpandParent={autoExpandParent}
           >
             {createTreeNode(newData, props.droppableId)}
           </Tree>
@@ -139,7 +170,9 @@ export default (props: TreeBodyProps) => {
             expandedKeys={expandedKeys}
             onExpand={(_expandedKeys) => {
               setExpandedKeys(_expandedKeys);
+              setAutoExpandParent(false)
             }}
+            autoExpandParent={autoExpandParent}
             draggable={{
               icon: false,
             }}

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

@@ -261,7 +261,7 @@ export default observer(() => {
         search={false}
         params={param}
         request={async (params) => {
-          const response = await service.queryMenuThree({ ...params, paging: false });
+          const response = await service.queryMenuThree({ ...params, sorts: [{ name: 'sortIndex', order: 'asc'}], paging: false });
           return {
             code: response.message,
             result: {
@@ -290,7 +290,7 @@ export default observer(() => {
           </PermissionButton>,
           <PermissionButton
             style={{ marginLeft: 12 }}
-            isPermission={permission.action}
+            isPermission={permission.add}
             onClick={() => {
               history.push(getMenuPathByCode('system/Menu/Setting'));
             }}

+ 51 - 33
src/pages/user/Login/index.tsx

@@ -156,39 +156,57 @@ const Login: React.FC = () => {
 
   const doLogin = async (data: LoginParam) => {
     setLoading(true);
-    Service.login({ expires: loginRef.current.expires, verifyKey: captcha.key, ...data }).subscribe(
-      {
-        next: async (userInfo) => {
-          Token.set(userInfo.token);
-          const userRef: any = await fetchUserInfo();
-          if (userRef?.user?.username === 'admin') {
-            const initRef = await Service.initPage()
-            if (initRef.status === 200 && !initRef.result.length) {
-              window.location.href = '/#/init-home';
-              setLoading(false);
-              return
-            }
-          }
-          // goto();
-          window.location.href = '/';
-          setLoading(false);
-        },
-        error: () => {
-          message.error(
-            intl.formatMessage({
-              id: 'pages.login.failure',
-              defaultMessage: '登录失败,请重试!',
-            }),
-          );
-          getCode();
-          // setLoading(false);
-        },
-        complete: () => {
-          // getCode();
-          // setLoading(false);
-        },
-      },
-    );
+    const res = await Service.login2({ expires: loginRef.current.expires, verifyKey: captcha.key, ...data })
+    setLoading(false)
+    if (res.status === 200) {
+      const userInfo = res.result
+      Token.set(userInfo.token);
+      const userRef: any = await fetchUserInfo();
+      if (userRef?.user?.username === 'admin') {
+        const initRef = await Service.initPage()
+        if (initRef.status === 200 && !initRef.result.length) {
+          window.location.href = '/#/init-home';
+          return
+        }
+      }
+      window.location.href = '/';
+    } else {
+      getCode();
+      setLoading(false);
+    }
+    // Service.login({ expires: loginRef.current.expires, verifyKey: captcha.key, ...data }).subscribe(
+    //   {
+    //     next: async (userInfo) => {
+    //       Token.set(userInfo.token);
+    //       const userRef: any = await fetchUserInfo();
+    //       if (userRef?.user?.username === 'admin') {
+    //         const initRef = await Service.initPage()
+    //         if (initRef.status === 200 && !initRef.result.length) {
+    //           window.location.href = '/#/init-home';
+    //           setLoading(false);
+    //           return
+    //         }
+    //       }
+    //       // goto();
+    //       window.location.href = '/';
+    //       setLoading(false);
+    //     },
+    //     error: () => {
+    //       message.error(
+    //         intl.formatMessage({
+    //           id: 'pages.login.failure',
+    //           defaultMessage: '登录失败,请重试!',
+    //         }),
+    //       );
+    //       getCode();
+    //       // setLoading(false);
+    //     },
+    //     complete: () => {
+    //       // getCode();
+    //       // setLoading(false);
+    //     },
+    //   },
+    // );
   };
   return (
     <Spin spinning={loading} delay={500}>

+ 4 - 0
src/pages/user/Login/service.ts

@@ -37,6 +37,10 @@ const Service = {
         map((resp) => resp.result),
       ),
     ),
+  login2: (data: LoginParam) => request(`/${SystemConst.API_BASE}/authorize/login`, {
+    method: 'POST',
+    data,
+  }),
 
   queryCurrent: () =>
     request(`/${SystemConst.API_BASE}/authorize/me`, {