xieyonghong 3 gadi atpakaļ
vecāks
revīzija
94bcde81fa

BIN
public/images/home/comprehensive.png


BIN
public/images/home/device.png


BIN
public/images/home/ops.png


+ 12 - 1
src/pages/device/Instance/Detail/Config/Edit.tsx

@@ -2,7 +2,7 @@ import { createForm } from '@formily/core';
 import { createSchemaField } from '@formily/react';
 import { InstanceModel, service } from '@/pages/device/Instance';
 import type { ISchema } from '@formily/json-schema';
-import { Form, FormGrid, FormItem, Input, Password, PreviewText } from '@formily/antd';
+import { Form, FormGrid, FormItem, Input, Password, PreviewText, Select } from '@formily/antd';
 import { Button, Drawer, Space } from 'antd';
 import { useParams } from 'umi';
 import { onlyMessage } from '@/utils/util';
@@ -10,6 +10,7 @@ import { onlyMessage } from '@/utils/util';
 const componentMap = {
   string: 'Input',
   password: 'Password',
+  enum: 'Select',
 };
 
 interface Props {
@@ -33,6 +34,7 @@ const Edit = (props: Props) => {
       FormItem,
       Input,
       Password,
+      Select,
       FormGrid,
       PreviewText,
     },
@@ -49,6 +51,15 @@ const Edit = (props: Props) => {
         'x-decorator-props': {
           tooltip: item.description,
         },
+        enum:
+          item?.type?.type === 'enum' && item?.type?.elements
+            ? (item?.type?.elements || []).map((t: { value: string; text: string }) => {
+                return {
+                  label: t.text,
+                  value: t.value,
+                };
+              })
+            : [],
       };
     });
     return config;

+ 1 - 1
src/pages/device/Instance/Detail/Running/Property/EditProperty.tsx

@@ -29,7 +29,7 @@ const EditProperty = (props: Props) => {
     properties: {
       propertyValue: {
         type: 'string',
-        title: '自定义属性',
+        title: data?.name || '自定义属性',
         required: true,
         'x-decorator': 'FormItem',
         'x-component': 'Input',

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

@@ -95,6 +95,7 @@ const Property = (props: Props) => {
               <a
                 onClick={() => {
                   setVisible(true);
+                  setCurrentInfo(record);
                 }}
               >
                 <EditOutlined />

+ 6 - 8
src/pages/device/Instance/Export/index.tsx

@@ -1,7 +1,7 @@
 import { FormItem, FormLayout, Radio, Select } from '@formily/antd';
 import { createForm } from '@formily/core';
 import { createSchemaField, FormProvider } from '@formily/react';
-import { Alert, Modal } from 'antd';
+import { Modal } from 'antd';
 import 'antd/lib/tree-select/style/index.less';
 import { useEffect, useState } from 'react';
 import { service } from '@/pages/device/Instance';
@@ -9,7 +9,6 @@ import type { DeviceInstance } from '../typings';
 import SystemConst from '@/utils/const';
 import encodeQuery from '@/utils/encodeQuery';
 import { downloadFile } from '@/utils/util';
-
 interface Props {
   visible: boolean;
   close: () => void;
@@ -115,12 +114,11 @@ const Export = (props: Props) => {
       title="导出"
       onOk={downloadTemplate}
     >
-      <Alert
-        message="选择单个产品时可导出其下属设备的详细数据,不选择产品时导出所有设备的基础数据"
-        type="warning"
-        showIcon
-        closable
-      />
+      <div style={{ background: 'rgb(236, 237, 238)' }}>
+        <p style={{ padding: 10 }}>
+          选择单个产品时可导出其下属设备的详细数据,不选择产品时导出所有设备的基础数
+        </p>
+      </div>
       <div style={{ marginTop: '20px' }}>
         <FormProvider form={form}>
           <SchemaField schema={schema} />

+ 21 - 1
src/pages/device/Product/Detail/Access/index.tsx

@@ -6,7 +6,16 @@ import type { SetStateAction } from 'react';
 import { useEffect, useState } from 'react';
 import AccessConfig from './AccessConfig';
 import ReactMarkdown from 'react-markdown';
-import { Form, FormGrid, FormItem, FormLayout, Input, Password, PreviewText } from '@formily/antd';
+import {
+  Form,
+  FormGrid,
+  FormItem,
+  FormLayout,
+  Input,
+  Password,
+  PreviewText,
+  Select,
+} from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
 import type { ConfigProperty } from '@/pages/device/Product/typings';
 import { createSchemaField } from '@formily/react';
@@ -19,6 +28,7 @@ import { onlyMessage } from '@/utils/util';
 const componentMap = {
   string: 'Input',
   password: 'Password',
+  enum: 'Select',
 };
 
 const Access = () => {
@@ -226,6 +236,7 @@ const Access = () => {
       PreviewText,
       FormItem,
       Input,
+      Select,
     },
   });
 
@@ -243,6 +254,15 @@ const Access = () => {
           labelAlign: 'left',
           layout: 'vertical',
         },
+        enum:
+          item?.type?.type === 'enum' && item?.type?.elements
+            ? (item?.type?.elements || []).map((t: { value: string; text: string }) => {
+                return {
+                  label: t.text,
+                  value: t.value,
+                };
+              })
+            : [],
       };
     });
     return obj;

+ 1 - 0
src/pages/device/Product/typings.d.ts

@@ -38,6 +38,7 @@ export type ConfigProperty = {
     name: string;
     id: string;
     type: string;
+    elements?: any[];
   };
   scopes: any[];
 };

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

@@ -662,6 +662,18 @@ const Edit = observer((props: Props) => {
                 value: 'report',
               },
             ],
+            'x-reactions': [
+              {
+                dependencies: ['.source'],
+                fulfill: {
+                  state: {
+                    value:
+                      '{{$deps[0]==="manual" ? ["write"] : $deps[0]==="rule" ? ["report"] : []}}',
+                    disabled: '{{["manual", "rule"].includes($deps[0])}}',
+                  },
+                },
+              },
+            ],
           },
           // 存储配置
           configConfig: {

+ 8 - 6
src/pages/device/components/Metadata/Import/index.tsx

@@ -40,11 +40,13 @@ const Import = (props: Props) => {
       paging: false,
       terms: [{ column: 'id$not', value: param.id }],
     })) as any;
-    field.dataSource = product.result.map((item: any) => ({
-      label: item.name,
-      value: item.metadata,
-      key: item.id,
-    }));
+    field.dataSource = product.result
+      .filter((i: any) => i?.metadata)
+      .map((item: any) => ({
+        label: item.name,
+        value: item.metadata,
+        key: item.id,
+      }));
     field.loading = false;
   };
 
@@ -213,7 +215,7 @@ const Import = (props: Props) => {
         <p style={{ padding: 10 }}>
           <span style={{ color: '#f5222d' }}>注</span>
           :导入的物模型会覆盖原来的属性、功能、事件、标签,请谨慎操作。
-          <br />
+          {/* <br /> */}
           {/*物模型格式请参考文档:*/}
           {/*<a*/}
           {/*  rel="noopener noreferrer"*/}

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

@@ -43,14 +43,17 @@ export default (props: DeviceModalProps) => {
       dataIndex: 'id',
       title: '设备ID',
       width: 220,
+      ellipsis: true,
     },
     {
       dataIndex: 'name',
       title: '设备名称',
+      ellipsis: true,
     },
     {
       dataIndex: 'productName',
       title: '产品名称',
+      ellipsis: true,
     },
     {
       dataIndex: 'modifyTime',

+ 6 - 1
src/pages/home/components/index.less

@@ -145,7 +145,7 @@
         padding: 16px 24px;
         color: #333;
         font-weight: bold;
-        font-size: 20px;
+        font-size: 14px;
         background-color: #f8f9fd;
         cursor: pointer;
 
@@ -154,6 +154,11 @@
           top: 0;
           right: 0;
           z-index: 1;
+          height: 100%;
+
+          img {
+            height: 100%;
+          }
         }
 
         > span {

+ 3 - 3
src/pages/home/comprehensive/index.tsx

@@ -126,14 +126,14 @@ const Comprehensive = () => {
       name: '设备接入配置',
       english: 'DEVICE ACCESS CONFIGURATION',
       auth: !!accessPermission,
-      url: 'link/AccessConfig',
+      url: accessPermission,
     },
     {
       key: 'logger',
       name: '日志排查',
       english: 'LOG SCREEN',
       auth: !!logPermission,
-      url: 'Log',
+      url: logPermission,
       param: {
         key: 'system',
       },
@@ -143,7 +143,7 @@ const Comprehensive = () => {
       name: '实时监控',
       english: 'REAL-TIME MONITORING',
       auth: !!linkPermission,
-      url: 'link/DashBoard',
+      url: linkPermission,
       param: {
         save: true,
       },

+ 9 - 3
src/pages/home/init/index.less

@@ -1,13 +1,16 @@
+@import '~antd/es/style/themes/default.less';
+
 .homeBox {
   display: flex;
   flex-direction: column;
   align-items: center;
   width: 100%;
   height: calc(100vh - 150px);
+  padding: 20px;
   background-color: white;
 }
 .title {
-  margin-top: 48px;
+  margin-top: 28px;
   margin-bottom: 48px;
   font-weight: 400;
   font-size: 26px;
@@ -19,8 +22,11 @@
   flex-direction: column;
   align-items: center;
 
+  &.active {
+    border: 2px solid @primary-color-active;
+  }
+
   img {
-    width: 80%;
-    margin-bottom: 10px;
+    width: 100%;
   }
 }

+ 18 - 13
src/pages/home/init/index.tsx

@@ -1,4 +1,5 @@
-import { Button, Col, Radio, Row } from 'antd';
+import { Button, Col, Row } from 'antd';
+import classNames from 'classnames';
 import { useState } from 'react';
 import { service } from '..';
 import styles from './index.less';
@@ -30,18 +31,22 @@ const Init = (props: Props) => {
   return (
     <div className={styles.homeBox}>
       <div className={styles.title}>请选择首页视图</div>
-      <Radio.Group value={value} onChange={(e) => setValue(e.target.value)}>
-        <Row gutter={24}>
-          {viewMap.map((item) => (
-            <Col span={8} key={item.value}>
-              <div className={styles.item}>
-                <img src={item.img} className={styles.item} />
-                <Radio value={item.value}>{item.title}</Radio>
-              </div>
-            </Col>
-          ))}
-        </Row>
-      </Radio.Group>
+
+      <Row gutter={24}>
+        {viewMap.map((item) => (
+          <Col
+            span={8}
+            key={item.value}
+            onClick={() => {
+              setValue(item.value);
+            }}
+          >
+            <div className={classNames(styles.item, value === item.value ? styles.active : {})}>
+              <img src={item.img} className={styles.item} />
+            </div>
+          </Col>
+        ))}
+      </Row>
 
       <div style={{ textAlign: 'center', marginTop: 48 }}>
         <Button

+ 23 - 20
src/pages/home/ops/index.tsx

@@ -1,6 +1,5 @@
 import { Col, message, Row, Tooltip } from 'antd';
 import Guide from '../components/Guide';
-import { PermissionButton } from '@/components';
 import Statistics from '../components/Statistics';
 import Pie from '@/pages/home/components/Pie';
 import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
@@ -16,9 +15,9 @@ const Ops = () => {
   const [subscribeTopic] = useSendWebsocketMessage();
   const history = useHistory();
 
-  const productPermission = PermissionButton.usePermission('device/Product').permission;
-  const devicePermission = PermissionButton.usePermission('device/Instance').permission;
-  const rulePermission = PermissionButton.usePermission('rule-engine/Instance').permission;
+  const accessPermission = getMenuPathByCode(MENUS_CODE['link/AccessConfig']);
+  const logPermission = getMenuPathByCode(MENUS_CODE['Log']);
+  const linkPermission = getMenuPathByCode(MENUS_CODE['link/DashBoard']);
 
   const [cpuValue, setCpuValue] = useState<number>(0);
   const [jvmValue, setJvmValue] = useState<number>(0);
@@ -57,30 +56,34 @@ const Ops = () => {
       jvmRealTime?.unsubscribe();
     };
   }, []);
-  const guideOpsList: any[] = [
+
+  const guideOpsList = [
     {
-      key: 'product',
+      key: 'access',
       name: '设备接入配置',
-      english: 'CREATE PRODUCT',
-      auth: !!productPermission.add,
-      url: 'device/Product',
-      param: '?save=true',
+      english: 'DEVICE ACCESS CONFIGURATION',
+      auth: !!accessPermission,
+      url: accessPermission,
     },
     {
-      key: 'device',
+      key: 'logger',
       name: '日志排查',
-      english: 'CREATE DEVICE',
-      auth: !!devicePermission.add,
-      url: 'device/Instance',
-      param: '?save=true',
+      english: 'LOG SCREEN',
+      auth: !!logPermission,
+      url: logPermission,
+      param: {
+        key: 'system',
+      },
     },
     {
-      key: 'rule-engine',
+      key: 'realtime',
       name: '实时监控',
-      english: 'RULE ENGINE',
-      auth: !!rulePermission.add,
-      url: 'rule-engine/Instance',
-      param: '?save=true',
+      english: 'REAL-TIME MONITORING',
+      auth: !!linkPermission,
+      url: linkPermission,
+      param: {
+        save: true,
+      },
     },
   ];
   return (

+ 6 - 2
src/pages/link/AccessConfig/Detail/Provider/index.tsx

@@ -1,6 +1,6 @@
 import { useEffect, useState } from 'react';
 import { TitleComponent } from '@/components';
-import { Button, Card, Col, Row } from 'antd';
+import { Button, Card, Col, Row, Tooltip } from 'antd';
 import styles from './index.less';
 
 interface Props {
@@ -84,7 +84,11 @@ const Provider = (props: Props) => {
                       </div>
                       <div className={styles.context}>
                         <div style={{ fontWeight: 600 }}>{item.name}</div>
-                        <div className={styles.desc}>{item?.description || ''}</div>
+                        <div className={styles.desc}>
+                          <Tooltip title={item?.description || ''}>
+                            {item?.description || ''}
+                          </Tooltip>
+                        </div>
                       </div>
                     </div>
                     <div style={{ width: '70px' }}>

+ 8 - 1
src/pages/link/Protocol/FileUpload/index.tsx

@@ -10,6 +10,7 @@ interface Props {
   value: string;
   onChange: (value: string) => void;
   accept?: string;
+  disabled?: boolean;
 }
 
 const FileUpload = connect((props: Props) => {
@@ -43,13 +44,19 @@ const FileUpload = connect((props: Props) => {
           <Input
             style={{ width: 'calc(100% - 100px)' }}
             value={url}
+            disabled={props?.disabled}
             onClick={(e) => {
               e.preventDefault();
               e.stopPropagation();
             }}
             placeholder="请上传文件"
           />
-          <Button shape="round" style={{ width: '100px', textAlign: 'center' }} type="primary">
+          <Button
+            disabled={props?.disabled}
+            shape="round"
+            style={{ width: '100px', textAlign: 'center' }}
+            type="primary"
+          >
             上传jar包
           </Button>
         </Input.Group>

+ 22 - 0
src/pages/link/Protocol/save/index.tsx

@@ -20,9 +20,30 @@ interface Props {
 const Save = (props: Props) => {
   const [data, setData] = useState<ProtocolItem | undefined>(props.data);
   const { permission } = PermissionButton.usePermission('link/Protocol');
+  const [count, setCount] = useState<number>(0);
 
   useEffect(() => {
     setData(props.data);
+    if (props.data?.id) {
+      service
+        .productCount({
+          terms: [
+            {
+              terms: [
+                {
+                  column: 'message_protocol',
+                  value: props.data.id,
+                },
+              ],
+            },
+          ],
+        })
+        .then((resp) => {
+          if (resp.status === 200) {
+            setCount(resp.result);
+          }
+        });
+    }
   }, [props.data]);
 
   const form = createForm({
@@ -179,6 +200,7 @@ const Save = (props: Props) => {
                 'x-decorator-props': {
                   gridSpan: 2,
                 },
+                'x-disabled': !!count,
                 'x-validator': [
                   {
                     required: true,

+ 3 - 0
src/pages/link/Protocol/service.ts

@@ -16,6 +16,9 @@ class Service extends BaseService<ProtocolItem> {
     request(`${this.uri}/${type}`, { method: 'POST', data });
 
   public validator = (id: string) => request(`${SystemConst.API_BASE}/protocol/${id}/exists`);
+
+  public productCount = (data: Record<string, unknown>) =>
+    request(`${SystemConst.API_BASE}/device-product/_count`, { method: 'POST', data });
 }
 
 export default Service;

+ 17 - 7
src/pages/media/Cascade/Save/index.tsx

@@ -385,30 +385,40 @@ const Save = () => {
               <h1>2.配置说明</h1>
               <div>以下配置说明以将本平台数据级联到LiveGBS平台为例。</div>
               <h2>1、上级SIP ID</h2>
-              <div>请填写第三方平台中配置的SIP ID。</div>
+              <div>
+                请填写第三方平台中配置的<b>SIP ID</b>。
+              </div>
               <div className={styles.image}>
                 <Image width="100%" src={img2} />
               </div>
               <h2>2、上级SIP 域</h2>
-              <div>请填写第三方平台中配置的SIP ID域。</div>
+              <div>
+                请填写第三方平台中配置的<b>SIP ID域</b>。
+              </div>
               <div className={styles.image}>
                 <Image width="100%" src={img1} />
               </div>
               <h2>3、上级SIP 地址</h2>
-              <div>请填写第三方平台中配置的SIP ID地址。</div>
+              <div>
+                请填写第三方平台中配置的<b>SIP ID地址</b>。
+              </div>
               <div className={styles.image}>
                 <Image width="100%" src={img3} />
               </div>
               <h2>4、本地SIP ID</h2>
               <div>
-                请填写本地的SIP ID地址。
-                地址由中心编码(8位)、行业编码(2位)、类型编码(3位)和序号(7位)四个码段共20位十
+                请填写本地的<b>SIP ID地址</b>
+                地址由中心编码(8位)、行业编码(2位)、类型编码(3位)和序号(7位)四个码段共20位十
                 进制数字字符构成。详细规则请参见《GB/T28181-2016》中附录D部分。
               </div>
               <h2>5、SIP本地地址</h2>
-              <div>请选择指定的网卡和端口,如有疑问请联系系统运维人员。</div>
+              <div>
+                请选择<b>指定的网卡和端口</b>,如有疑问请联系系统运维人员。
+              </div>
               <h2>6、用户</h2>
-              <div>部分平台有基于用于和接入密码的特殊认证。通常情况下,请填写本地SIP ID值。</div>
+              <div>
+                部分平台有基于用户和接入密码的特殊认证。通常情况下,请填写<b>本地SIP ID</b>值。
+              </div>
               <h2>7、接入密码</h2>
               <div>需与上级平台设置的接入密码一致,用于身份认证。</div>
               <h2>8、厂商/型号/版本号</h2>

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

@@ -25,6 +25,17 @@ const Log = observer(() => {
     {
       dataIndex: 'state',
       title: '状态',
+      valueType: 'select',
+      valueEnum: {
+        success: {
+          text: '成功',
+          status: 'success',
+        },
+        error: {
+          text: '失败',
+          status: 'error',
+        },
+      },
       renderText: (text: { value: string; text: string }, record) => {
         return (
           <>

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

@@ -25,6 +25,17 @@ const Log = observer(() => {
     {
       dataIndex: 'state',
       title: '状态',
+      valueType: 'select',
+      valueEnum: {
+        success: {
+          text: '成功',
+          status: 'success',
+        },
+        error: {
+          text: '失败',
+          status: 'error',
+        },
+      },
       renderText: (text: { value: string; text: string }, record) => {
         return (
           <>

+ 1 - 4
src/pages/system/Permission/Save/index.tsx

@@ -219,10 +219,7 @@ const Save = (props: Props) => {
           add: {
             type: 'void',
             'x-component': 'ArrayTable.Addition',
-            title: intl.formatMessage({
-              id: 'pages.system.permission.add',
-              defaultMessage: '添加条目',
-            }),
+            title: '添加',
           },
         },
       },