Ver código fonte

feat(search): add initUIParam

lind 3 anos atrás
pai
commit
3a99903fbc

+ 126 - 112
src/components/SearchComponent/index.tsx

@@ -1,5 +1,5 @@
-import type { ISchema } from '@formily/json-schema';
-import { createSchemaField } from '@formily/react';
+import type {ISchema} from '@formily/json-schema';
+import {createSchemaField} from '@formily/react';
 import {
   ArrayItems,
   DatePicker,
@@ -13,40 +13,24 @@ import {
   Select,
   Space,
 } from '@formily/antd';
-import type { Field, FieldDataSource } from '@formily/core';
-import { createForm, onFieldReact, onFormInit } 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,
-  ReloadOutlined,
-  SaveOutlined,
-  SearchOutlined,
-} from '@ant-design/icons';
-import {
-  Button,
-  Card,
-  Dropdown,
-  Empty,
-  Menu,
-  message,
-  Popconfirm,
-  Popover,
-  Typography,
-} from 'antd';
-import { useEffect, useMemo, useState } from 'react';
-import type { ProColumns } from '@jetlinks/pro-table';
-import type { EnumData } from '@/utils/typings';
+import {DeleteOutlined, DoubleRightOutlined, ReloadOutlined, SaveOutlined, SearchOutlined,} from '@ant-design/icons';
+import {Button, Card, Dropdown, Empty, Menu, message, Popover, Typography,} from 'antd';
+import {useEffect, useMemo, useRef, useState} from 'react';
+import type {ProColumns} from '@jetlinks/pro-table';
+import type {EnumData} from '@/utils/typings';
 import styles from './index.less';
 import Service from '@/components/SearchComponent/service';
 import _ from 'lodash';
-import { useIntl } from '@@/plugin-locale/localeExports';
+import {useIntl} from '@@/plugin-locale/localeExports';
 import classnames from 'classnames';
-import { randomString } from '@/utils/util';
+import {randomString} from '@/utils/util';
 
 const ui2Server = (source: SearchTermsUI): SearchTermsServer => [
-  { terms: source.terms1 },
-  { terms: source.terms2, type: source.type },
+  {terms: source.terms1},
+  {terms: source.terms2, type: source.type},
 ];
 
 const server2Ui = (source: SearchTermsServer): SearchTermsUI => ({
@@ -75,23 +59,23 @@ interface Props<T> {
   defaultParam?: SearchTermsServer | Term[];
   // pattern?: 'simple' | 'advance';
   enableSave?: boolean;
+  initParam?: SearchTermsServer
 }
 
 const termType = [
-  { label: '=', value: 'eq' },
-  { label: '!=', value: 'not' },
-  { label: '包含', value: 'like' },
-  { label: '不包含', value: 'nlike' },
-  { label: '>', value: 'gt' },
-  { label: '>=', value: 'gte' },
-  { label: '<', value: 'lt' },
-  { label: '<=', value: 'lte' },
-  { label: '属于', value: 'in' },
-  { label: '不属于', value: 'nin' },
+  {label: '=', value: 'eq'},
+  {label: '!=', value: 'not'},
+  {label: '包含', value: 'like'},
+  {label: '不包含', value: 'nlike'},
+  {label: '>', value: 'gt'},
+  {label: '>=', value: 'gte'},
+  {label: '<', value: 'lt'},
+  {label: '<=', value: 'lte'},
+  {label: '属于', value: 'in'},
+  {label: '不属于', value: 'nin'},
 ];
 
 const service = new Service();
-const initTerm = { termType: 'like' };
 const SchemaField = createSchemaField({
   components: {
     FormItem,
@@ -133,15 +117,7 @@ const sortField = (field: ProColumns[]) => {
 };
 
 const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
-  const { field, target, onSearch, defaultParam, enableSave = true } = props;
-
-  const intl = useIntl();
-  const [expand, setExpand] = useState<boolean>(true);
-  const initForm = server2Ui([{ terms: [initTerm] }]);
-  const [logVisible, setLogVisible] = useState<boolean>(false);
-  const [aliasVisible, setAliasVisible] = useState<boolean>(false);
-  const [initParams, setInitParams] = useState<SearchTermsUI>(initForm);
-  const [history, setHistory] = useState([]);
+  const {field, target, onSearch, defaultParam, enableSave = true, initParam} = props;
 
   /**
    * 过滤不参与搜索的数据
@@ -151,22 +127,35 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
       .filter((item) => item.dataIndex)
       .filter((item) => !item.hideInSearch)
       .filter((item) => !['index', 'option'].includes(item.dataIndex as string));
+
   // 处理后的搜索条件
   const processedField = sortField(filterSearchTerm());
+  const defaultTerms = (index: number) => ({
+    termType: 'like',
+    column: (processedField[index]?.dataIndex as string) || null,
+    type: 'or'
+  } as Partial<Term>);
+  const intl = useIntl();
+  const [expand, setExpand] = useState<boolean>(true);
+  const initForm = server2Ui(initParam || [{terms: [defaultTerms(0)]}]);
+  const [aliasVisible, setAliasVisible] = useState<boolean>(false);
 
+  const [initParams, setInitParams] = useState<SearchTermsUI>(initForm);
+  const [history, setHistory] = useState([]);
+  const [logVisible, setLogVisible] = useState<boolean>(false);
   const form = useMemo(
     () =>
       createForm<SearchTermsUI>({
         validateFirst: true,
         initialValues: initParams,
         effects() {
-          onFormInit((form1) => {
-            if (expand) {
-              form1.setValues({
-                terms1: [{ column: processedField[0]?.dataIndex, termType: 'like' }],
-              });
-            }
-          });
+          // onFormInit((form1) => {
+          //   if (expand && !initParam) {
+          //     form1.setValues({
+          //       terms1: [{column: processedField[0]?.dataIndex, termType: 'like'}],
+          //     });
+          //   }
+          // });
           onFieldReact('*.*.column', async (typeFiled, f) => {
             const _column = (typeFiled as Field).value;
             const _field = field.find((item) => item.dataIndex === _column);
@@ -199,7 +188,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
             } else if (_field?.valueType === 'dateTime') {
               f.setFieldState(typeFiled.query('.value'), async (state) => {
                 state.componentType = 'DatePicker';
-                state.componentProps = { showTime: true };
+                state.componentProps = {showTime: true};
               });
               f.setFieldState(typeFiled.query('.termType'), async (state) => {
                 state.value = 'gt';
@@ -212,7 +201,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
           });
         },
       }),
-    [expand],
+    [target],
   );
 
   const historyForm = createForm();
@@ -231,7 +220,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
     },
     'x-component': 'ArrayItems',
     type: 'array',
-    'x-value': new Array(expand ? 1 : 3).fill({ termType: 'like' }),
+    'x-value': new Array(expand ? 1 : 3).fill({termType: 'like'}),
     items: {
       type: 'object',
       'x-component': 'FormGrid',
@@ -264,7 +253,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
           'x-component-props': {
             placeholder: '请选择',
           },
-          enum: filterSearchTerm().map((i) => ({ label: i.title, value: i.dataIndex } as EnumData)),
+          enum: filterSearchTerm().map((i) => ({label: i.title, value: i.dataIndex} as EnumData)),
         },
         termType: {
           type: 'enum',
@@ -313,8 +302,8 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
             },
             default: 'and',
             enum: [
-              { label: '并且', value: 'and' },
-              { label: '或者', value: 'or' },
+              {label: '并且', value: 'and'},
+              {label: '或者', value: 'or'},
             ],
           },
           terms2: createGroup('第二组'),
@@ -323,30 +312,50 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
     },
   };
 
-  const handleExpand = () => {
-    const value = form.values;
+  const uiParamRef = useRef(initParam);
 
-    if (expand) {
-      value.terms1 = [0, 1, 2].map((i) => ({
-        termType: 'like',
-        column: (processedField[i]?.dataIndex as string) || null,
-        type: 'or',
-      }));
-      value.terms2 = [3, 4, 5].map((i) => ({
-        termType: 'like',
-        column: (processedField[i]?.dataIndex as string) || null,
-        type: 'or',
-      }));
-    } else {
+  const handleForm = (_expand?: boolean) => {
+    const value = form.values;
+    const __expand = _expand || expand;
+    // 第一组条件值
+    const _terms1 = _.cloneDeep(value.terms1?.[0]);
+    const uiParam = uiParamRef.current;
+    // 判断一下条件。。是否展开。
+    if (__expand) {
       value.terms1 = [
-        { termType: 'like', column: (processedField[0].dataIndex as string) || null },
+        uiParam?.[0]?.terms?.[0] || _terms1 || defaultTerms(0),
+        uiParam?.[0]?.terms?.[1] || defaultTerms(1),
+        uiParam?.[0]?.terms?.[2] || defaultTerms(2),
+      ]
+      value.terms2 = [
+        uiParam?.[1]?.terms?.[0] || defaultTerms(3),
+        uiParam?.[1]?.terms?.[1] || defaultTerms(4),
+        uiParam?.[1]?.terms?.[2] || defaultTerms(5),
       ];
+    } else {
+      value.terms1 = _terms1 ? [_terms1] : [defaultTerms(0)];
       value.terms2 = [];
     }
     setInitParams(value);
+  }
+  const handleExpand = () => {
+    handleForm();
     setExpand(!expand);
   };
 
+  useEffect(() => {
+    //  1、一组条件时的表单值
+    //  2、六组条件时的表单值
+    //  3、拥有默认条件时的表单值
+    // 合并初始化的值
+
+    //expand false 6组条件 true 1组条件
+
+    if (initParam && initParam[0].terms && initParam[0].terms.length > 1) {
+      handleExpand();
+    }
+
+  }, []);
   const simpleSchema: ISchema = {
     type: 'object',
     properties: {
@@ -355,8 +364,11 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
   };
   const handleHistory = (item: SearchHistory) => {
     const log = JSON.parse(item.content) as SearchTermsUI;
-    form.setValues(log);
-    setExpand(!((log.terms1 && log.terms1?.length > 1) || (log.terms2 && log.terms2?.length > 1)));
+    setLogVisible(false)
+    uiParamRef.current = ui2Server(log);
+    const _expand = (log.terms1 && log.terms1?.length > 1) || (log.terms2 && log.terms2?.length > 1);
+    _expand && setExpand(false)
+    handleForm(_expand);
   };
 
   const historyDom = (
@@ -365,21 +377,16 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
         history.map((item: SearchHistory) => (
           <Menu.Item onClick={() => handleHistory(item)} key={item.id || randomString(9)}>
             <div className={styles.list}>
-              <Typography.Text ellipsis={{ tooltip: item.name }}>{item.name}</Typography.Text>
-              <Popconfirm
-                onConfirm={async (e) => {
-                  e?.stopPropagation();
-                  const response = await service.history.remove(`${target}-search`, item.key);
-                  if (response.status === 200) {
-                    message.success('操作成功');
-                    const temp = history.filter((h: any) => h.key !== item.key);
-                    setHistory(temp);
-                  }
-                }}
-                title={'确认删除吗?'}
-              >
-                <DeleteOutlined onClick={(e) => e.stopPropagation()} />
-              </Popconfirm>
+              <Typography.Text ellipsis={{tooltip: item.name}}>{item.name}</Typography.Text>
+              <DeleteOutlined onClick={async (e) => {
+                e?.stopPropagation();
+                const response = await service.history.remove(`${target}-search`, item.key);
+                if (response.status === 200) {
+                  message.success('操作成功');
+                  const temp = history.filter((h: any) => h.key !== item.key);
+                  setHistory(temp);
+                }
+              }}/>
             </div>
           </Menu.Item>
         ))
@@ -393,7 +400,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
               width: '148px',
             }}
           >
-            <Empty />
+            <Empty/>
           </div>
         </Menu.Item>
       )}
@@ -402,13 +409,12 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
 
   const formatValue = (value: SearchTermsUI): SearchTermsServer => {
     let _value = ui2Server(value);
-
     // 处理默认查询参数
     if (defaultParam && defaultParam?.length > 0) {
       if ('terms' in defaultParam[0]) {
         _value = _value.concat(defaultParam as SearchTermsServer);
       } else if ('value' in defaultParam[0]) {
-        _value = _value.concat([{ terms: defaultParam }]);
+        _value = _value.concat([{terms: defaultParam}]);
       }
     }
 
@@ -434,7 +440,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
     _terms.terms1 = filterTerms(_terms.terms1);
     _terms.terms2 = filterTerms(_terms.terms2);
 
-    onSearch({ terms: formatValue(_terms) });
+    onSearch({terms: formatValue(_terms)});
   };
 
   useEffect(() => {
@@ -459,25 +465,29 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
   };
 
   const resetForm = async () => {
-    const temp = initForm;
-    const expandData = Array(expand ? 1 : 3).fill(initTerm);
-    temp.terms1 = expandData;
-    temp.terms2 = expandData;
-    await form.reset();
+    const value = form.values;
+    if (!expand) {
+      value.terms1 = [defaultTerms(0), defaultTerms(1), defaultTerms(2)]
+      value.terms2 = [defaultTerms(3), defaultTerms(4), defaultTerms(5)]
+    } else {
+      value.terms1 = [defaultTerms(0)];
+      value.terms2 = [];
+    }
+    setInitParams(value);
     await handleSearch();
   };
 
   const SearchBtn = {
     simple: (
-      <Button icon={<SearchOutlined />} onClick={handleSearch} type="primary">
+      <Button icon={<SearchOutlined/>} onClick={handleSearch} type="primary">
         搜索
       </Button>
     ),
     advance: (
       <Dropdown.Button
-        icon={<SearchOutlined />}
+        icon={<SearchOutlined/>}
         placement={'bottomLeft'}
-        trigger={['click']}
+        destroyPopupOnHide
         onClick={handleSearch}
         visible={logVisible}
         onVisibleChange={async (visible) => {
@@ -497,7 +507,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
   const SaveBtn = (
     <Popover
       content={
-        <Form style={{ width: '217px' }} form={historyForm}>
+        <Form style={{width: '217px'}} form={historyForm}>
           <SchemaField
             schema={{
               type: 'object',
@@ -510,6 +520,10 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
                       max: 64,
                       message: '最多可输入64个字符',
                     },
+                    {
+                      required: true,
+                      message: '请输入名称'
+                    }
                   ],
                 },
               },
@@ -525,7 +539,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
       title="搜索名称"
       trigger="click"
     >
-      <Button icon={<SaveOutlined />} block>
+      <Button icon={<SaveOutlined/>} block>
         {intl.formatMessage({
           id: 'pages.data.option.save',
           defaultMessage: '保存',
@@ -538,19 +552,19 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
     <Card bordered={false} className={styles.container}>
       <Form form={form} className={styles.form} labelCol={4} wrapperCol={18}>
         <div className={expand && styles.simple}>
-          <SchemaField schema={expand ? simpleSchema : schema} />
-          <div className={styles.action} style={{ marginTop: expand ? 0 : -12 }}>
+          <SchemaField schema={expand ? simpleSchema : schema}/>
+          <div className={styles.action} style={{marginTop: expand ? 0 : -12}}>
             <Space>
               {enableSave ? SearchBtn.advance : SearchBtn.simple}
               {enableSave && SaveBtn}
-              <Button icon={<ReloadOutlined />} block onClick={resetForm}>
+              <Button icon={<ReloadOutlined/>} block onClick={resetForm}>
                 重置
               </Button>
             </Space>
             <div className={classnames(styles.more, !expand ? styles.simple : styles.advance)}>
               <Button type="link" onClick={handleExpand}>
                 更多筛选
-                <DoubleRightOutlined style={{ marginLeft: 32 }} rotate={expand ? 90 : -90} />
+                <DoubleRightOutlined style={{marginLeft: 32}} rotate={expand ? 90 : -90}/>
               </Button>
             </div>
           </div>

+ 90 - 14
src/components/SearchComponent/readme.md

@@ -1,6 +1,6 @@
 ### 字段数据由后端提供
 
-```typescript jsx
+```
 {
   title: '测试字段',
     dataIndex
@@ -14,11 +14,17 @@
   '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 }))),
+  () => request(
+    '/jetlinks/dictionary/device-log-type/items'
+  )
+    .then(response => response.result.map((item: {
+                                             text: string,
+                                             value: string
+                                           }
+    ) => ({
+      label: item.text,
+      value: item.value
+    }))),
 }
 ,
 ```
@@ -28,21 +34,91 @@
 - `digit` 数字类型
 - `dateTime` 日期时间
 
-## defaultParams
+## defaultParams 默认查询参数不展示到UI上
 
 支持两种类型的默认参数
 
-```typescript jsx
-const a = { [{ column: 'test', value: 'admin' }] };
+```
+const a = {[{column: 'test', value: 'admin'}]};
 
 const b = {
   [
     {
-      terms: [{ column: 'parentId$isnull', value: '' }, { column: 'parentId$not', value: 'test', type: 'or' }],
-    },
-    {
-      terms: [{ column: 'id$not', value: 'test', type: 'and' }],
+      terms: [{column: 'parentId$isnull', value: ''}, {column: 'parentId$not', value: 'test', type: 'or'}],
     },
-  ]
+{
+  terms: [{column: 'id$not', value: 'test', type: 'and'}],
 }
+,
+]
+}
+```
+
+## initParam 默认查询参数,展示到UI上
+
+```
+{[
+  {
+    terms: [
+      {
+        column: 'name',
+        termType: 'eq',
+        value: '123'
+      },
+      {
+        column: 'name',
+        termType: 'eq',
+        value: '444'
+      },
+      {
+        column: 'name',
+        termType: 'eq',
+        value: '555'
+      },
+      {
+        column: 'name',
+        termType: 'eq',
+        value: '666'
+      },
+      {
+        column: 'username',
+        termType: 'eq',
+        value: 'username',
+        type: 'and'
+      }
+    ],
+    type: 'or'
+  },
+  {
+    terms: [
+      {
+        column: 'name',
+        termType: 'eq',
+        value: '132323'
+      },
+      {
+        column: 'name',
+        termType: 'eq',
+        value: '22'
+      },
+      {
+        column: 'name',
+        termType: 'eq',
+        value: '333'
+      },
+      {
+        column: 'name',
+        termType: 'eq',
+        value: '444'
+      },
+      {
+        column: 'username',
+        termType: 'eq',
+        value: '123123',
+        type: 'and'
+      }
+    ],
+    type: 'or'
+  },
+]}
 ```