Prechádzať zdrojové kódy

Merge branch 'next' into next-xyh

Lind 3 rokov pred
rodič
commit
6bc9a397ab

+ 161 - 0
src/components/FTermArrayCards/index.tsx

@@ -0,0 +1,161 @@
+import React from 'react';
+import { Card, Empty, Select } from 'antd';
+import { CardProps } from 'antd/lib/card';
+import { ArrayField } from '@formily/core';
+import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
+import cls from 'classnames';
+import { ISchema } from '@formily/json-schema';
+import { usePrefixCls } from '@formily/antd/lib/__builtins__';
+import { ArrayBase, ArrayBaseMixins } from '@formily/antd';
+
+type ComposedArrayCards = React.FC<CardProps> & ArrayBaseMixins;
+
+const isAdditionComponent = (schema: ISchema) => {
+  return schema['x-component']?.indexOf('Addition') > -1;
+};
+
+const isIndexComponent = (schema: ISchema) => {
+  return schema['x-component']?.indexOf('Index') > -1;
+};
+
+const isRemoveComponent = (schema: ISchema) => {
+  return schema['x-component']?.indexOf('Remove') > -1;
+};
+
+const isMoveUpComponent = (schema: ISchema) => {
+  return schema['x-component']?.indexOf('MoveUp') > -1;
+};
+
+const isMoveDownComponent = (schema: ISchema) => {
+  return schema['x-component']?.indexOf('MoveDown') > -1;
+};
+
+const isOperationComponent = (schema: ISchema) => {
+  return (
+    isAdditionComponent(schema) ||
+    isRemoveComponent(schema) ||
+    isMoveDownComponent(schema) ||
+    isMoveUpComponent(schema)
+  );
+};
+
+export const FTermArrayCards: ComposedArrayCards = observer((props) => {
+  const field = useField<ArrayField>();
+  const schema = useFieldSchema();
+  const dataSource = Array.isArray(field.value) ? field.value : [];
+  const prefixCls = usePrefixCls('formily-array-cards', props);
+
+  if (!schema) throw new Error('can not found schema object');
+
+  const renderItems = () => {
+    return dataSource?.map((item, index) => {
+      const items = Array.isArray(schema.items)
+        ? schema.items[index] || schema.items[0]
+        : schema.items;
+      const title = (
+        <span>
+          <RecursionField
+            schema={items!}
+            name={index}
+            filterProperties={(schema4) => {
+              if (!isIndexComponent(schema4)) return false;
+              return true;
+            }}
+            onlyRenderProperties
+          />
+          {props.title || field.title}
+        </span>
+      );
+      const extra = (
+        <span>
+          <RecursionField
+            schema={items!}
+            name={index}
+            filterProperties={(schema1) => {
+              if (!isOperationComponent(schema1)) return false;
+              return true;
+            }}
+            onlyRenderProperties
+          />
+          {props.extra}
+        </span>
+      );
+      const content = (
+        <RecursionField
+          schema={items!}
+          name={index}
+          filterProperties={(schema2) => {
+            if (isIndexComponent(schema2)) return false;
+            if (isOperationComponent(schema2)) return false;
+            return true;
+          }}
+        />
+      );
+      console.log(index, 'index');
+      return (
+        ArrayBase.Item && (
+          <ArrayBase.Item key={index} index={index} record={item}>
+            {index > 0 && (
+              <div style={{ margin: 10, display: 'flex', justifyContent: 'center' }}>
+                <Select
+                  value="or"
+                  style={{ width: '200px' }}
+                  options={[
+                    { label: '或者', value: 'or' },
+                    { label: '并且', value: 'and' },
+                  ]}
+                />
+              </div>
+            )}
+            <Card
+              {...props}
+              onChange={() => {}}
+              className={cls(`${prefixCls}-item`, props.className)}
+              title={title}
+              extra={extra}
+            >
+              {content}
+            </Card>
+          </ArrayBase.Item>
+        )
+      );
+    });
+  };
+
+  const renderAddition = () => {
+    return schema.reduceProperties((addition, schema3, key) => {
+      if (isAdditionComponent(schema3)) {
+        return <RecursionField schema={schema3} name={key} />;
+      }
+      return addition;
+    }, null);
+  };
+
+  const renderEmpty = () => {
+    if (dataSource?.length) return;
+    return (
+      <Card
+        {...props}
+        onChange={() => {}}
+        className={cls(`${prefixCls}-item`, props.className)}
+        title={props.title || field.title}
+      >
+        <Empty />
+      </Card>
+    );
+  };
+
+  return (
+    <ArrayBase>
+      {renderEmpty()}
+      {renderItems()}
+      {renderAddition()}
+    </ArrayBase>
+  );
+});
+
+FTermArrayCards.displayName = 'FTermArrayCards';
+
+ArrayBase.mixin!(FTermArrayCards);
+
+export default FTermArrayCards;

+ 8 - 0
src/components/FTermArrayCards/style.less

@@ -0,0 +1,8 @@
+@root-entry-name: 'default';
+@import (reference) '~antd/es/style/themes/index.less';
+
+@array-cards-prefix-cls: ~'@{ant-prefix}-formily-array-cards';
+
+.@{array-cards-prefix-cls}-item {
+  margin-bottom: 10px !important;
+}

+ 4 - 0
src/components/FTermArrayCards/style.ts

@@ -0,0 +1,4 @@
+import 'antd/lib/card/style/index';
+import 'antd/lib/empty/style/index';
+import 'antd/lib/button/style/index';
+import './style.less';

+ 18 - 0
src/components/FTermTypeSelect/index.tsx

@@ -0,0 +1,18 @@
+import { ArrayItems, Select } from '@formily/antd';
+
+const FTermTypeSelect = () => {
+  const index = ArrayItems.useIndex!();
+  return index > 0 ? (
+    <div style={{ width: '100%', marginBottom: 15, display: 'flex', justifyContent: 'center' }}>
+      <Select
+        style={{ width: '200px' }}
+        value="or"
+        options={[
+          { label: '并且', value: 'and' },
+          { label: '或者', value: 'or' },
+        ]}
+      />
+    </div>
+  ) : null;
+};
+export default FTermTypeSelect;

+ 6 - 6
src/pages/device/Instance/Detail/Running/Property/Indicators.tsx

@@ -1,14 +1,14 @@
 import { message, Modal } from 'antd';
 import {
-  FormItem,
-  Input,
-  Select,
-  DatePicker,
   ArrayItems,
-  Form,
   Checkbox,
-  NumberPicker,
+  DatePicker,
+  Form,
   FormGrid,
+  FormItem,
+  Input,
+  NumberPicker,
+  Select,
 } from '@formily/antd';
 import { createForm } from '@formily/core';
 import { createSchemaField } from '@formily/react';

+ 1 - 0
src/pages/device/Instance/Detail/Running/Property/PropertyCard.less

@@ -9,6 +9,7 @@
   justify-content: space-between;
   width: 100%;
   margin-bottom: 10px;
+
   .card-title {
     width: 60%;
     margin-right: 10px;

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

@@ -4,7 +4,7 @@ import {
   SyncOutlined,
   UnorderedListOutlined,
 } from '@ant-design/icons';
-import { message, Space, Spin, Tooltip, Card } from 'antd';
+import { Card, message, Space, Spin, Tooltip } from 'antd';
 import type { PropertyMetadata } from '@/pages/device/Product/typings';
 import { useState } from 'react';
 import { service } from '@/pages/device/Instance';

+ 4 - 4
src/pages/device/components/Metadata/index.tsx

@@ -6,10 +6,10 @@ import Import from './Import';
 import type { ReactNode } from 'react';
 import { useState } from 'react';
 import Cat from './Cat';
-// import Service from '@/pages/device/components/Metadata/service';
+import Service from '@/pages/device/components/Metadata/service';
 import { InfoCircleOutlined } from '@ant-design/icons';
 import styles from './index.less';
-import { InstanceModel, service } from '@/pages/device/Instance';
+import { InstanceModel, service as instanceService } from '@/pages/device/Instance';
 import { PermissionButton } from '@/components';
 import { Store } from 'jetlinks-store';
 import SystemConst from '@/utils/const';
@@ -21,7 +21,7 @@ interface Props {
   independentMetadata?: boolean;
 }
 
-// export const service = new Service();
+export const service = new Service();
 const Metadata = observer((props: Props) => {
   const intl = useIntl();
   const [visible, setVisible] = useState<boolean>(false);
@@ -33,7 +33,7 @@ const Metadata = observer((props: Props) => {
   const params = useParams<{ id: string }>();
 
   const resetMetadata = async () => {
-    const resp = await service.deleteMetadata(params.id);
+    const resp = await instanceService.deleteMetadata(params.id);
     if (resp.status === 200) {
       message.success('操作成功');
       Store.set(SystemConst.REFRESH_DEVICE, true);

+ 8 - 7
src/pages/notice/Config/Detail/index.tsx

@@ -63,15 +63,15 @@ const Detail = observer(() => {
       createForm({
         validateFirst: true,
         effects() {
-          onFieldValueChange('type', async (field, f) => {
+          onFieldValueChange('type', async (field) => {
             const type = field.value;
             if (!type) return;
-            f.setFieldState('provider', (state1) => {
-              state1.value = undefined;
-              // state.dataSource = providerRef.current
-              //   .find((item) => type === item.id)
-              //   ?.providerInfos.map((i) => ({ label: i.name, value: i.id }));
-            });
+            // f.setFieldState('provider', (state1) => {
+            // state1.value = undefined;
+            // state.dataSource = providerRef.current
+            //   .find((item) => type === item.id)
+            //   ?.providerInfos.map((i) => ({ label: i.name, value: i.id }));
+            // });
           });
           onFieldValueChange('provider', async (field) => {
             if (id === 'email') {
@@ -145,6 +145,7 @@ const Detail = observer(() => {
         required: true,
         'x-visible': typeList[id]?.length > 0,
         'x-hidden': id === 'email',
+        'x-value': typeList[id][0]?.value,
         enum: typeList[id] || [],
       },
       configuration: {

+ 4 - 2
src/pages/notice/Template/Detail/index.tsx

@@ -347,6 +347,7 @@ const Detail = observer(() => {
     }
   };
 
+  console.log(typeList[id][0]);
   const schema: ISchema = {
     type: 'object',
     properties: {
@@ -387,6 +388,7 @@ const Detail = observer(() => {
         required: true,
         'x-visible': typeList[id]?.length > 0,
         'x-hidden': id === 'email',
+        'x-value': typeList[id][0]?.value,
         enum: typeList[id] || [],
       },
       configId: {
@@ -653,11 +655,11 @@ const Detail = observer(() => {
                         'x-component': 'Select',
                         'x-decorator': 'FormItem',
                         'x-decorator-props': {
-                          tooltip: '请输入收信部门ID',
+                          tooltip: '收信部门ID',
                           gridSpan: 1,
                         },
                         'x-component-props': {
-                          placeholder: '请输入AgentID',
+                          placeholder: '请选择收信部门',
                         },
                         'x-reactions': {
                           dependencies: ['configId'],

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

@@ -56,7 +56,7 @@ export const typeList = {
   ],
   email: [
     {
-      value: 'email',
+      value: 'embedded',
       label: '默认',
     },
   ],

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

@@ -6,6 +6,7 @@ import { PermissionButton } from '@/components';
 import ActionItems from './action/action';
 import { PlusOutlined } from '@ant-design/icons';
 import { TriggerWay } from './components';
+import TriggerTerm from '@/pages/rule-engine/Scene/TriggerTerm';
 
 export default () => {
   const location = useLocation();
@@ -69,6 +70,9 @@ export default () => {
           保存
         </PermissionButton>
       </Card>
+      <Card>
+        <TriggerTerm />
+      </Card>
     </PageContainer>
   );
 };

+ 7 - 0
src/pages/rule-engine/Scene/TriggerTerm/index.less

@@ -0,0 +1,7 @@
+.form {
+  :global {
+    .ant-formily-array-cards-item {
+      background-color: #f9f9f9;
+    }
+  }
+}

+ 165 - 0
src/pages/rule-engine/Scene/TriggerTerm/index.tsx

@@ -0,0 +1,165 @@
+import { createSchemaField } from '@formily/react';
+import {
+  ArrayCards,
+  ArrayItems,
+  Form,
+  FormGrid,
+  FormItem,
+  Input,
+  Select,
+  Space,
+} from '@formily/antd';
+import { ISchema } from '@formily/json-schema';
+import { createForm } from '@formily/core';
+import { useMemo } from 'react';
+import FTermArrayCards from '@/components/FTermArrayCards';
+import FTermTypeSelect from '@/components/FTermTypeSelect';
+import styles from './index.less';
+
+const TriggerTerm = () => {
+  const form = useMemo(() => createForm({}), []);
+  const SchemaField = createSchemaField({
+    components: {
+      FormItem,
+      Input,
+      Select,
+      ArrayCards,
+      FTermArrayCards,
+      ArrayItems,
+      Space,
+      FormGrid,
+      FTermTypeSelect,
+    },
+  });
+
+  const schema: ISchema = {
+    type: 'object',
+    properties: {
+      trigger: {
+        type: 'array',
+        'x-component': 'FTermArrayCards',
+        'x-decorator': 'FormItem',
+        'x-component-props': {
+          title: '分组',
+        },
+        items: {
+          type: 'object',
+          properties: {
+            index: {
+              type: 'void',
+              'x-component': 'FTermArrayCards.Index',
+            },
+            terms: {
+              type: 'array',
+              'x-component': 'ArrayItems',
+              'x-decorator': 'FormItem',
+              items: {
+                type: 'object',
+                properties: {
+                  termType: {
+                    type: 'string',
+                    // "x-decorator": 'FormItem',
+                    'x-component': 'FTermTypeSelect',
+                  },
+                  layout: {
+                    type: 'void',
+                    'x-component': 'FormGrid',
+                    'x-decorator-props': {
+                      maxColumns: 24,
+                      minColumns: 24,
+                    },
+                    properties: {
+                      params: {
+                        type: 'string',
+                        // title: '日期',
+                        'x-decorator': 'FormItem',
+                        'x-component': 'Input',
+                        'x-decorator-props': {
+                          gridSpan: 4,
+                        },
+                        'x-component-props': {
+                          placeholder: '请选择参数',
+                        },
+                      },
+                      operator: {
+                        type: 'string',
+                        // title: '输入框',
+                        'x-decorator': 'FormItem',
+                        'x-component': 'Select',
+                        'x-decorator-props': {
+                          gridSpan: 3,
+                        },
+                        'x-component-props': {
+                          placeholder: '操作符',
+                        },
+                      },
+                      type: {
+                        type: 'string',
+                        'x-decorator': 'FormItem',
+                        'x-component': 'Select',
+                        enum: [
+                          { label: '手动输入', value: 'sd' },
+                          { label: '指标', value: 'metrics' },
+                        ],
+                        'x-decorator-props': {
+                          gridSpan: 3,
+                        },
+                      },
+                      value: {
+                        type: 'string',
+                        enum: [
+                          { label: '高高值', value: 1 },
+                          { label: '低低值', value: 2 },
+                          { label: '高值', value: 3 },
+                          { label: '低值', value: 4 },
+                        ],
+                        'x-decorator': 'FormItem',
+                        'x-component': 'Select',
+                        'x-component-props': {},
+                        'x-decorator-props': {
+                          gridSpan: 3,
+                        },
+                      },
+                      remove: {
+                        type: 'void',
+                        'x-decorator': 'FormItem',
+                        'x-component': 'ArrayItems.Remove',
+                        'x-decorator-props': {
+                          gridSpan: 1,
+                        },
+                      },
+                    },
+                  },
+                },
+              },
+              properties: {
+                add: {
+                  type: 'void',
+                  title: '添加条件',
+                  'x-component': 'ArrayItems.Addition',
+                },
+              },
+            },
+            remove: {
+              type: 'void',
+              'x-component': 'FTermArrayCards.Remove',
+            },
+          },
+        },
+        properties: {
+          addition: {
+            type: 'void',
+            title: '添加分组',
+            'x-component': 'FTermArrayCards.Addition',
+          },
+        },
+      },
+    },
+  };
+  return (
+    <Form form={form} layout="vertical" className={styles.form}>
+      <SchemaField schema={schema} />
+    </Form>
+  );
+};
+export default TriggerTerm;

+ 60 - 16
src/pages/system/User/ResetPassword/index.tsx

@@ -51,18 +51,40 @@ const ResetPassword = (props: Props) => {
         ],
         name: 'password',
         'x-validator': [
-          {
-            max: 128,
-            message: '密码最多可输入128位',
-          },
-          {
-            min: 8,
-            message: '密码不能少于6位',
-          },
+          // {
+          //   max: 128,
+          //   message: '密码最多可输入128位',
+          // },
+          // {
+          //   min: 8,
+          //   message: '密码不能少于8位',
+          // },
           {
             required: true,
             message: '请输入密码',
           },
+          {
+            triggerType: 'onBlur',
+            validator: (value: string) => {
+              return new Promise((resolve) => {
+                service
+                  .validateField('password', value)
+                  .then((resp) => {
+                    if (resp.status === 200) {
+                      if (resp.result.passed) {
+                        resolve('');
+                      } else {
+                        resolve(resp.result.reason);
+                      }
+                    }
+                    resolve('');
+                  })
+                  .catch(() => {
+                    return '验证失败!';
+                  });
+              });
+            },
+          },
         ],
       },
       confirmPassword: {
@@ -78,18 +100,40 @@ const ResetPassword = (props: Props) => {
           placeholder: '请再次输入密码',
         },
         'x-validator': [
-          {
-            max: 128,
-            message: '密码最多可输入128位',
-          },
-          {
-            min: 8,
-            message: '密码不能少于8位',
-          },
+          // {
+          //   max: 128,
+          //   message: '密码最多可输入128位',
+          // },
+          // {
+          //   min: 8,
+          //   message: '密码不能少于8位',
+          // },
           {
             required: true,
             message: '请输入确认密码',
           },
+          {
+            triggerType: 'onBlur',
+            validator: (value: string) => {
+              return new Promise((resolve) => {
+                service
+                  .validateField('password', value)
+                  .then((resp) => {
+                    if (resp.status === 200) {
+                      if (resp.result.passed) {
+                        resolve('');
+                      } else {
+                        resolve(resp.result.reason);
+                      }
+                    }
+                    resolve('');
+                  })
+                  .catch(() => {
+                    return '验证失败!';
+                  });
+              });
+            },
+          },
         ],
         'x-reactions': [
           {

+ 41 - 16
src/pages/system/User/Save/index.tsx

@@ -214,14 +214,14 @@ const Save = (props: Props) => {
         ],
         name: 'password',
         'x-validator': [
-          {
-            max: 128,
-            message: '密码最多可输入128位',
-          },
-          {
-            min: 8,
-            message: '密码不能少于6位',
-          },
+          // {
+          //   max: 128,
+          //   message: '密码最多可输入128位',
+          // },
+          // {
+          //   min: 8,
+          //   message: '密码不能少于8位',
+          // },
           {
             required: model === 'add',
             message: '请输入密码',
@@ -242,19 +242,42 @@ const Save = (props: Props) => {
         },
         'x-visible': model === 'add',
         'x-validator': [
-          {
-            max: 128,
-            message: '密码最多可输入128位',
-          },
-          {
-            min: 8,
-            message: '密码不能少于6位',
-          },
+          // {
+          //   max: 128,
+          //   message: '密码最多可输入128位',
+          // },
+          // {
+          //   min: 8,
+          //   message: '密码不能少于6位',
+          // },
           {
             required: model === 'add',
             message: '请输入确认密码',
           },
+          {
+            triggerType: 'onBlur',
+            validator: (value: string) => {
+              return new Promise((resolve) => {
+                service
+                  .validateField('password', value)
+                  .then((resp) => {
+                    if (resp.status === 200) {
+                      if (resp.result.passed) {
+                        resolve('');
+                      } else {
+                        resolve(model === 'edit' ? '' : resp.result.reason);
+                      }
+                    }
+                    resolve('');
+                  })
+                  .catch(() => {
+                    return '验证失败!';
+                  });
+              });
+            },
+          },
         ],
+
         'x-reactions': [
           {
             dependencies: ['.password'],
@@ -368,6 +391,7 @@ const Save = (props: Props) => {
             title: '手机号',
             'x-decorator': 'FormItem',
             'x-component': 'Input',
+            'x-validator': 'phone',
             'x-decorator-props': {
               gridSpan: 1,
             },
@@ -376,6 +400,7 @@ const Save = (props: Props) => {
             title: '邮箱',
             'x-decorator': 'FormItem',
             'x-component': 'Input',
+            'x-validator': 'email',
             'x-decorator-props': {
               gridSpan: 1,
             },