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

feat(merge): merge xyh

Next xyh
Lind 3 лет назад
Родитель
Сommit
032b0a7a40

+ 1 - 0
src/components/DashBoard/timePicker.tsx

@@ -72,6 +72,7 @@ export default forwardRef((props: ExtraTimePickerProps, ref) => {
         // @ts-ignore
         <DatePicker.RangePicker
           {...extraProps}
+          allowClear={false}
           showTime={props.showTime}
           value={
             value && [

+ 2 - 2
src/components/FormItems/MetadataJsonInput/index.tsx

@@ -1,5 +1,5 @@
 import { Input, Modal } from 'antd';
-import { EnvironmentOutlined } from '@ant-design/icons';
+import { FormOutlined } from '@ant-design/icons';
 import { useEffect, useState } from 'react';
 import MonacoEditor from 'react-monaco-editor';
 import { isObject } from 'lodash';
@@ -75,7 +75,7 @@ export default (props: MetaDataJsonInputProps) => {
     <>
       <Input
         addonAfter={
-          <EnvironmentOutlined
+          <FormOutlined
             onClick={() => {
               setMonacoValue(value);
               setVisible(true);

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

@@ -53,7 +53,7 @@ const PermissionButton = (props: PermissionButtonProps) => {
     if (isPermission) {
       if (popConfirm) {
         popConfirm.children = tooltip ? isTooltip : defaultButton;
-        return <Popconfirm disabled={!isPermission} {...popConfirm} />;
+        return <Popconfirm disabled={!isPermission || props.disabled} {...popConfirm} />;
       } else if (tooltip && !popConfirm) {
         return isTooltip;
       } else {

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

@@ -136,7 +136,7 @@ export default (props: ProductCardProps) => {
             </div>
             <div>
               <label>接入方式</label>
-              <div className={'ellipsis'}>{props.transportProtocol || '未接入'}</div>
+              <div className={'ellipsis'}>{props.protocolName || '未接入'}</div>
             </div>
           </div>
         </div>

+ 9 - 0
src/components/ProTableCard/index.less

@@ -217,6 +217,15 @@
       cursor: pointer;
       transition: all 0.3s;
 
+      > div {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 100%;
+        height: 100%;
+        padding: 0 !important;
+      }
+
       &.show {
         background-color: rgba(#000, 0.5);
         visibility: visible;

+ 1 - 1
src/locales/zh-CN/pages.ts

@@ -57,7 +57,7 @@ export default {
   'pages.form.tip.max64': '最多输入64个字符',
   'pages.form.tip.id': '请输入英文或者数字或者-或者_',
   'pages.form.tooltip.id': '若不填写,系统将自动生成唯一ID',
-  'pages.form.tip.existsID': 'ID重复',
+  'pages.form.tip.existsID': '该ID已存在',
   'pages.form.tip.input.props': '请输入{name}',
   'pages.form.tip.select.props': '请选择{name}',
 

+ 75 - 12
src/pages/device/Instance/Detail/Functions/form.tsx

@@ -1,6 +1,6 @@
 import type { FunctionMetadata } from '@/pages/device/Product/typings';
 import React, { useEffect, useRef, useState } from 'react';
-import { Button, DatePicker, Input, InputNumber, Select } from 'antd';
+import { Button, DatePicker, Input, InputNumber, Select, Tooltip } from 'antd';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import type { ProColumns } from '@jetlinks/pro-table';
 import { EditableProTable } from '@jetlinks/pro-table';
@@ -10,6 +10,7 @@ import { InstanceModel, service } from '@/pages/device/Instance';
 import moment from 'moment';
 import './index.less';
 import { GeoPoint, MetadataJsonInput } from '@/components';
+import { QuestionCircleOutlined } from '@ant-design/icons';
 
 type FunctionProps = {
   data: FunctionMetadata;
@@ -82,22 +83,88 @@ export default (props: FunctionProps) => {
   const columns: ProColumns<FunctionTableDataType>[] = [
     {
       dataIndex: 'name',
-      title: '名称',
+      title: '参数名称',
       width: 120,
       editable: false,
       ellipsis: true,
     },
     {
       dataIndex: 'type',
-      title: '类型',
+      title: '输入类型',
       width: 120,
       editable: false,
+      render: (row) => {
+        switch (row) {
+          case 'array':
+            return (
+              <span>
+                {row}
+                <Tooltip
+                  title={
+                    <div>
+                      <p>输入示例:</p>
+                      <p>配置类型为int时,输入[1,2,3,4]</p>
+                    </div>
+                  }
+                >
+                  <QuestionCircleOutlined style={{ marginLeft: 8 }} />
+                </Tooltip>
+              </span>
+            );
+          case 'object':
+            return (
+              <span>
+                {row}
+                <Tooltip
+                  title={
+                    <div>
+                      <p>请按照json格式输入</p>
+                    </div>
+                  }
+                >
+                  <QuestionCircleOutlined style={{ marginLeft: 8 }} />
+                </Tooltip>
+              </span>
+            );
+          case 'file':
+            return (
+              <span>
+                {row}
+                <Tooltip
+                  title={
+                    <div>
+                      <p>输入示例:</p>
+                      <p>模型配置为base64时,输入YXNkZmRzYWY=</p>
+                    </div>
+                  }
+                >
+                  <QuestionCircleOutlined style={{ marginLeft: 8 }} />
+                </Tooltip>
+              </span>
+            );
+          case 'geoPoint':
+            return (
+              <span>
+                {row}
+                <Tooltip
+                  title={
+                    <div>
+                      <p>输入示例:</p>
+                      <p>[102,12231, 39.251423]</p>
+                    </div>
+                  }
+                >
+                  <QuestionCircleOutlined style={{ marginLeft: 8 }} />
+                </Tooltip>
+              </span>
+            );
+          default:
+            return row;
+        }
+      },
     },
     {
-      title: intl.formatMessage({
-        id: 'pages.data.option',
-        defaultMessage: '操作',
-      }),
+      title: '值',
       dataIndex: 'value',
       align: 'center',
       renderFormItem: (_, row: any) => {
@@ -111,7 +178,6 @@ export default (props: FunctionProps) => {
     const properties = data.valueType ? data.valueType.properties : data.inputs;
 
     for (const datum of properties) {
-      console.log(datum);
       const type = datum.valueType ? datum.valueType.type : '-';
 
       array.push({
@@ -191,10 +257,7 @@ export default (props: FunctionProps) => {
               });
             }}
           >
-            {intl.formatMessage({
-              id: 'pages.data.option.cancel',
-              defaultMessage: '取消',
-            })}
+            清空
           </Button>
         </div>
       </div>

+ 17 - 10
src/pages/device/Instance/Detail/Functions/index.tsx

@@ -5,6 +5,7 @@ import FnForm from './form';
 import AModel from './AdvancedMode';
 import { useDomFullHeight } from '@/hooks';
 import Empty from '@/pages/device/components/Empty';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
 
 const Functions = () => {
   const functionList = JSON.parse(InstanceModel.detail.metadata || '{}')
@@ -17,16 +18,22 @@ const Functions = () => {
       {functionList ? (
         <Tabs>
           <Tabs.TabPane tab={'精简模式'} key={1}>
-            <Tabs tabPosition="left">
-              {functionList &&
-                functionList.map((fn) => {
-                  return (
-                    <Tabs.TabPane tab={fn.name} key={fn.id}>
-                      <FnForm data={fn} />
-                    </Tabs.TabPane>
-                  );
-                })}
-            </Tabs>
+            <>
+              <div style={{ paddingBottom: 12 }}>
+                <ExclamationCircleOutlined style={{ marginRight: 12 }} />
+                精简模式下参数只支持已输入框的方式录入
+              </div>
+              <Tabs tabPosition="left">
+                {functionList &&
+                  functionList.map((fn) => {
+                    return (
+                      <Tabs.TabPane tab={fn.name} key={fn.id}>
+                        <FnForm data={fn} />
+                      </Tabs.TabPane>
+                    );
+                  })}
+              </Tabs>
+            </>
           </Tabs.TabPane>
           <Tabs.TabPane tab={'高级模式'} key={2}>
             <Tabs tabPosition="left">

+ 8 - 2
src/pages/device/Instance/Detail/Info/index.tsx

@@ -6,7 +6,7 @@ import { useIntl } from '@@/plugin-locale/localeExports';
 import Config from '@/pages/device/Instance/Detail/Config';
 import Reation from '@/pages/device/Instance/Detail/Reation';
 import Save from '../../Save';
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
 import type { DeviceInstance } from '../../typings';
 import { EditOutlined } from '@ant-design/icons';
 import Tags from '@/pages/device/Instance/Detail/Tags';
@@ -19,6 +19,10 @@ const Info = observer(() => {
   const { permission } = PermissionButton.usePermission('device/Instance');
   const { minHeight } = useDomFullHeight(`.device-detail-body`);
 
+  useEffect(() => {
+    console.log(InstanceModel.detail);
+  }, [InstanceModel.detail]);
+
   return (
     <>
       <Card className={'device-detail-body'} style={{ minHeight }}>
@@ -95,7 +99,8 @@ const Info = observer(() => {
               defaultMessage: '注册时间',
             })}
           >
-            {moment(InstanceModel.detail?.registerTime).format('YYYY-MM-DD HH:mm:ss')}
+            {InstanceModel.detail?.registerTime &&
+              moment(InstanceModel.detail?.registerTime).format('YYYY-MM-DD HH:mm:ss')}
           </Descriptions.Item>
           <Descriptions.Item
             label={intl.formatMessage({
@@ -131,6 +136,7 @@ const Info = observer(() => {
             InstanceModel.detail = {
               ...InstanceModel.detail,
               ...data,
+              describe: data.description,
             };
           }
         }}

+ 5 - 1
src/pages/device/Instance/Save/index.tsx

@@ -37,6 +37,9 @@ const Save = (props: Props) => {
       .getProductList(
         encodeQuery({
           paging: false,
+          sorts: {
+            createTime: 'desc',
+          },
           terms: {
             state: 1,
           },
@@ -222,6 +225,7 @@ const Save = (props: Props) => {
               <Select
                 showSearch
                 options={productList}
+                disabled={props.model === 'edit'}
                 onSelect={(_: any, node: any) => {
                   form.setFieldsValue({
                     productName: node.label,
@@ -238,7 +242,7 @@ const Save = (props: Props) => {
         </Row>
         <Row>
           <Col span={24}>
-            <Form.Item label={intlFormat('pages.table.description', '说明')} name={'describe'}>
+            <Form.Item label={intlFormat('pages.table.description', '说明')} name={'description'}>
               <Input.TextArea
                 placeholder={
                   intlFormat('pages.form.tip.input', '请输入') +

+ 13 - 9
src/pages/device/Instance/index.tsx

@@ -250,7 +250,9 @@ const Instance = () => {
       dataIndex: 'registryTime',
       width: '200px',
       valueType: 'dateTime',
-      render: (text: any) => (text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
+      render: (_: any, row) => {
+        return row.registryTime ? moment(row.registryTime).format('YYYY-MM-DD HH:mm:ss') : '/';
+      },
       sorter: true,
     },
     {
@@ -662,14 +664,16 @@ const Instance = () => {
                   disabled: record.state.value !== 'notActive',
                   onConfirm: async () => {
                     if (record.state.value === 'notActive') {
-                      await service.remove(record.id);
-                      onlyMessage(
-                        intl.formatMessage({
-                          id: 'pages.data.option.success',
-                          defaultMessage: '操作成功!',
-                        }),
-                      );
-                      actionRef.current?.reload();
+                      const resp: any = await service.remove(record.id);
+                      if (resp.code === 200) {
+                        onlyMessage(
+                          intl.formatMessage({
+                            id: 'pages.data.option.success',
+                            defaultMessage: '操作成功!',
+                          }),
+                        );
+                        actionRef.current?.reload();
+                      }
                     } else {
                       onlyMessage(
                         intl.formatMessage({ id: 'pages.device.instance.deleteTip' }),

+ 12 - 1
src/pages/device/Product/index.tsx

@@ -258,8 +258,19 @@ const Product = observer(() => {
     },
     {
       title: '接入方式',
-      dataIndex: 'transportProtocol',
+      dataIndex: 'accessId',
       width: 150,
+      valueType: 'select',
+      render: (_, row) => {
+        return row.protocolName;
+      },
+      request: () =>
+        service.queryGatewayList().then((resp: any) =>
+          resp.result.map((item: any) => ({
+            label: item.name,
+            value: item.id,
+          })),
+        ),
     },
     {
       title: '设备类型',

+ 10 - 1
src/pages/device/Product/service.ts

@@ -111,7 +111,7 @@ class Service extends BaseService<ProductItem> {
   public category = () =>
     request(`/${SystemConst.API_BASE}/device/category/_tree?paging=false`, {
       method: 'GET',
-      params: encodeQuery({ sorts: { id: 'desc' } }),
+      params: encodeQuery({ sorts: { sortIndex: 'asc' } }),
     });
 
   public getOrg = () =>
@@ -150,6 +150,15 @@ class Service extends BaseService<ProductItem> {
     );
 
   public existsID = (id: string) => request(`${this.uri}/${id}/exists`, { method: 'GET' });
+
+  //接入网关
+  public queryGatewayList = () =>
+    request(`/${SystemConst.API_BASE}/gateway/device/_query/no-paging`, {
+      method: 'POST',
+      data: {
+        paging: false,
+      },
+    });
 }
 
 export default Service;

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

@@ -1057,6 +1057,9 @@ const Edit = observer((props: Props) => {
         }
         MetadataModel.edit = false;
         MetadataModel.item = {};
+        if (InstanceModel.detail) {
+          InstanceModel.detail.independentMetadata = true;
+        }
       }
     } else {
       onlyMessage('操作失败!', 'error');

+ 2 - 4
src/pages/home/components/Guide.tsx

@@ -1,5 +1,4 @@
 import './index.less';
-import { getMenuPathByCode } from '@/utils/menu';
 import { message } from 'antd';
 import useHistory from '@/hooks/route/useHistory';
 import Title from './Title';
@@ -26,12 +25,11 @@ interface GuideItemProps {
 }
 
 const GuideItem = (props: GuideItemProps) => {
-  const path = getMenuPathByCode(props.url);
   const history = useHistory();
 
   const jumpPage = () => {
-    if (path && props.auth) {
-      history.push(`${path}`, props.param);
+    if (props.url && props.auth) {
+      history.push(`${props.url}`, props.param);
     } else {
       message.warning('暂无权限,请联系管理员');
     }

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

@@ -26,6 +26,7 @@
   background: linear-gradient(135.62deg, #f6f7fd 22.27%, rgba(255, 255, 255, 0.86) 91.82%);
   border-radius: 2px;
   box-shadow: 0 4px 18px #efefef;
+  cursor: pointer;
 
   .item-english {
     color: #4f4f4f;

+ 8 - 8
src/pages/link/Type/index.tsx

@@ -330,6 +330,7 @@ const Network = () => {
               </PermissionButton>,
               <PermissionButton
                 type="link"
+                key="other-delete"
                 style={{ padding: 0 }}
                 isPermission={networkPermission.delete}
                 disabled={record.state.value === 'enabled'}
@@ -342,19 +343,18 @@ const Network = () => {
                         })
                       : '请先禁用该组件,再删除。',
                 }}
-              >
-                <Popconfirm
-                  title="确认删除?"
-                  onConfirm={async () => {
+                popConfirm={{
+                  title: '确认删除?',
+                  onConfirm: async () => {
                     const response: any = await service.remove(record.id);
                     if (response.status === 200) {
                       onlyMessage('删除成功');
                       actionRef.current?.reload();
                     }
-                  }}
-                >
-                  <DeleteOutlined />
-                </Popconfirm>
+                  },
+                }}
+              >
+                <DeleteOutlined />
               </PermissionButton>,
             ]}
           />

+ 20 - 12
src/pages/media/Device/index.tsx

@@ -218,7 +218,7 @@ const Device = () => {
         </PermissionButton>,
         <PermissionButton
           tooltip={{
-            title: '查看设备',
+            title: '查看通道',
           }}
           style={{ padding: 0 }}
           type={'link'}
@@ -248,15 +248,23 @@ const Device = () => {
           </Button>
         </Tooltip>,
         <PermissionButton
-          tooltip={{
-            title:
-              record.provider === ProviderValue.FIXED
-                ? '接入方式为固定地址时不支持更新通道'
-                : '更新通道',
-          }}
+          tooltip={
+            record.state.value === 'offline' || record.provider === providerType['fixed-media']
+              ? {
+                  title:
+                    record.provider === providerType['fixed-media']
+                      ? '固定地址无法更新通道'
+                      : record.state.value === 'offline'
+                      ? '设备已离线'
+                      : '',
+                }
+              : undefined
+          }
           key={'updateChannel'}
-          isPermission={permission.action}
-          disabled={record.state.value === 'offline' || record.provider === ProviderValue.FIXED}
+          isPermission={permission.update}
+          disabled={
+            record.state.value === 'offline' || record.provider === providerType['fixed-media']
+          }
           style={{ padding: 0 }}
           type={'link'}
           onClick={() => {
@@ -273,13 +281,13 @@ const Device = () => {
           popConfirm={{
             title: intl.formatMessage({
               id:
-                record.state.value === 'offline'
-                  ? 'pages.device.productDetail.deleteTip'
+                record.state.value !== 'offline'
+                  ? 'pages.device.instance.deleteTip'
                   : 'page.table.isDelete',
               defaultMessage: '是否删除?',
             }),
             onConfirm: async () => {
-              if (record.state.value !== 'offline') {
+              if (record.state.value === 'offline') {
                 await deleteItem(record.id);
               } else {
                 onlyMessage('在线设备不能进行删除操作', 'error');

+ 6 - 5
src/pages/rule-engine/Scene/Save/action/device/index.tsx

@@ -25,10 +25,7 @@ enum SourceEnum {
   'relation' = 'relation',
 }
 
-const DefaultSourceOptions = [
-  { label: '固定设备', value: SourceEnum.fixed },
-  { label: '按标签', value: SourceEnum.tag },
-];
+const DefaultSourceOptions = [{ label: '固定设备', value: SourceEnum.fixed }];
 
 export enum MessageTypeEnum {
   'WRITE_PROPERTY' = 'WRITE_PROPERTY',
@@ -82,7 +79,11 @@ export default (props: DeviceProps) => {
   useEffect(() => {
     props.form?.resetFields([['actions', name, 'device', 'selector']]);
     if (props.triggerType === 'device') {
-      setSourceList([...DefaultSourceOptions, { label: '按关系', value: SourceEnum.relation }]);
+      setSourceList([
+        ...DefaultSourceOptions,
+        { label: '按关系', value: SourceEnum.relation },
+        { label: '按标签', value: SourceEnum.tag },
+      ]);
     } else {
       setSourceList(DefaultSourceOptions);
     }

+ 4 - 2
src/pages/rule-engine/Scene/Save/index.tsx

@@ -150,7 +150,8 @@ export default () => {
         <>
           <InputNumber
             value={shakeLimit.time}
-            min={0}
+            min={1}
+            max={100}
             onChange={(e: number) => {
               const newShake = {
                 ...shakeLimit,
@@ -162,7 +163,8 @@ export default () => {
           <span> 秒内发生 </span>
           <InputNumber
             value={shakeLimit.threshold}
-            min={0}
+            min={1}
+            max={100}
             onChange={(e: number) => {
               const newShake = {
                 ...shakeLimit,

+ 3 - 0
src/pages/system/Platforms/Api/leftTree.tsx

@@ -64,6 +64,9 @@ export default (props: LeftTreeType) => {
   );
 
   const handleTreeData = (data: any) => {
+    if (data && Object.keys(data).length) {
+      return [];
+    }
     const newArr = data.tags.map((item: any) => ({ id: item.name, name: item.name, isLeaf: true }));
 
     Object.keys(data.paths).forEach((a: any) => {

+ 1 - 2
src/pages/system/Platforms/Api/swagger-ui/debugging.tsx

@@ -196,7 +196,6 @@ export default observer(() => {
             {ApiModel.swagger.method ? ApiModel.swagger.method.toUpperCase() : ''}
           </Button>
           <Input
-            allowClear
             style={{
               width: `calc(100% - ${ApiModel.swagger.method !== 'delete' ? '140px' : '150px'})`,
             }}
@@ -237,7 +236,7 @@ export default observer(() => {
       </div>
       <div className={'swagger-content-item'}>
         <TitleComponent data={'响应内容'} />
-        <div>
+        <div style={{ border: '1px solid #fefefe', borderRadius: 2 }}>
           {
             // @ts-ignore
             <ReactJson

+ 4 - 4
src/pages/system/Platforms/save.tsx

@@ -384,10 +384,10 @@ export default (props: SaveProps) => {
               tooltip: '授权后自动跳转的页面地址',
             },
             'x-validator': [
-              {
-                max: 128,
-                message: '最多可输入128个字符',
-              },
+              // {
+              //   max: 128,
+              //   message: '最多可输入128个字符',
+              // },
               {
                 required: true,
                 message: '请输入redirectUrl',