lind пре 3 година
родитељ
комит
bac2fde2e6

BIN
public/images/network.png


+ 2 - 0
src/components/FBraftEditor/index.tsx

@@ -6,6 +6,7 @@ import { useState } from 'react';
 interface Props extends BraftEditorProps {
 interface Props extends BraftEditorProps {
   value: any;
   value: any;
   onChange: (data: any) => void;
   onChange: (data: any) => void;
+  placeholder?: string;
 }
 }
 
 
 const FBraftEditor = connect((props: Props) => {
 const FBraftEditor = connect((props: Props) => {
@@ -18,6 +19,7 @@ const FBraftEditor = connect((props: Props) => {
       {
       {
         // @ts-ignore
         // @ts-ignore
         <BraftEditor
         <BraftEditor
+          placeholder={props.placeholder}
           value={editorState}
           value={editorState}
           onChange={(state) => {
           onChange={(state) => {
             setEditorState(state);
             setEditorState(state);

+ 32 - 33
src/components/Footer/index.tsx

@@ -1,37 +1,36 @@
-import { useIntl } from 'umi';
-import { GithubOutlined } from '@ant-design/icons';
-import { DefaultFooter } from '@ant-design/pro-layout';
+// import {useIntl} from 'umi';
+// import {GithubOutlined} from '@ant-design/icons';
+// import {DefaultFooter} from '@ant-design/pro-layout';
 
 
 export default () => {
 export default () => {
-  const intl = useIntl();
-  const defaultMessage = intl.formatMessage({
-    id: 'app.copyright.produced',
-    defaultMessage: 'Jetlinks Team',
-  });
+  // const intl = useIntl();
+  // const defaultMessage = intl.formatMessage({
+  //   id: 'app.copyright.produced',
+  //   defaultMessage: 'Jetlinks Team',
+  // });
 
 
-  return (
-    <DefaultFooter
-      copyright={`2021 ${defaultMessage}`}
-      links={[
-        {
-          key: 'Jetlinks',
-          title: 'Jetlinks',
-          href: 'https://pro.ant.design',
-          blankTarget: true,
-        },
-        {
-          key: 'github',
-          title: <GithubOutlined />,
-          href: 'https://github.com/jetlinks',
-          blankTarget: true,
-        },
-        {
-          key: 'Ant Design',
-          title: 'Ant Design',
-          href: 'https://ant.design',
-          blankTarget: true,
-        },
-      ]}
-    />
-  );
+  // const footer = <DefaultFooter
+  //   copyright={`2021 ${defaultMessage}`}
+  //   links={[
+  //     {
+  //       key: 'Jetlinks',
+  //       title: 'Jetlinks',
+  //       href: 'https://pro.ant.design',
+  //       blankTarget: true,
+  //     },
+  //     {
+  //       key: 'github',
+  //       title: <GithubOutlined/>,
+  //       href: 'https://github.com/jetlinks',
+  //       blankTarget: true,
+  //     },
+  //     {
+  //       key: 'Ant Design',
+  //       title: 'Ant Design',
+  //       href: 'https://ant.design',
+  //       blankTarget: true,
+  //     },
+  //   ]}
+  // />
+  return null;
 };
 };

+ 80 - 0
src/components/ProTableCard/CardItems/networkCard.tsx

@@ -0,0 +1,80 @@
+import React from 'react';
+import { TableCard } from '@/components';
+import '@/style/common.less';
+import '../index.less';
+import { NetworkItem } from '@/pages/link/Type/typings';
+import { networkMap } from '@/pages/link/Type';
+import { StatusColorEnum } from '@/components/BadgeStatus';
+import { Tooltip } from 'antd';
+
+export interface NoticeCardProps extends NetworkItem {
+  detail?: React.ReactNode;
+  actions?: React.ReactNode[];
+  avatarSize?: number;
+}
+
+const image = require('/public/images/network.png');
+
+export default (props: NoticeCardProps) => {
+  const createDetail = () => {
+    const record = props;
+    if (record.shareCluster) {
+      const publicHost = record.configuration.publicHost;
+      const publicPort = record.configuration.publicPort;
+      return publicHost ? (
+        <>
+          {networkMap[record.type]}
+          {publicHost}:{publicPort}
+        </>
+      ) : null;
+    } else {
+      const log = record.cluster?.map(
+        (item) => `${item.configuration.publicHost}:${item.configuration.publicPort}`,
+      );
+      return (
+        <>
+          {log.map((item) => (
+            <div key={item}>
+              `${networkMap[record.type]}${item}`
+            </div>
+          ))}
+        </>
+      );
+    }
+  };
+  return (
+    <TableCard
+      actions={props.actions}
+      status={props.state.value}
+      statusText={props.state.text}
+      statusNames={{
+        disabled: StatusColorEnum.error,
+        enabled: StatusColorEnum.processing,
+      }}
+      showMask={false}
+    >
+      <div className={'pro-table-card-item'}>
+        <div className={'card-item-avatar'}>
+          <img width={88} height={88} src={image} alt={props.type} />
+        </div>
+        <div className={'card-item-body'}>
+          <div className={'card-item-header'}>
+            <span className={'card-item-header-name ellipsis'}>{props.name}</span>
+          </div>
+          <div className={'card-item-content'}>
+            <div>
+              <label>类型</label>
+              <div className={'ellipsis'}>{props.type}</div>
+            </div>
+            <div>
+              <label>详情</label>
+              <Tooltip title={createDetail()}>
+                <div className={'ellipsis'}>{createDetail()}</div>
+              </Tooltip>
+            </div>
+          </div>
+        </div>
+      </div>
+    </TableCard>
+  );
+};

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

@@ -1,7 +1,7 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import { PageContainer } from '@ant-design/pro-layout';
 import { InstanceModel, service } from '@/pages/device/Instance';
 import { InstanceModel, service } from '@/pages/device/Instance';
 import { history, useParams } from 'umi';
 import { history, useParams } from 'umi';
-import { Badge, Button, Card, Descriptions, Divider, message, Tooltip } from 'antd';
+import { Badge, Button, Card, Descriptions, Divider, message, Popconfirm, Tooltip } from 'antd';
 import type { ReactNode } from 'react';
 import type { ReactNode } from 'react';
 import { useEffect, useState } from 'react';
 import { useEffect, useState } from 'react';
 import { observer } from '@formily/react';
 import { observer } from '@formily/react';
@@ -70,9 +70,11 @@ const InstanceDetail = observer(() => {
           <Metadata
           <Metadata
             type="device"
             type="device"
             tabAction={
             tabAction={
-              <Tooltip title="重置后将使用产品的物模型配置">
-                <Button onClick={resetMetadata}>重置操作</Button>
-              </Tooltip>
+              <Popconfirm title="确认重置?" onConfirm={resetMetadata}>
+                <Tooltip title="重置后将使用产品的物模型配置">
+                  <Button>重置操作</Button>
+                </Tooltip>
+              </Popconfirm>
             }
             }
           />
           />
         </Card>
         </Card>

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

@@ -582,7 +582,7 @@ const Edit = observer((props: Props) => {
             },
             },
           },
           },
           type: {
           type: {
-            title: '属性类型',
+            title: MetadataModel.type === 'tags' ? '标签类型' : '属性类型',
             required: true,
             required: true,
             'x-decorator': 'FormItem',
             'x-decorator': 'FormItem',
             'x-component': 'Select',
             'x-component': 'Select',

+ 12 - 10
src/pages/device/components/Metadata/Base/index.tsx

@@ -144,16 +144,18 @@ const BaseMetadata = observer((props: Props) => {
           },
           },
         }}
         }}
         toolBarRender={() => [
         toolBarRender={() => [
-          <Button
-            onClick={() => {
-              MetadataModel.importMetadata = true;
-            }}
-            key="button"
-            icon={<ImportOutlined />}
-            type="ghost"
-          >
-            导入属性
-          </Button>,
+          props.type === 'properties' && (
+            <Button
+              onClick={() => {
+                MetadataModel.importMetadata = true;
+              }}
+              key="button"
+              icon={<ImportOutlined />}
+              type="ghost"
+            >
+              导入属性
+            </Button>
+          ),
           <Button
           <Button
             onClick={() => {
             onClick={() => {
               MetadataModel.edit = true;
               MetadataModel.edit = true;

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

@@ -776,7 +776,7 @@ const Save = observer(() => {
     }
     }
   };
   };
   return (
   return (
-    <PageContainer onBack={() => history.back()}>
+    <PageContainer className={'page-title-show'} onBack={() => history.back()}>
       <Card>
       <Card>
         <Form form={form} layout="vertical" style={{ padding: 30 }}>
         <Form form={form} layout="vertical" style={{ padding: 30 }}>
           <SchemaField
           <SchemaField

+ 92 - 7
src/pages/link/Type/index.tsx

@@ -1,6 +1,5 @@
 import { useRef, useState } from 'react';
 import { useRef, useState } from 'react';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
-import ProTable from '@jetlinks/pro-table';
 import { Badge, Button, message, Popconfirm, Tooltip } from 'antd';
 import { Badge, Button, message, Popconfirm, Tooltip } from 'antd';
 import {
 import {
   CloseCircleOutlined,
   CloseCircleOutlined,
@@ -17,6 +16,8 @@ import { getButtonPermission, getMenuPathByParams, MENUS_CODE } from '@/utils/me
 import { history } from 'umi';
 import { history } from 'umi';
 import Service from '@/pages/link/service';
 import Service from '@/pages/link/service';
 import { Store } from 'jetlinks-store';
 import { Store } from 'jetlinks-store';
+import { ProTableCard } from '@/components';
+import NetworkCard from '@/components/ProTableCard/CardItems/networkCard';
 
 
 export const service = new Service('network/config');
 export const service = new Service('network/config');
 
 
@@ -29,6 +30,16 @@ const pageJump = (id?: string) => {
   history.push(`${getMenuPathByParams(MENUS_CODE['link/Type/Detail'], id)}`);
   history.push(`${getMenuPathByParams(MENUS_CODE['link/Type/Detail'], id)}`);
 };
 };
 
 
+export const networkMap = {
+  UDP: 'udp://',
+  TCP_SERVER: 'tcp://',
+  WEB_SOCKET_SERVER: 'ws://',
+  MQTT_CLIENT: 'mqtt://',
+  HTTP_SERVER: 'http://',
+  MQTT_SERVER: 'mqtt://',
+  COAP_SERVER: 'coap://',
+};
+
 const Network = () => {
 const Network = () => {
   const intl = useIntl();
   const intl = useIntl();
   const actionRef = useRef<ActionType>();
   const actionRef = useRef<ActionType>();
@@ -60,11 +71,12 @@ const Network = () => {
         if (record.shareCluster) {
         if (record.shareCluster) {
           const publicHost = record.configuration.publicHost;
           const publicHost = record.configuration.publicHost;
           const publicPort = record.configuration.publicPort;
           const publicPort = record.configuration.publicPort;
-          return (
+          return publicHost ? (
             <>
             <>
-              公网: {publicHost}:{publicPort}
+              {networkMap[record.type]}
+              {publicHost}:{publicPort}
             </>
             </>
-          );
+          ) : null;
         } else {
         } else {
           const log = record.cluster?.map(
           const log = record.cluster?.map(
             (item) => `${item.configuration.publicHost}:${item.configuration.publicPort}`,
             (item) => `${item.configuration.publicHost}:${item.configuration.publicPort}`,
@@ -72,7 +84,9 @@ const Network = () => {
           return (
           return (
             <>
             <>
               {log.map((item) => (
               {log.map((item) => (
-                <div key={item}>公网:{item}</div>
+                <div key={item}>
+                  `${networkMap[record.type]}${item}`
+                </div>
               ))}
               ))}
             </>
             </>
           );
           );
@@ -114,7 +128,7 @@ const Network = () => {
             pageJump(record.id);
             pageJump(record.id);
           }}
           }}
         >
         >
-          <Tooltip title="查看">
+          <Tooltip title="编辑">
             <EditOutlined />
             <EditOutlined />
           </Tooltip>
           </Tooltip>
         </Button>,
         </Button>,
@@ -198,7 +212,7 @@ const Network = () => {
           setParam(data);
           setParam(data);
         }}
         }}
       />
       />
-      <ProTable<NetworkItem>
+      <ProTableCard<NetworkItem>
         actionRef={actionRef}
         actionRef={actionRef}
         params={param}
         params={param}
         columns={columns}
         columns={columns}
@@ -222,6 +236,77 @@ const Network = () => {
         request={async (params) =>
         request={async (params) =>
           service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
           service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
         }
         }
+        gridColumn={3}
+        cardRender={(record) => (
+          <NetworkCard
+            {...record}
+            actions={[
+              <Button
+                key="edit"
+                onClick={() => {
+                  Store.set('current-network-data', record);
+                  pageJump(record.id);
+                }}
+              >
+                <EditOutlined />
+                编辑
+              </Button>,
+              <Tooltip title={record.state.value === 'enabled' ? '禁用' : '启用'}>
+                <Popconfirm
+                  disabled={getButtonPermission('link/Type', ['action'])}
+                  title={`确认${record.state.value === 'enabled' ? '禁用' : '启用'}?`}
+                  onConfirm={async () => {
+                    // await service.update({
+                    //   id: record.id,
+                    //   status: record.status ? 0 : 1,
+                    // });
+                    const map = {
+                      disabled: 'start',
+                      enabled: 'shutdown',
+                    };
+                    await service.changeState(record.id, map[record.state.value]);
+                    message.success(
+                      intl.formatMessage({
+                        id: 'pages.data.option.success',
+                        defaultMessage: '操作成功!',
+                      }),
+                    );
+                    actionRef.current?.reload();
+                  }}
+                >
+                  <Button
+                    type="link"
+                    style={{ padding: 0 }}
+                    disabled={getButtonPermission('link/Type', ['action'])}
+                    key="changeState"
+                  >
+                    {record.state.value === 'enabled' ? (
+                      <CloseCircleOutlined />
+                    ) : (
+                      <PlayCircleOutlined />
+                    )}
+                    {record.state.value === 'enabled' ? '禁用' : '启用'}
+                  </Button>
+                </Popconfirm>
+              </Tooltip>,
+              <Popconfirm
+                key="delete"
+                title="确认删除?"
+                onConfirm={async () => {
+                  const response: any = await service.remove(record.id);
+                  if (response.status === 200) {
+                    message.success('删除成功');
+                    actionRef.current?.reload();
+                  }
+                }}
+              >
+                <Button key="delete">
+                  <DeleteOutlined />
+                </Button>
+              </Popconfirm>,
+            ]}
+          />
+        )}
       />
       />
     </PageContainer>
     </PageContainer>
   );
   );

+ 3 - 1
src/pages/notice/Config/index.tsx

@@ -242,7 +242,9 @@ const Config = observer(() => {
           </Space>
           </Space>
         }
         }
         gridColumn={3}
         gridColumn={3}
-        request={async (params) => service.query(params)}
+        request={async (params) =>
+          service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+        }
         cardRender={(record) => (
         cardRender={(record) => (
           <NoticeConfig
           <NoticeConfig
             {...record}
             {...record}

+ 13 - 8
src/pages/notice/Template/Detail/index.tsx

@@ -102,7 +102,10 @@ const Detail = observer(() => {
         effects() {
         effects() {
           onFieldInit('template.message', (field) => {
           onFieldInit('template.message', (field) => {
             if (id === 'email') {
             if (id === 'email') {
-              field.setComponent(FBraftEditor);
+              field.setComponent(FBraftEditor, {
+                placeholder:
+                  '变量格式:${name};\n 示例:尊敬的${name},${time}有设备触发告警,请注意处理',
+              });
             }
             }
           });
           });
           onFieldValueChange('provider', (field, form1) => {
           onFieldValueChange('provider', (field, form1) => {
@@ -132,7 +135,6 @@ const Detail = observer(() => {
                 });
                 });
                 break;
                 break;
               case 'officialMessage':
               case 'officialMessage':
-                // TODO 通知配置不能为空
                 form1.setFieldState('template.tagid', async (state1) => {
                 form1.setFieldState('template.tagid', async (state1) => {
                   state1.dataSource = await getWeixinOfficialTags(value);
                   state1.dataSource = await getWeixinOfficialTags(value);
                 });
                 });
@@ -837,15 +839,15 @@ const Detail = observer(() => {
                     },
                     },
                     properties: {
                     properties: {
                       code: {
                       code: {
-                        title: '模版ID',
+                        title: '模版',
                         'x-component': 'Select',
                         'x-component': 'Select',
                         'x-decorator': 'FormItem',
                         'x-decorator': 'FormItem',
                         'x-decorator-props': {
                         'x-decorator-props': {
-                          tooltip: '请输入模版ID',
+                          tooltip: '阿里云短信平台自定义的模版名称',
                           gridSpan: 1,
                           gridSpan: 1,
                         },
                         },
                         'x-component-props': {
                         'x-component-props': {
-                          placeholder: '请输入模版ID',
+                          placeholder: '请选择模版',
                         },
                         },
                         'x-reactions': {
                         'x-reactions': {
                           dependencies: ['configId'],
                           dependencies: ['configId'],
@@ -898,7 +900,10 @@ const Detail = observer(() => {
                 'x-decorator': 'FormItem',
                 'x-decorator': 'FormItem',
                 title: '标题',
                 title: '标题',
                 'x-decorator-props': {
                 'x-decorator-props': {
-                  tip: '请输入邮件标题',
+                  tip: '邮件标题',
+                },
+                'x-component-props': {
+                  placeholder: '请输入标题',
                 },
                 },
               },
               },
               sendTo: {
               sendTo: {
@@ -906,7 +911,7 @@ const Detail = observer(() => {
                 'x-decorator': 'FormItem',
                 'x-decorator': 'FormItem',
                 title: '收件人',
                 title: '收件人',
                 'x-decorator-props': {
                 'x-decorator-props': {
-                  tip: '请输入收件人邮箱,多个收件人用换行分隔',
+                  tip: '多个收件人用换行分隔 \n最大支持1000个号码',
                 },
                 },
               },
               },
               attachments: {
               attachments: {
@@ -969,7 +974,7 @@ const Detail = observer(() => {
         'x-component': 'Input.TextArea',
         'x-component': 'Input.TextArea',
         'x-decorator': 'FormItem',
         'x-decorator': 'FormItem',
         'x-decorator-props': {
         'x-decorator-props': {
-          tooltip: '请输入模版内容',
+          tooltip: '发送的内容,支持录入变量',
         },
         },
         required: true,
         required: true,
         'x-reactions': {
         'x-reactions': {

+ 3 - 1
src/pages/notice/Template/index.tsx

@@ -282,7 +282,9 @@ const Template = () => {
             ]}
             ]}
           />
           />
         )}
         )}
-        request={async (params) => service.query(params)}
+        request={async (params) =>
+          service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+        }
       />
       />
       <Debug />
       <Debug />
       <Log />
       <Log />

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

@@ -55,7 +55,7 @@ const BindUser = (props: Props) => {
   return (
   return (
     <Modal
     <Modal
       title="添加"
       title="添加"
-      width={900}
+      width={990}
       visible={props.visible}
       visible={props.visible}
       onCancel={() => {
       onCancel={() => {
         props.cancel();
         props.cancel();