xieyonghong преди 4 години
родител
ревизия
c531b9a803

+ 1 - 0
src/components/FRuleEditor/index.less

@@ -1,4 +1,5 @@
 .box {
+  margin-bottom: 10px;
   border: 1px solid lightgray;
 
   .top {

+ 21 - 6
src/components/SearchComponent/index.tsx

@@ -2,6 +2,7 @@ import type { ISchema } from '@formily/json-schema';
 import { createSchemaField } from '@formily/react';
 import {
   ArrayItems,
+  DatePicker,
   Form,
   FormButtonGroup,
   FormGrid,
@@ -13,7 +14,7 @@ import {
   Select,
   Space,
 } from '@formily/antd';
-import type { Field } from '@formily/core';
+import type { Field, FieldDataSource } from '@formily/core';
 import { createForm, onFieldReact } from '@formily/core';
 import GroupNameControl from '@/components/SearchComponent/GroupNameControl';
 import { DeleteOutlined, DoubleRightOutlined } from '@ant-design/icons';
@@ -82,6 +83,7 @@ const SchemaField = createSchemaField({
     NumberPicker,
     FormGrid,
     ArrayItems,
+    DatePicker,
     PreviewText,
     GroupNameControl,
     Space,
@@ -114,14 +116,19 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
         validateFirst: true,
         initialValues: initParams,
         effects() {
-          onFieldReact('*.*.column', (typeFiled, f) => {
+          onFieldReact('*.*.column', async (typeFiled, f) => {
             const _column = (typeFiled as Field).value;
             const _field = field.find((item) => item.dataIndex === _column);
             if (_field?.valueType === 'select') {
-              const option = Object.values(_field?.valueEnum || {}).map((item) => ({
-                label: item.text,
-                value: item.status,
-              }));
+              let option: { label: any; value: any }[] | FieldDataSource | undefined = [];
+              if (_field?.valueEnum) {
+                option = Object.values(_field?.valueEnum || {}).map((item) => ({
+                  label: item.text,
+                  value: item.status,
+                }));
+              } else if (_field?.request) {
+                option = await _field.request();
+              }
               f.setFieldState(typeFiled.query('.termType'), async (state) => {
                 state.value = 'eq';
               });
@@ -138,6 +145,14 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
               f.setFieldState(typeFiled.query('.termType'), async (state) => {
                 state.value = 'eq';
               });
+            } else if (_field?.valueType === 'dateTime') {
+              f.setFieldState(typeFiled.query('.value'), async (state) => {
+                state.componentType = 'DatePicker';
+                state.componentProps = { showTime: true };
+              });
+              f.setFieldState(typeFiled.query('.termType'), async (state) => {
+                state.value = 'gt';
+              });
             }
           });
         },

+ 29 - 0
src/components/SearchComponent/readme.md

@@ -0,0 +1,29 @@
+### 字段数据由后端提供
+
+```typescript jsx
+{
+  title: '测试字段',
+    dataIndex
+:
+  'test',
+    valueType
+:
+  'select',
+    align
+:
+  'center',
+    request
+:
+  () => request('/jetlinks/dictionary/device-log-type/items')
+    .then(response =>
+      response.result
+        .map((item: { text: string, value: string }) =>
+          ({ label: item.text, value: item.value }))),
+}
+,
+```
+
+### `valueType` 对应类型
+
+- `digit` 数字类型
+- `dateTime` 日期时间

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

@@ -4,15 +4,15 @@ import MetadataModel from '../model';
 import type { Field, IFieldState } from '@formily/core';
 import { createForm } from '@formily/core';
 import {
-  FormLayout,
   ArrayItems,
   Editable,
-  Radio,
-  Select,
   Form,
-  Input,
   FormItem,
+  FormLayout,
+  Input,
   NumberPicker,
+  Radio,
+  Select,
   Space,
 } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
@@ -27,7 +27,7 @@ import { useMemo } from 'react';
 import { productModel } from '@/pages/device/Product';
 import { service } from '@/pages/device/components/Metadata';
 import { Store } from 'jetlinks-store';
-import type { MetadataItem, UnitType } from '@/pages/device/Product/typings';
+import type { DeviceMetadata, MetadataItem } from '@/pages/device/Product/typings';
 
 import JsonParam from '@/components/Metadata/JsonParam';
 import ArrayParam from '@/components/Metadata/ArrayParam';
@@ -36,7 +36,6 @@ import BooleanEnum from '@/components/Metadata/BooleanParam';
 import ConfigParam from '@/components/Metadata/ConfigParam';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { lastValueFrom } from 'rxjs';
-import type { DeviceMetadata } from '@/pages/device/Product/typings';
 import SystemConst from '@/utils/const';
 import DB from '@/db';
 import _ from 'lodash';
@@ -44,7 +43,6 @@ import { useParams } from 'umi';
 import { InstanceModel } from '@/pages/device/Instance';
 import FRuleEditor from '@/components/FRuleEditor';
 import { action } from '@formily/reactive';
-import type { Response } from '@/utils/typings';
 
 interface Props {
   type: 'product' | 'device';
@@ -364,26 +362,146 @@ const Edit = observer((props: Props) => {
             'x-component': 'Select',
             enum: PropertySource,
           },
-          rule: {
-            type: 'string',
-            'x-component': 'FRuleEditor',
+          virtualRule: {
+            type: 'object',
+            title: '规则配置',
             'x-visible': false,
-            'x-component-props': {
-              property: 'ggg',
+            'x-component': 'Editable.Popover',
+            'x-reactions': {
+              dependencies: ['.source'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="rule"}}',
+                },
+              },
             },
-            'x-reactions': [
-              {
-                dependencies: ['.source', '..id'],
-                fulfill: {
-                  state: {
-                    visible: '{{$deps[0]==="rule"}}',
+            properties: {
+              script: {
+                type: 'string',
+                'x-component': 'FRuleEditor',
+                'x-visible': false,
+                'x-reactions': [
+                  {
+                    dependencies: ['.source', '..id'],
+                    fulfill: {
+                      state: {
+                        visible: '{{$deps[0]==="rule"}}',
+                      },
+                      schema: {
+                        'x-component-props.property': '{{$deps[1]}}',
+                      },
+                    },
                   },
-                  schema: {
-                    'x-component-props.property': '{{$deps[1]}}',
+                ],
+              },
+
+              windowType: {
+                type: 'string',
+                title: '窗口',
+                'x-decorator': 'FormItem',
+                'x-component': 'Select',
+                enum: [
+                  { label: '时间窗口', value: 'time' },
+                  { label: '次数窗口', value: 'num' },
+                ],
+                'x-component-props': {
+                  allowClear: true,
+                },
+              },
+              type: {
+                type: 'string',
+                'x-visible': false,
+                'x-reactions': {
+                  dependencies: ['.windowType'],
+                  when: '{{$deps[0]}}',
+                  fulfill: {
+                    state: {
+                      value: 'window',
+                    },
                   },
                 },
               },
-            ],
+              aggType: {
+                type: 'string',
+                title: '聚合函数',
+                'x-decorator': 'FormItem',
+                'x-component': 'Select',
+                'x-reactions': '{{useAsyncDataSource(getStreamingAggType)}}',
+              },
+              window: {
+                type: 'object',
+                properties: {
+                  span: {
+                    title: '窗口长度',
+                    'x-component': 'Input',
+                    'x-decorator': 'FormItem',
+                    'x-reactions': [
+                      {
+                        dependencies: ['..windowType'],
+                        when: '{{$deps[0]==="time"}}',
+                        fulfill: {
+                          state: {
+                            title: '窗口长度(秒)',
+                          },
+                        },
+                      },
+                      {
+                        dependencies: ['..windowType'],
+                        when: '{{$deps[0]==="num"}}',
+                        fulfill: {
+                          state: {
+                            title: '窗口长度(次)',
+                          },
+                        },
+                      },
+                      {
+                        dependencies: ['..windowType'],
+                        when: '{{!$deps[0]}}',
+                        fulfill: {
+                          state: {
+                            title: '窗口长度',
+                          },
+                        },
+                      },
+                    ],
+                  },
+                  every: {
+                    title: '步长',
+                    'x-component': 'Input',
+                    'x-decorator': 'FormItem',
+                    'x-reactions': [
+                      {
+                        dependencies: ['..windowType'],
+                        when: '{{$deps[0]==="time"}}',
+                        fulfill: {
+                          state: {
+                            title: '步长(秒)',
+                          },
+                        },
+                      },
+                      {
+                        dependencies: ['..windowType'],
+                        when: '{{$deps[0]==="num"}}',
+                        fulfill: {
+                          state: {
+                            title: '步长(次)',
+                          },
+                        },
+                      },
+                      {
+                        dependencies: ['..windowType'],
+                        when: '{{!$deps[0]}}',
+                        fulfill: {
+                          state: {
+                            title: '步长',
+                          },
+                        },
+                      },
+                    ],
+                  },
+                },
+              },
+            },
           },
           type: {
             title: '属性类型',
@@ -517,16 +635,27 @@ const Edit = observer((props: Props) => {
     },
   };
 
-  const getUnit = () => service.getUnit();
+  const getUnit = () =>
+    service.getUnit().then((resp) =>
+      resp.result.map((item: any) => ({
+        label: item.description,
+        value: item.id,
+      })),
+    );
+
+  const getStreamingAggType = () =>
+    service.getStreamingAggType().then((resp) =>
+      resp.result.map((item: any) => ({
+        label: `${item.value}(${item.text})`,
+        value: item.value,
+      })),
+    );
+
   const useAsyncDataSource = (services: (arg0: Field) => Promise<any>) => (field: Field) => {
     field.loading = true;
     services(field).then(
-      action.bound!((data: Response<UnitType>) => {
-        // products.current = data.result;
-        field.dataSource = (data.result as UnitType[]).map((item: any) => ({
-          label: item.description,
-          value: item.id,
-        }));
+      action.bound!((data: { label: string; value: string }[]) => {
+        field.dataSource = data;
         field.loading = false;
       }),
     );
@@ -621,8 +750,8 @@ const Edit = observer((props: Props) => {
       >
         <Form form={form} layout="vertical" size="small">
           <SchemaField
-            scope={{ useAsyncDataSource, getUnit }}
-            schema={metadataTypeMapping.properties.schema}
+            scope={{ useAsyncDataSource, getUnit, getStreamingAggType }}
+            schema={metadataTypeMapping[MetadataModel.type].schema}
           />
         </Form>
       </Drawer>

+ 5 - 0
src/pages/device/components/Metadata/service.ts

@@ -41,6 +41,11 @@ class Service extends BaseService<any> {
     request(`/${SystemConst.API_BASE}/protocol/units`, {
       method: 'GET',
     });
+
+  public getStreamingAggType = () =>
+    request(`/${SystemConst.API_BASE}/dictionary/streaming-agg-type/items`, {
+      method: 'GET',
+    });
 }
 
 export default Service;

+ 0 - 7
src/pages/system/User/index.tsx

@@ -15,7 +15,6 @@ import { useIntl } from '@@/plugin-locale/localeExports';
 import { useRef, useState } from 'react';
 import Save from './Save';
 import { observer } from '@formily/react';
-import { request } from 'umi';
 
 export const service = new Service('user');
 
@@ -56,12 +55,6 @@ const User = observer(() => {
       },
     },
     {
-      title: '测试字段',
-      dataIndex: 'test',
-      align: 'center',
-      request: () => request('/jetlinks/dictionary/device-log-type/items'),
-    },
-    {
       title: intl.formatMessage({
         id: 'pages.system.username',
         defaultMessage: '用户名',