xieyonghong 4 år sedan
förälder
incheckning
4075b06aa5

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

@@ -1,4 +1,4 @@
-import type { ReactNode, CSSProperties } from 'react';
+import type { CSSProperties, ReactNode } from 'react';
 import './index.less';
 
 interface TitleComponentProps {

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

@@ -161,6 +161,7 @@ const Status = observer((props: Props) => {
       } else {
         service.queryProductState(InstanceModel.detail?.productId || '').then((resp) => {
           if (resp.status === 200) {
+            DiagnoseStatusModel.product = resp.result;
             if (resp.result.accessId) {
               service.queryGatewayState(resp.result.accessId).then((response: any) => {
                 if (response.status === 200) {
@@ -211,7 +212,7 @@ const Status = observer((props: Props) => {
                                         title="确认启用"
                                         onConfirm={async () => {
                                           const res = await service.startNetwork(
-                                            resp.result?.channelId,
+                                            DiagnoseStatusModel.product?.channelId,
                                           );
                                           if (res.status === 200) {
                                             message.success('操作成功!');

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

@@ -27,6 +27,7 @@ export const DiagnoseStatusModel = model<{
   };
   list: ListProps[];
   model: boolean;
+  product: any;
 }>({
   status: {
     config: {
@@ -87,4 +88,5 @@ export const DiagnoseStatusModel = model<{
     },
   ],
   model: true,
+  product: {},
 });

+ 19 - 8
src/pages/device/Instance/Detail/MetadataMap/EditableTable/index.tsx

@@ -1,7 +1,6 @@
 import React, { useContext, useEffect, useState } from 'react';
 import { Badge, Col, Form, Input, message, Pagination, Row, Select, Table } from 'antd';
 import { service } from '@/pages/device/Instance';
-import _ from 'lodash';
 import './index.less';
 
 const defaultImage = require('/public/images/metadata-map.png');
@@ -48,7 +47,11 @@ const EditableCell = ({
   const save = async () => {
     try {
       const values = await form.validateFields();
-      handleSave({ ...record, originalId: values?.originalId });
+      handleSave({
+        ...record,
+        originalId: values?.originalId,
+        customMapping: values?.originalId !== '',
+      });
     } catch (errInfo) {
       console.log('Save failed:', errInfo);
     }
@@ -75,7 +78,7 @@ const EditableCell = ({
           }
         >
           <Select.Option value={''}>使用物模型属性</Select.Option>
-          {record.originalId !== record.metadataId && (
+          {record.customMapping && (
             <Select.Option value={record.originalId}>
               {temp?.name}({temp?.id})
             </Select.Option>
@@ -153,13 +156,21 @@ const EditableTable = (props: Props) => {
       resp = await service.queryProductMetadata(props.data.id);
     }
     if (resp.status === 200) {
-      const data = resp.result;
       const obj: any = {};
-      data.map((i: any) => {
-        obj[i?.metadataId] = i;
+      const data = (resp?.result || []).map((i: any) => {
+        const t = {
+          ...i,
+          originalId: i.customMapping ? i.originalId : '',
+        };
+        obj[i?.metadataId] = t;
+        return t;
       });
       if (lists.length > 0) {
-        setPmList(lists.filter((i) => !_.map(data, 'originalId').includes(i.id)));
+        const arr = lists.filter((i) => {
+          const t = data.find((item: any) => item?.originalId === i?.id);
+          return !t || (t && !t.customMapping);
+        });
+        setPmList(arr);
       } else {
         setPmList([]);
       }
@@ -205,7 +216,7 @@ const EditableTable = (props: Props) => {
     const newData = [...dataSource.data];
     const index = newData.findIndex((item) => row.id === item.id);
     const item = newData[index];
-    if (item?.originalId !== row?.originalId) {
+    if (item?.originalId !== row?.originalId || row.customMapping !== item.customMapping) {
       const resp = await service[
         props.type === 'device' ? 'saveDeviceMetadata' : 'saveProductMetadata'
       ](props.data?.id, [

+ 40 - 13
src/pages/notice/Config/SyncUser/index.tsx

@@ -14,6 +14,7 @@ const SyncUser = observer(() => {
   const id = (location as any).query?.id;
   const [visible, setVisible] = useState<boolean>(false);
   const [current, setCurrent] = useState<any>({});
+  const [list, setList] = useState<any[]>([]);
 
   const idMap = {
     dingTalk: '钉钉',
@@ -24,19 +25,14 @@ const SyncUser = observer(() => {
 
   const columns: ProColumns<any>[] = [
     {
-      dataIndex: 'id',
+      dataIndex: 'thirdPartyUserName',
       title: `${idMap[id]}用户名`,
-      render: (text: any, record: any) => (
-        <span>
-          {text}({record?.name})
-        </span>
-      ),
     },
     {
       dataIndex: 'userId',
       title: `用户`,
       render: (text: any, record: any) => (
-        <span>{record?.userId ? `${record?.username}(${record?.userName})` : '--'}</span>
+        <span>{record?.userId ? `${record?.userName}(${record?.username})` : '--'}</span>
       ),
     },
     {
@@ -44,8 +40,8 @@ const SyncUser = observer(() => {
       title: '绑定状态',
       render: (text: any, record: any) => (
         <Badge
-          status={record?.userId ? 'success' : 'error'}
-          text={record?.userId ? '已绑定' : '未绑定'}
+          status={record?.status === 1 ? 'success' : 'error'}
+          text={record?.status === 1 ? '已绑定' : '未绑定'}
         />
       ),
     },
@@ -65,13 +61,15 @@ const SyncUser = observer(() => {
           </Button>
         </Tooltip>,
         <Tooltip title={'解绑用户'} key="unbind">
-          {record?.userId && (
+          {record?.status === 1 && (
             <Button type="link">
               <Popconfirm
                 title={'确认解绑'}
                 onConfirm={async () => {
                   if (record?.bindingId) {
-                    const resp = await service.syncUser.unBindUser(record.bindingId);
+                    const resp = await service.syncUser.unBindUser(record.bindingId, {
+                      bindingId: record.bindingId,
+                    });
                     if (resp.status === 200) {
                       message.success('操作成功!');
                       actionRef.current?.reload();
@@ -139,6 +137,7 @@ const SyncUser = observer(() => {
                 title: 'name',
                 key: 'id',
               }}
+              selectedKeys={[dept || '']}
               onSelect={(key) => {
                 setDept(key[0] as string);
               }}
@@ -149,7 +148,7 @@ const SyncUser = observer(() => {
         <Col span={20}>
           {dept && (
             <ProTable
-              rowKey="id"
+              rowKey="thirdPartyUserId"
               actionRef={actionRef}
               search={false}
               columns={columns}
@@ -167,6 +166,7 @@ const SyncUser = observer(() => {
                     params.dept || '',
                   )
                   .then((resp: any) => {
+                    setList(resp);
                     return {
                       code: '',
                       result: {
@@ -179,7 +179,34 @@ const SyncUser = observer(() => {
                     };
                   })
               }
-              headerTitle={<Button>保存</Button>}
+              headerTitle={
+                <Popconfirm
+                  title="确认保存"
+                  onConfirm={async () => {
+                    const arr = list
+                      .filter((item) => item.status === 0)
+                      .map((i) => {
+                        return {
+                          userId: i.userId,
+                          providerName: i.userName,
+                          thirdPartyUserId: i.thirdPartyUserId,
+                        };
+                      });
+                    const resp = await service.syncUser.bindUser(
+                      id,
+                      state.current?.provider || '',
+                      state.current?.id || '',
+                      [...arr],
+                    );
+                    if (resp.status === 200) {
+                      message.success('操作成功!');
+                      actionRef.current?.reload();
+                    }
+                  }}
+                >
+                  <Button type="primary">保存</Button>
+                </Popconfirm>
+              }
             />
           )}
         </Col>

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

@@ -300,6 +300,7 @@ const Config = observer(() => {
                 <PermissionButton
                   key="syncUser"
                   isPermission={true}
+                  type="link"
                   onClick={() => {
                     state.syncUser = true;
                     state.current = record;

+ 24 - 19
src/pages/notice/Config/service.ts

@@ -71,9 +71,10 @@ class Service extends BaseService<ConfigItem> {
       }),
     getUserBindInfo: () =>
       request(`${SystemConst.API_BASE}/user/third-party/me`, { method: 'GET' }),
-    unBindUser: (bindId: string) =>
-      request(`${SystemConst.API_BASE}/user/third-party/me/${bindId}`, {
-        method: 'DELETE',
+    unBindUser: (bindingId: string, data: any) =>
+      request(`${SystemConst.API_BASE}/user/third-party/${bindingId}/_unbind`, {
+        method: 'POST',
+        data,
       }),
   };
 
@@ -93,26 +94,30 @@ class Service extends BaseService<ConfigItem> {
         map((resp) => resp.map((i) => i.result)),
         mergeMap((res) => {
           const [resp1, resp2, resp3] = res;
-          const list = resp1.map((item: { id: string; name: string }) => {
-            const data =
-              resp2.find(
-                (i: { userId: string; providerName: string; thirdPartyUserId: string }) =>
-                  i.thirdPartyUserId === item.id,
-              ) || {};
-            let _user: Partial<UserItem> = {};
-            if (data) {
-              _user = resp3.find((i: UserItem) => i.id === data.userId);
+          // 1.自动匹配
+          // 2.已匹配
+          // status: 1: 已匹配 0: 自动匹配,但是没有保存 -1: 未匹配
+          const arr = resp1.map((item: { id: string; name: string }) => {
+            let user = resp3.find((i: UserItem) => i?.name === item?.name);
+            const thirdPartyUser = resp2.find(
+              (i: { userId: string; providerName: string; thirdPartyUserId: string }) =>
+                i?.thirdPartyUserId === item?.id,
+            );
+            if (thirdPartyUser) {
+              user = resp3.find((i: UserItem) => i?.id === thirdPartyUser?.userId);
             }
+            const status = thirdPartyUser ? 1 : user ? 0 : -1;
             return {
-              ..._user,
-              ...data,
-              ...item,
-              bindingId: data?.id,
-              userId: _user?.id,
-              userName: _user?.name,
+              thirdPartyUserId: item?.id,
+              thirdPartyUserName: item?.name,
+              bindingId: thirdPartyUser?.id,
+              userId: user?.id,
+              userName: user?.name,
+              username: user?.username,
+              status,
             };
           });
-          return list;
+          return arr;
         }),
         toArray(),
       ),

+ 33 - 4
src/pages/rule-engine/Alarm/Config/index.tsx

@@ -53,8 +53,36 @@ const Config = () => {
     [],
   );
 
-  const inputForm = useMemo(() => createForm(), []);
-  const outputForm = useMemo(() => createForm(), []);
+  const inputForm = useMemo(
+    () =>
+      createForm({
+        validateFirst: true,
+        effects() {
+          onFormInit(async () => {
+            const resp = await service.getDataExchange('consume');
+            if (resp.status === 200) {
+              console.log(resp, 'resp');
+            }
+          });
+        },
+      }),
+    [],
+  );
+  const outputForm = useMemo(
+    () =>
+      createForm({
+        validateFirst: true,
+        effects() {
+          onFormInit(async () => {
+            const resp = await service.getDataExchange('producer');
+            if (resp.status === 200) {
+              console.log(resp, 'producer');
+            }
+          });
+        },
+      }),
+    [],
+  );
 
   const levelSchema: ISchema = {
     type: 'object',
@@ -174,16 +202,17 @@ const Config = () => {
     const outputConfig: IOConfigItem = await outputForm.submit();
     const inputResp = await service.saveOutputData({
       config: {
-        type: 'kafka',
         config: inputConfig,
       },
+      sourceType: 'kafka',
       exchangeType: 'producer',
     });
     const outputResp = await service.saveOutputData({
       config: {
-        type: 'kafka',
+        sourceType: 'kafka',
         config: outputConfig,
       },
+      sourceType: 'kafka',
       exchangeType: 'consume',
     });
 

+ 3 - 0
src/pages/rule-engine/Alarm/Config/service.ts

@@ -21,6 +21,9 @@ class Service extends BaseService<IOConfigItem> {
       method: 'PATCH',
       data,
     });
+
+  getDataExchange = (type: 'consume' | 'producer') =>
+    request(`/${SystemConst.API_BASE}/alarm/config/${type}/data-exchange`, { method: 'GET' });
 }
 
 export default Service;

+ 13 - 4
src/pages/rule-engine/Alarm/Configuration/Save/index.tsx

@@ -60,8 +60,11 @@ const Save = (props: Props) => {
 
   const getScene = () => {
     return service.getScene().then((resp) => {
-      Store.set('scene-data', resp);
-      return resp;
+      Store.set('scene-data', resp.result);
+      return resp.result.map((item: { id: string; name: string }) => ({
+        label: item.name,
+        value: item.id,
+      }));
     });
   };
   const form = useMemo(
@@ -89,8 +92,14 @@ const Save = (props: Props) => {
   const handleSave = async () => {
     const data: any = await form.submit();
     const list = Store.get('scene-data');
-    const scene = list.find((item: any) => item.value === data.sceneId);
-    const resp: any = await service.update({ ...data, sceneName: scene.label, state: 'disable' });
+    const scene = list.find((item: any) => item.id === data.sceneId);
+
+    const resp: any = await service.update({
+      ...data,
+      sceneTriggerType: scene.triggerType,
+      sceneName: scene.name,
+    });
+
     if (resp.status === 200) {
       message.success('操作成功');
       props.close();

+ 0 - 5
src/pages/rule-engine/Alarm/Configuration/service.ts

@@ -16,11 +16,6 @@ class Service extends BaseService<ConfigItem> {
   public getScene = () =>
     request(`/${SystemConst.API_BASE}/scene/_query/no-paging?paging=false`, {
       method: 'GET',
-    }).then((resp) => {
-      return resp.result.map((item: { id: string; name: string }) => ({
-        label: item.name,
-        value: item.id,
-      }));
     });
 
   public _enable = (id: string) =>

+ 1 - 1
src/pages/rule-engine/Scene/Save/action/action.tsx

@@ -1,5 +1,5 @@
-import { Button, Select, Form } from 'antd';
 import type { FormInstance } from 'antd';
+import { Button, Form, Select } from 'antd';
 import { useCallback, useEffect, useState } from 'react';
 import { useRequest } from 'umi';
 import {

+ 1 - 1
src/pages/rule-engine/Scene/Save/action/device/functionCall.tsx

@@ -3,8 +3,8 @@ import { EditableProTable } from '@jetlinks/pro-table';
 import { Input, InputNumber, Select } from 'antd';
 import React, { useEffect, useRef, useState } from 'react';
 import type { ProFormInstance } from '@ant-design/pro-form';
-import { DatePickerFormat } from '@/pages/rule-engine/Scene/Save/components';
 import ProForm from '@ant-design/pro-form';
+import { DatePickerFormat } from '@/pages/rule-engine/Scene/Save/components';
 
 type FunctionTableDataType = {
   id: string;

+ 1 - 0
src/pages/rule-engine/Scene/Save/components/TriggerWay/index.less

@@ -19,6 +19,7 @@
         font-weight: bold;
         font-size: 16px;
       }
+
       span {
         color: rgba(#000, 0.24);
         font-size: 12px;

+ 123 - 20
src/pages/rule-engine/Scene/TriggerTerm/index.tsx

@@ -14,8 +14,8 @@ import {
   TreeSelect,
 } from '@formily/antd';
 import { ISchema } from '@formily/json-schema';
-import { createForm, onFieldValueChange, onFormValuesChange } from '@formily/core';
-import { forwardRef, useImperativeHandle, useMemo } from 'react';
+import { createForm, Field, onFieldReact, onFormValuesChange } from '@formily/core';
+import { forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
 import FTermArrayCards from '@/components/FTermArrayCards';
 import FTermTypeSelect from '@/components/FTermTypeSelect';
 import styles from './index.less';
@@ -34,27 +34,138 @@ interface Props {
 }
 
 const TriggerTerm = (props: Props, ref: any) => {
+  const requestParams = {
+    trigger: {
+      type: 'device',
+      device: {
+        productId: '0412-zj',
+        selector: 'device',
+        selectorValue: [
+          {
+            id: '0412-zj',
+            name: '0412-zj',
+          },
+        ],
+        operation: {
+          operator: 'reportProperty',
+          timer: {
+            trigger: 'week',
+            cron: '',
+            when: [1, 3, 5],
+            mod: 'period',
+            period: {
+              from: '09:30',
+              to: '14:30',
+              every: 1,
+              unit: 'hours',
+            },
+            once: {
+              time: '',
+            },
+          },
+          eventId: '',
+          readProperties: ['temparature', 'temperature-k', 'test-zhibioa'],
+          writeProperties: {},
+          functionId: '',
+          functionParameters: [
+            {
+              name: '',
+              value: {},
+            },
+          ],
+        },
+        defaultVariable: [],
+      },
+      timer: {},
+      defaultVariable: [],
+    },
+  };
+
+  const parseTermRef = useRef<any>();
+  const getParseTerm = () =>
+    service.getParseTerm(requestParams || props.params).then((data) => {
+      Store.set('trigger-parse-term', data);
+      parseTermRef.current = data;
+      return data.map((item: any) => ({
+        column: item.column,
+        name: item.name,
+        children: item.children,
+      }));
+    });
+
   const form = useMemo(
     () =>
       createForm({
         validateFirst: true,
-        initialValues: props.value,
+        initialValues:
+          {
+            trigger: [
+              {
+                terms: [
+                  {
+                    column: 'properties.temprature.current',
+                    termType: 'gt',
+                    source: 'manual',
+                    value: 123,
+                  },
+                  {
+                    column: 'properties.test-zhibioa.recent',
+                    termType: 'gt',
+                    source: 'metrics',
+                    value: '123',
+                  },
+                  {
+                    column: 'properties.test-zhibioa.current',
+                    termType: 'lte',
+                    source: 'manual',
+                    value: 223,
+                  },
+                ],
+              },
+              {
+                terms: [
+                  {
+                    column: 'properties.temprature.current',
+                    termType: 'btw',
+                    source: 'manual',
+                    value: 23,
+                  },
+                  {
+                    column: 'properties.temperature-k.current',
+                    termType: 'gt',
+                    source: 'manual',
+                    value: 123,
+                  },
+                  {
+                    column: '_now',
+                    termType: 'eq',
+                    source: 'manual',
+                    value: '2022-04-29 00:00:07',
+                  },
+                ],
+              },
+            ],
+          } || props.value,
+
         effects() {
           onFormValuesChange(async (f) => {
             if (props.onChange) {
               props.onChange(await f.submit());
             }
           });
-          onFieldValueChange('trigger.*.terms.*.column', (field, form1) => {
+          onFieldReact('trigger.*.terms.*.column', async (field, form1) => {
             const operator = field.query('.termType');
+            const value = (field as Field).value;
+
             // 找到选中的
-            const _data = Store.get('trigger-parse-term');
+            const _data = await service.getParseTerm(requestParams || props.params);
+            if (!_data) return;
             // 树形搜索
-            const treeValue = treeFilter(_data, field.value, 'column');
+            const treeValue = treeFilter(_data, value, 'column');
             // 找到
             const target =
               treeValue && treeValue[0].children
-                ? treeValue[0]?.children.find((item) => item.column === field.value)
+                ? treeValue[0]?.children.find((item) => item.column === value)
                 : treeValue[0];
 
             form1.setFieldState(operator, (state) => {
@@ -73,11 +184,12 @@ const TriggerTerm = (props: Props, ref: any) => {
                   : [{ label: '手动输入', value: 'manual' }];
             });
           });
-          onFieldValueChange('trigger.*.terms.*.source', (field, form1) => {
+          onFieldReact('trigger.*.terms.*.source', (field, form1) => {
             const params = field.query('.column').value();
             const value = field.query('.value');
             // 找到选中的
             const _data = Store.get('trigger-parse-term');
+            if (!_data) return;
             // 树形搜索
             const treeValue = treeFilter(_data, params, 'column');
             // 找到
@@ -86,8 +198,9 @@ const TriggerTerm = (props: Props, ref: any) => {
                 ? treeValue[0]?.children.find((item) => item.column === params)
                 : treeValue[0];
 
+            const source = (field as Field).value;
             if (target) {
-              if (field.value === 'manual') {
+              if (source === 'manual') {
                 // 手动输入
                 const valueType = target.dataType;
 
@@ -109,7 +222,7 @@ const TriggerTerm = (props: Props, ref: any) => {
                     };
                   }
                 });
-              } else if (field.value === 'metrics') {
+              } else if (source === 'metrics') {
                 // 指标
                 form1.setFieldState(value, (state) => {
                   state.componentType = Select;
@@ -144,16 +257,6 @@ const TriggerTerm = (props: Props, ref: any) => {
     },
   });
 
-  const getParseTerm = () =>
-    service.getParseTerm(props.params).then((data) => {
-      Store.set('trigger-parse-term', data);
-      return data.map((item: any) => ({
-        column: item.column,
-        name: item.name,
-        children: item.children,
-      }));
-    });
-
   const schema: ISchema = {
     type: 'object',
     properties: {

+ 49 - 5
src/pages/rule-engine/Scene/service.ts

@@ -1,6 +1,8 @@
 import { request } from '@@/plugin-request/request';
 import BaseService from '@/utils/BaseService';
 import type { SceneItem } from '@/pages/rule-engine/Scene/typings';
+import { defer, from, lastValueFrom, shareReplay } from 'rxjs';
+import { filter, map } from 'rxjs/operators';
 
 class Service extends BaseService<SceneItem> {
   startScene = (id: string) => request(`${this.uri}/${id}/_enable`, { method: 'PUT' });
@@ -9,11 +11,53 @@ class Service extends BaseService<SceneItem> {
 
   updateScene = (data: any) => request(`${this.uri}/${data.id}`, { method: 'PUT', data });
 
-  getParseTerm = (data: Record<string, any>) =>
-    request(`${this.uri}/parse-term-column`, {
-      method: 'POST',
-      data,
-    }).then((resp) => resp.result);
+  // getParseTerm = (data: Record<string, any>) =>
+  //   request(`${this.uri}/parse-term-column`, {
+  //     method: 'POST',
+  //     data,
+  //   }).then((resp) => resp.result);
+  // getParseTerm = (data: Record<string, any>) => {
+  //   const oldParams = Store.get('request-params-parse-term');
+  //   const list = Store.get('parse-term');
+  //   const f = list && _.isEqual(oldParams, data);
+  //   console.log(oldParams, list, f, data, 'request');
+  //   return f ? new Promise(resolve => {
+  //     resolve(list);
+  //   }) : request(`${this.uri}/parse-term-column`, {
+  //     method: 'POST',
+  //     data,
+  //   }).then((resp) => {
+  //     Store.set('parse-term', resp.result);
+  //     console.log(Store.get('parse-term'), 'then-resp')
+  //     return resp.result
+  //   }).finally(() => {
+  //     Store.set('request-params-parse-term', data);
+  //   });
+  // };
+
+  private cacheTerm$: Promise<any> | undefined;
+
+  getParseTerm = (data: Record<string, any>) => {
+    if (!this.cacheTerm$) {
+      this.cacheTerm$ = lastValueFrom(
+        defer(() =>
+          from(
+            request(`${this.uri}/parse-term-column`, {
+              method: 'POST',
+              data,
+            }),
+          ),
+        ).pipe(
+          filter((item) => item.status === 200),
+          map((item) => {
+            return item.result;
+          }),
+          shareReplay(1, 100),
+        ),
+      );
+    }
+    return this.cacheTerm$;
+  };
 }
 
 export default Service;