Explorar el Código

fix: 修改bug

100011797 hace 3 años
padre
commit
4909cda125

+ 73 - 30
src/components/FSelectDevices/index.tsx

@@ -1,28 +1,38 @@
-import { Input, Modal } from 'antd';
+import { Badge, Input, Modal } from 'antd';
 import { EditOutlined } from '@ant-design/icons';
 import type { Key } from 'react';
 import { useRef, useState } from 'react';
-import { connect } from '@formily/react';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
 import type { DeviceInstance } from '@/pages/device/Instance/typings';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import Service from '@/pages/device/Instance/service';
 import SearchComponent from '../SearchComponent';
-import _ from 'lodash';
+import { observer } from '@formily/react';
+import { model } from '@formily/reactive';
 
 interface Props {
-  value: Partial<DeviceInstance>[];
-  onChange: (data: Partial<DeviceInstance>[]) => void;
+  value?: Partial<DeviceInstance>[];
+  onChange?: (data: Partial<DeviceInstance>[]) => void;
   productId?: string;
 }
 
-export const service = new Service('device/instance');
-const FSelectDevices = connect((props: Props) => {
+const deviceStatus = new Map();
+deviceStatus.set('online', <Badge status="success" text={'在线'} />);
+deviceStatus.set('offline', <Badge status="error" text={'离线'} />);
+deviceStatus.set('notActive', <Badge status="processing" text={'禁用'} />);
+
+const service = new Service('device/instance');
+const State = model<{
+  visible: boolean;
+}>({
+  visible: false,
+});
+
+const FSelectDevices = observer((props: Props) => {
   // todo 考虑与单选设备合并
-  const [visible, setVisible] = useState<boolean>(false);
   const intl = useIntl();
-  const actionRef = useRef<ActionType>();
+  const actionRef1 = useRef<ActionType>();
   const [searchParam, setSearchParam] = useState({});
   const columns: ProColumns<DeviceInstance>[] = [
     {
@@ -53,50 +63,87 @@ const FSelectDevices = connect((props: Props) => {
       width: '200px',
       valueType: 'dateTime',
     },
+    {
+      title: '状态',
+      dataIndex: 'state',
+      render: (text: any, record: any) =>
+        record?.state?.value ? deviceStatus.get(record?.state?.value) : '',
+      ellipsis: true,
+    },
   ];
 
   const [data, setData] = useState<Partial<DeviceInstance>[]>(props?.value || []);
   const rowSelection = {
-    onChange: (selectedRowKeys: Key[], selectedRows: DeviceInstance[]) => {
-      const list = [...data];
-      selectedRows.map((item) => {
-        if (!_.map(data, 'id').includes(item.id)) {
-          list.push(item);
-        }
-      });
-      setData(list);
+    onSelect: (selectedRow: any, selected: any) => {
+      let newSelectKeys = [...data];
+      if (selected) {
+        newSelectKeys.push({ ...selectedRow });
+      } else {
+        newSelectKeys = newSelectKeys.filter((item) => item.id !== selectedRow.id);
+      }
+      setData(newSelectKeys);
+    },
+    onSelectAll: (selected: boolean, _: any, changeRows: any) => {
+      let newSelectKeys = [...data];
+      if (selected) {
+        changeRows.forEach((item: any) => {
+          newSelectKeys.push({ ...item });
+        });
+      } else {
+        newSelectKeys = newSelectKeys.filter((a) => {
+          return !changeRows.some((b: any) => b.id === a.id);
+        });
+      }
+      setData(newSelectKeys);
     },
     selectedRowKeys: data?.map((item) => item.id) as Key[],
   };
 
+  const reload = () => {
+    actionRef1.current?.reset?.();
+    setSearchParam({});
+  };
+
   return (
     <>
       <Input
         disabled
         value={props.value?.map((item) => item.name).join(',')}
-        addonAfter={<EditOutlined onClick={() => setVisible(true)} />}
+        addonAfter={
+          <EditOutlined
+            onClick={() => {
+              State.visible = true;
+            }}
+          />
+        }
       />
-      {visible && (
+      {State.visible && (
         <Modal
           maskClosable={false}
           visible
           title="选择设备"
           width="80vw"
-          onCancel={() => setVisible(false)}
+          onCancel={() => {
+            State.visible = false;
+            reload();
+          }}
           onOk={() => {
-            setVisible(false);
-            props.onChange(data);
+            State.visible = false;
+            reload();
+            if (props.onChange) {
+              props.onChange(data);
+            }
           }}
         >
           <SearchComponent<DeviceInstance>
             field={columns}
             enableSave={false}
             model="simple"
-            onSearch={async (data1) => {
+            onSearch={(data1) => {
+              actionRef1.current?.reset?.();
               setSearchParam(data1);
-              actionRef.current?.reset?.();
             }}
-            target="choose-device"
+            target="choose-devices"
           />
           <ProTable<DeviceInstance>
             tableAlertRender={false}
@@ -106,14 +153,10 @@ const FSelectDevices = connect((props: Props) => {
             }}
             search={false}
             columnEmptyText={''}
-            toolBarRender={false}
             rowKey="id"
-            pagination={{
-              pageSize: 10,
-            }}
             params={searchParam}
             columns={columns}
-            actionRef={actionRef}
+            actionRef={actionRef1}
             request={async (params) => {
               return service.queryDetailList({
                 context: {

+ 1 - 1
src/pages/device/Firmware/Save/index.tsx

@@ -65,7 +65,7 @@ const Save = (props: Props) => {
           value: 1,
         },
       ],
-      sorts: [{ name: 'name', order: 'desc' }],
+      sorts: [{ name: 'createTime', order: 'desc' }],
     });
 
   const SchemaField = createSchemaField({

+ 16 - 17
src/pages/device/Firmware/Task/Save/index.tsx

@@ -2,13 +2,12 @@ import { Modal } from 'antd';
 import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 import { createSchemaField } from '@formily/react';
 import { Form, FormGrid, FormItem, Input, Select, NumberPicker, Radio } from '@formily/antd';
-import { createForm, onFieldValueChange, onFormInit } from '@formily/core';
+import { createForm, onFieldValueChange } from '@formily/core';
 import type { ISchema } from '@formily/json-schema';
 import { service } from '@/pages/device/Firmware';
-import { useEffect, useMemo, useRef } from 'react';
+import { useEffect, useMemo } from 'react';
 import { onlyMessage } from '@/utils/util';
 import FSelectDevices from '@/components/FSelectDevices';
-import type { DeviceInstance } from '@/pages/device/Instance/typings';
 
 interface Props {
   ids: { id: string; productId: string };
@@ -27,10 +26,10 @@ const Save = (props: Props) => {
         validateFirst: true,
         initialValues: {},
         effects() {
-          onFormInit(async (form1) => {
-            if (!data?.id) return;
-            form1.setInitialValues({ ...data, upload: { url: data?.url } });
-          });
+          // onFormInit(async (form1) => {
+          //   if (!data?.id) return;
+          //   form1.setInitialValues({ ...data, upload: { url: data?.url } });
+          // });
           onFieldValueChange('mode', async (field) => {
             field
               .query('timeoutSeconds')
@@ -55,7 +54,7 @@ const Save = (props: Props) => {
     [],
   );
 
-  const devices = useRef<DeviceInstance[]>([]);
+  // const devices = useRef<DeviceInstance[]>([]);
 
   const SchemaField = createSchemaField({
     components: {
@@ -70,19 +69,19 @@ const Save = (props: Props) => {
   });
 
   useEffect(() => {
-    if (visible) {
-      service.queryDevice().then((resp) => {
-        if (resp.status === 200) {
-          devices.current = resp.result;
-        }
-      });
-    }
+    // if (visible) {
+    //   service.queryDevice().then((resp) => {
+    //     if (resp.status === 200) {
+    //       devices.current = resp.result;
+    //     }
+    //   });
+    // }
   }, [visible]);
 
   const save = async () => {
     const values: any = await form.submit();
     if (values?.releaseType !== 'all') {
-      values.deviceId = devices.current.map((item) => item.id);
+      // values.deviceId = devices.current.map((item) => item.id);
     } else {
       values.deviceId = undefined;
     }
@@ -211,7 +210,7 @@ const Save = (props: Props) => {
             },
           },
           releaseType: {
-            type: 'number',
+            type: 'string',
             title: '升级设备',
             default: 'all',
             'x-visible': false,

+ 229 - 0
src/pages/device/Firmware/Task/Save/index1.tsx

@@ -0,0 +1,229 @@
+import { Col, Form, Input, InputNumber, message, Modal, Radio, Row, Select } from 'antd';
+import type { FirmwareItem } from '@/pages/device/Firmware/typings';
+import FSelectDevices from '@/components/FSelectDevices';
+import { useEffect, useRef, useState } from 'react';
+import type { DeviceInstance } from '@/pages/device/Instance/typings';
+import { service } from '@/pages/device/Firmware';
+import { onlyMessage } from '@/utils/util';
+
+interface Props {
+  ids: { id: string; productId: string };
+  data?: FirmwareItem;
+  close: () => void;
+  save: () => void;
+}
+
+const Save = (props: Props) => {
+  const { data, close, ids } = props;
+  const [mode, setMode] = useState<'push' | 'pull' | undefined>(undefined);
+  const [releaseType, setReleaseType] = useState<'all' | 'part' | undefined>(undefined);
+
+  const [form] = Form.useForm();
+
+  const devices = useRef<DeviceInstance[]>([]);
+
+  useEffect(() => {
+    service.queryDevice().then((resp) => {
+      if (resp.status === 200) {
+        devices.current = resp.result;
+      }
+    });
+  }, []);
+
+  const save = async () => {
+    const values = await form.validateFields();
+    if (values?.releaseType !== 'all') {
+      values.deviceId = devices.current.map((item) => item.id);
+    } else {
+      values.deviceId = undefined;
+    }
+    const resp = await service.saveTask({
+      ...values,
+      firmwareId: ids?.id,
+      productId: ids?.productId,
+    });
+    if (resp.status === 200) {
+      onlyMessage('保存成功!');
+      props.save();
+      form.resetFields();
+      setMode(undefined);
+      setReleaseType(undefined);
+    } else {
+      message.error('保存失败!');
+    }
+  };
+
+  return (
+    <Modal
+      maskClosable={false}
+      width="50vw"
+      title={data?.id ? '编辑任务' : '新增任务'}
+      onCancel={() => {
+        form.resetFields();
+        close();
+        setMode(undefined);
+        setReleaseType(undefined);
+      }}
+      onOk={() => save()}
+      visible
+    >
+      <Form form={form} name="basic" layout="vertical">
+        <Row gutter={24}>
+          <Col span={24}>
+            <Form.Item
+              label="任务名称"
+              name="name"
+              rules={[
+                {
+                  required: true,
+                  message: '请输入任务名称',
+                },
+                {
+                  max: 64,
+                  message: '最多可输入64个字符',
+                },
+              ]}
+            >
+              <Input placeholder="请输入任务名称" />
+            </Form.Item>
+          </Col>
+          <Col span={24}>
+            <Form.Item
+              label="推送方式"
+              name="mode"
+              rules={[
+                {
+                  required: true,
+                  message: '请选择推送方式',
+                },
+              ]}
+            >
+              <Select
+                placeholder="请选择推送方式"
+                onChange={(value) => {
+                  setMode(value);
+                }}
+              >
+                <Select.Option value="push">平台推送</Select.Option>
+                <Select.Option value="pull">设备拉取</Select.Option>
+              </Select>
+            </Form.Item>
+          </Col>
+          {mode === 'push' && (
+            <>
+              <Col span={12}>
+                <Form.Item
+                  label="响应超时时间"
+                  name="responseTimeoutSeconds"
+                  rules={[
+                    {
+                      required: true,
+                      message: '请输入响应超时时间',
+                    },
+                    {
+                      type: 'number',
+                      max: 99999,
+                      min: 1,
+                      message: '请输入1~99999之间的数字',
+                    },
+                  ]}
+                >
+                  <InputNumber style={{ width: '100%' }} placeholder="请输入响应超时时间(秒)" />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item
+                  label="升级超时时间"
+                  name="timeoutSeconds"
+                  rules={[
+                    {
+                      required: true,
+                      message: '请输入升级超时时间',
+                    },
+                    {
+                      type: 'number',
+                      max: 99999,
+                      min: 1,
+                      message: '请输入1~99999之间的数字',
+                    },
+                  ]}
+                >
+                  <InputNumber style={{ width: '100%' }} placeholder="请请输入升级超时时间(秒)" />
+                </Form.Item>
+              </Col>
+            </>
+          )}
+          {mode === 'pull' && (
+            <Col span={24}>
+              <Form.Item
+                label="升级超时时间"
+                name="timeoutSeconds"
+                rules={[
+                  {
+                    required: true,
+                    message: '请输入升级超时时间',
+                  },
+                  {
+                    type: 'number',
+                    max: 99999,
+                    min: 1,
+                    message: '请输入1~99999之间的数字',
+                  },
+                ]}
+              >
+                <InputNumber style={{ width: '100%' }} placeholder="请请输入升级超时时间(秒)" />
+              </Form.Item>
+            </Col>
+          )}
+          {!!mode && (
+            <>
+              <Col span={12}>
+                <Form.Item
+                  label="升级设备"
+                  name="releaseType"
+                  rules={[
+                    {
+                      required: true,
+                      message: '请选择升级设备',
+                    },
+                  ]}
+                >
+                  <Radio.Group
+                    onChange={(e) => {
+                      setReleaseType(e.target.value);
+                    }}
+                  >
+                    <Radio value="all"> 所有设备 </Radio>
+                    <Radio value="part"> 选择设备 </Radio>
+                  </Radio.Group>
+                </Form.Item>
+              </Col>
+              {releaseType === 'part' && (
+                <Col span={12}>
+                  <Form.Item
+                    label="选择设备"
+                    name="deviceId"
+                    rules={[
+                      {
+                        required: true,
+                        message: '请选择设备',
+                      },
+                    ]}
+                  >
+                    <FSelectDevices productId={ids?.productId || ''} />
+                  </Form.Item>
+                </Col>
+              )}
+            </>
+          )}
+          <Col span={24}>
+            <Form.Item label="说明" name="description">
+              <Input.TextArea rows={3} maxLength={200} showCount={true} placeholder="请输入说明" />
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    </Modal>
+  );
+};
+export default Save;

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

@@ -15,7 +15,7 @@ import { useHistory, useLocation } from 'umi';
 import { model } from '@formily/reactive';
 import { observer } from '@formily/react';
 import type { FirmwareItem } from '@/pages/device/Firmware/typings';
-import Save from './Save';
+import Save from './Save/index1';
 import { onlyMessage } from '@/utils/util';
 import { PermissionButton } from '@/components';
 import useDomFullHeight from '@/hooks/document/useDomFullHeight';
@@ -26,6 +26,9 @@ import { service } from '@/pages/device/Firmware';
 
 const UpgradeBtn = (props: { data: any; actions: any }) => {
   const { data, actions } = props;
+  if (data.progress === 100) {
+    return null;
+  }
   return (
     <a>
       <Tooltip title={data.waiting ? '停止' : '继续升级'}>
@@ -106,9 +109,9 @@ const Task = observer(() => {
     {
       title: '完成比例',
       ellipsis: true,
-      // hideInSearch: true,
+      hideInSearch: true,
       dataIndex: 'progress',
-      valueType: 'digit',
+      // valueType: 'digit',
     },
     {
       title: intl.formatMessage({
@@ -223,18 +226,19 @@ const Task = observer(() => {
         columns={columns}
         actionRef={actionRef}
       />
-      <Save
-        data={state.current}
-        ids={{ id: id, productId: productId }}
-        visible={state.visible}
-        save={() => {
-          state.visible = false;
-          actionRef.current?.reload?.();
-        }}
-        close={() => {
-          state.visible = false;
-        }}
-      />
+      {state.visible && (
+        <Save
+          data={state.current}
+          ids={{ id: id, productId: productId }}
+          save={() => {
+            state.visible = false;
+            actionRef.current?.reload?.();
+          }}
+          close={() => {
+            state.visible = false;
+          }}
+        />
+      )}
     </PageContainer>
   );
 });

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

@@ -3,9 +3,6 @@ import { Badge, Button, message, Popconfirm, Space } from 'antd';
 import styles from './index.less';
 import { observer } from '@formily/reactive-react';
 import type { ListProps } from './model';
-import { urlMap } from './model';
-import { gatewayList } from './model';
-import { textColorMap } from './model';
 import {
   DiagnoseStatusModel,
   StatusMap,
@@ -13,6 +10,9 @@ import {
   childInitList,
   cloudInitList,
   mediaInitList,
+  TextColorMap,
+  gatewayList,
+  urlMap,
 } from './model';
 import type { ReactNode } from 'react';
 import { useEffect, useState } from 'react';
@@ -2006,7 +2006,7 @@ const Status = observer((props: Props) => {
                 <div className={styles.info}>{item?.info}</div>
               </div>
             </div>
-            <div className={styles.statusRight} style={{ color: textColorMap.get(item.status) }}>
+            <div className={styles.statusRight} style={{ color: TextColorMap.get(item.status) }}>
               {item?.text}
             </div>
           </div>

+ 5 - 5
src/pages/device/Instance/Detail/Diagnose/Status/model.ts

@@ -9,11 +9,11 @@ StatusMap.set('success', require('/public/images/diagnose/status/success.png'));
 StatusMap.set('warning', require('/public/images/diagnose/status/warning.png'));
 StatusMap.set('loading', require('/public/images/diagnose/status/loading.png'));
 
-export const textColorMap = new Map();
-textColorMap.set('loading', 'black');
-textColorMap.set('error', 'red');
-textColorMap.set('success', 'green');
-textColorMap.set('warning', 'red');
+export const TextColorMap = new Map();
+TextColorMap.set('loading', 'black');
+TextColorMap.set('error', 'red');
+TextColorMap.set('success', 'green');
+TextColorMap.set('warning', 'red');
 
 export type ListProps = {
   key: string;

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

@@ -136,7 +136,9 @@ const AccessConfig = (props: Props) => {
         oldData.push(item);
       }
     });
-    return oldData;
+    return oldData.map((item, index) => {
+      return { ...item, sortsIndex: index };
+    });
   };
 
   return (

+ 5 - 1
src/pages/device/Product/Detail/PropertyImport/index.tsx

@@ -31,7 +31,11 @@ const NormalUpload = (props: any) => {
 
     const target = typeMap.get(props.type);
 
-    const _data = updateMetadata('properties', _metadata.properties, target) as ProductItem;
+    const properties = (_metadata?.properties || []).map((item, index) => {
+      return { ...item, sortsIndex: index };
+    });
+
+    const _data = updateMetadata('properties', properties, target) as ProductItem;
     // const resp = await service.update(_product);
     const resp = await asyncUpdateMedata(props.type, _data);
     if (resp.status === 200) {

+ 6 - 0
src/pages/device/Product/service.ts

@@ -157,6 +157,12 @@ class Service extends BaseService<ProductItem> {
       method: 'POST',
       data: {
         paging: false,
+        sorts: [
+          {
+            name: 'createTime',
+            order: 'desc',
+          },
+        ],
       },
     });
   //获取协议详情

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

@@ -1112,9 +1112,14 @@ const Edit = observer((props: Props) => {
 
     if (!typeMap.get(props.type)) return;
 
+    const list = await DB.getDB().table(`${type}`).toArray();
+
     const updateDB = (t: 'add' | 'update', item: MetadataItem) => {
       switch (t) {
         case 'add':
+          const dt = list.sort((a, b) => b?.sortsIndex - a?.sortsIndex) || [];
+          item.sortsIndex =
+            dt.length > 0 && dt[0]?.sortsIndex !== undefined ? dt[0].sortsIndex + 1 : 0;
           DB.getDB().table(`${type}`).add(item, item.id);
           return;
         case 'update':

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

@@ -121,7 +121,7 @@ const BaseMetadata = observer((props: Props) => {
 
   const initData = useCallback(async () => {
     const result = await DB.getDB().table(`${type}`).toArray();
-    setData(result);
+    setData(result.sort((a, b) => b?.sortsIndex - a?.sortsIndex));
   }, [param.id, type]);
 
   useEffect(() => {
@@ -146,7 +146,7 @@ const BaseMetadata = observer((props: Props) => {
         .where('id')
         .startsWithAnyOfIgnoreCase(name)
         .toArray();
-      setData(result);
+      setData(result.sort((a, b) => b?.sortsIndex - a?.sortsIndex));
     } else {
       await initData();
     }

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

@@ -197,6 +197,18 @@ const Import = (props: Props) => {
     if (fid.includes('propertyNotModifiable')) {
       obj.properties = old?.properties || [];
     }
+    obj.events.map((item, index) => {
+      return { ...item, sortsIndex: index };
+    });
+    obj.properties.map((item, index) => {
+      return { ...item, sortsIndex: index };
+    });
+    obj.functions.map((item, index) => {
+      return { ...item, sortsIndex: index };
+    });
+    obj.tags.map((item, index) => {
+      return { ...item, sortsIndex: index };
+    });
     return obj;
   };
 

+ 25 - 18
src/pages/link/Type/Detail/index.tsx

@@ -124,7 +124,14 @@ const Save = observer(() => {
           onFormInit(async (form1) => {
             if (param?.id && param.id !== ':id') {
               const resp = await service.detail(param.id);
-              form1.setInitialValues({ ...resp?.result });
+              const data = resp?.result || {};
+              if (data?.shareCluster === false) {
+                data.cluster = data.cluster?.map((item: any) => ({
+                  ...item.configuration,
+                  configuration: item,
+                }));
+              }
+              form1.setInitialValues({ ...data });
             }
           });
           onFieldValueChange('type', (field, f) => {
@@ -208,23 +215,23 @@ const Save = observer(() => {
     [],
   );
 
-  useEffect(() => {
-    console.log(Store.get('current-network-data'));
-    // const subscription = Store.subscribe('current-network-data', (data) => {
-    //   if (!data) return;
-    //   // form.readPretty = true;
-    //   const _data = _.cloneDeep(data);
-    //   // 处理一下集群模式数据
-    //   if (!_data.shareCluster) {
-    //     _data.cluster = _data.cluster?.map((item: any) => ({ ...item.configuration }));
-    //   }
-    //   form.setValues({ ..._data });
-    // });
-    // return () => {
-    //   subscription.unsubscribe();
-    //   // Store.set('current-network-data', undefined);
-    // };
-  }, []);
+  // useEffect(() => {
+  //   console.log(Store.get('current-network-data'));
+  //   // const subscription = Store.subscribe('current-network-data', (data) => {
+  //   //   if (!data) return;
+  //   //   // form.readPretty = true;
+  //   //   const _data = _.cloneDeep(data);
+  //   //   // 处理一下集群模式数据
+  //   //   if (!_data.shareCluster) {
+  //   //     _data.cluster = _data.cluster?.map((item: any) => ({ ...item.configuration }));
+  //   //   }
+  //   //   form.setValues({ ..._data });
+  //   // });
+  //   // return () => {
+  //   //   subscription.unsubscribe();
+  //   //   // Store.set('current-network-data', undefined);
+  //   // };
+  // }, []);
 
   const SchemaField = createSchemaField({
     components: {

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

@@ -96,6 +96,7 @@ const Save = (props: Props) => {
     return service
       .getScene(
         encodeQuery({
+          sorts: { createTime: 'desc' },
           terms: {
             triggerType: map[form.getValuesIn('targetType')],
           },

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

@@ -119,6 +119,7 @@ const BindUser = (props: Props) => {
                 ],
               },
             ],
+            sorts: [{ name: 'createTime', order: 'desc' }],
           });
           return {
             result: {