diff --git a/.gitignore b/.gitignore
index da1b4aff..f7e98bb7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,4 @@ yarn-error.log*
package-lock.json
.idea
.codebuddy
+prompts
diff --git a/package.json b/package.json
index 3d2a9774..cd30bc51 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@kne-components/components-core",
- "version": "0.4.75",
+ "version": "0.5.0",
"files": [
"build"
],
@@ -35,6 +35,7 @@
"@kne/react-fetch": "^1.5.5",
"@kne/react-file": "^0.1.35",
"@kne/react-file-type": "^1.0.5",
+ "@kne/react-filter": "^1.0.5",
"@kne/react-form-antd": "^4.1.0",
"@kne/react-form-plus": "^0.1.5",
"@kne/react-icon": "^0.1.3",
@@ -102,7 +103,7 @@
"devDependencies": {
"@kne/craco": "^7.1.3",
"@kne/md-doc": "^0.1.16",
- "@kne/modules-dev": "^2.3.0",
+ "@kne/modules-dev": "^2.3.4",
"@kne/react-error-boundary": "^0.1.1",
"antd": "6.0.0",
"http-proxy-middleware": "^2.0.6",
diff --git a/src/components/Enum/commonStatus.js b/src/components/Enum/commonStatus.js
new file mode 100644
index 00000000..1471d844
--- /dev/null
+++ b/src/components/Enum/commonStatus.js
@@ -0,0 +1,12 @@
+import { createFormatMessage } from './withLocale';
+
+const commonStatus = ({ locale }) => {
+ const formatMessage = createFormatMessage(locale);
+ return [{
+ value: 'open', description: formatMessage({ id: 'CommonStatusOpen' }), type: 'success',
+ }, {
+ value: 'close', description: formatMessage({ id: 'CommonStatusClose' }), type: 'danger'
+ }];
+};
+
+export default commonStatus;
diff --git a/src/components/Enum/confirm.js b/src/components/Enum/confirm.js
new file mode 100644
index 00000000..d12ec954
--- /dev/null
+++ b/src/components/Enum/confirm.js
@@ -0,0 +1,12 @@
+import { createFormatMessage } from './withLocale';
+
+const confirm = ({ locale }) => {
+ const formatMessage = createFormatMessage(locale);
+ return [{
+ description: formatMessage({ id: 'ConfirmYes' }), value: "Y",
+ }, {
+ description: formatMessage({ id: 'ConfirmNo' }), value: "N",
+ }];
+};
+
+export default confirm;
diff --git a/src/components/Enum/degree.js b/src/components/Enum/degree.js
new file mode 100644
index 00000000..b289f5e9
--- /dev/null
+++ b/src/components/Enum/degree.js
@@ -0,0 +1,26 @@
+import { createFormatMessage } from './withLocale';
+
+const degree = ({ locale }) => {
+ const formatMessage = createFormatMessage(locale);
+ return [{
+ description: formatMessage({ id: 'DegreeJuniorHigh' }), value: 10,
+ }, {
+ description: formatMessage({ id: 'DegreeSecondaryVocational' }), value: 20,
+ }, {
+ description: formatMessage({ id: 'DegreeSeniorHigh' }), value: 30,
+ }, {
+ description: formatMessage({ id: 'DegreeJuniorCollege' }), value: 40,
+ }, {
+ description: formatMessage({ id: 'DegreeBachelor' }), value: 50,
+ }, {
+ description: formatMessage({ id: 'DegreeMaster' }), value: 60,
+ }, {
+ description: formatMessage({ id: 'DegreeDoctor' }), value: 70,
+ }, {
+ description: formatMessage({ id: 'DegreePostDoc' }), value: 75,
+ }, {
+ description: formatMessage({ id: 'DegreeUnlimited' }), value: 999,
+ }];
+};
+
+export default degree;
diff --git a/src/components/Enum/gender.js b/src/components/Enum/gender.js
new file mode 100644
index 00000000..30bc6fd6
--- /dev/null
+++ b/src/components/Enum/gender.js
@@ -0,0 +1,12 @@
+import { createFormatMessage } from './withLocale';
+
+const gender = ({ locale }) => {
+ const formatMessage = createFormatMessage(locale);
+ return [{
+ value: "M", description: formatMessage({ id: 'GenderMale' }),
+ }, {
+ value: "F", description: formatMessage({ id: 'GenderFemale' }),
+ }];
+};
+
+export default gender;
diff --git a/src/components/Enum/index.js b/src/components/Enum/index.js
index bf6e8b5a..8bf07af0 100644
--- a/src/components/Enum/index.js
+++ b/src/components/Enum/index.js
@@ -1,64 +1,27 @@
import {preset} from "@kne/react-enum";
-import transform from "lodash/transform";
-const degree = [{
- description: "初中", value: 10,
-}, {
- description: "中专", value: 20,
-}, {
- description: "高中", value: 30,
-}, {
- description: "大专", value: 40,
-}, {
- description: "本科", value: 50,
-}, {
- description: "硕士研究生", value: 60,
-}, {
- description: "博士研究生", value: 70,
-}, {
- description: "博士后", value: 75,
-}, {
- description: "学历不限", value: 999,
-}];
-
-const phoneState = [{
- value: 0, description: "空号",
-}, {
- value: 1, description: "实号",
-}, {
- value: 2, description: "停机",
-}, {
- value: 3, description: "库无",
-}, {
- value: 4, description: "沉默号",
-}, {
- value: 5, description: "风险号",
-}];
-
-const openStatus = [{value: 'open', description: '开启', type: 'success',}, {
- value: 'closed', description: '关闭', type: 'danger'
-}];
-
-const baseLoaders = [['openStatus', openStatus], ['commonStatus', () => [{
- value: 'open', description: '开启', type: 'success',
-}, {
- value: 'close', description: '关闭', type: 'danger'
-}]], ["gender", () => [{value: "M", description: "男"}, {
- value: "F", description: "女",
-},],], ["marital", () => [{description: "已婚", value: "Y"}, {
- description: "未婚", value: "N",
-},],], ["confirm", () => [{description: "是", value: "Y"}, {
- description: "否", value: "N",
-},],], ["political", () => [{description: "中共党员", value: "中共党员"}, {
- description: "共青团员", value: "共青团员",
-}, {description: "群众", value: "群众"}, {
- description: "其他党派", value: "其他党派",
-},],], ["phoneStateEnum", phoneState], ["phoneState", phoneState], ["degreeEnum", degree], ["degree", degree]];
+import degree from './degree';
+import phoneState from './phoneState';
+import openStatus from './openStatus';
+import commonStatus from './commonStatus';
+import gender from './gender';
+import marital from './marital';
+import confirm from './confirm';
+import political from './political';
preset({
- base: transform(baseLoaders, (result, value) => {
- result[value[0]] = value[1];
- }, {}),
+ base: {
+ openStatus,
+ commonStatus,
+ gender,
+ marital,
+ confirm,
+ political,
+ phoneStateEnum: phoneState,
+ phoneState,
+ degreeEnum: degree,
+ degree
+ },
});
export {default} from "@kne/react-enum";
diff --git a/src/components/Enum/locale/en-US.js b/src/components/Enum/locale/en-US.js
new file mode 100644
index 00000000..0c74feb7
--- /dev/null
+++ b/src/components/Enum/locale/en-US.js
@@ -0,0 +1,33 @@
+const message = {
+ DegreeJuniorHigh: "Junior High School",
+ DegreeSecondaryVocational: "Secondary Vocational",
+ DegreeSeniorHigh: "Senior High School",
+ DegreeJuniorCollege: "Junior College",
+ DegreeBachelor: "Bachelor",
+ DegreeMaster: "Master",
+ DegreeDoctor: "Doctor",
+ DegreePostDoc: "Postdoctoral",
+ DegreeUnlimited: "No Limit",
+ PhoneStateEmpty: "Empty",
+ PhoneStateValid: "Valid",
+ PhoneStateSuspended: "Suspended",
+ PhoneStateNotFound: "Not Found",
+ PhoneStateSilent: "Silent",
+ PhoneStateRisk: "Risk",
+ OpenStatusOpen: "Open",
+ OpenStatusClosed: "Closed",
+ CommonStatusOpen: "Open",
+ CommonStatusClose: "Closed",
+ GenderMale: "Male",
+ GenderFemale: "Female",
+ MaritalMarried: "Married",
+ MaritalSingle: "Single",
+ ConfirmYes: "Yes",
+ ConfirmNo: "No",
+ PoliticalPartyMember: "CPC Member",
+ PoliticalLeagueMember: "CYLC Member",
+ PoliticalMasses: "Masses",
+ PoliticalOther: "Other Parties"
+};
+
+export default message;
diff --git a/src/components/Enum/locale/zh-CN.js b/src/components/Enum/locale/zh-CN.js
new file mode 100644
index 00000000..2ac93392
--- /dev/null
+++ b/src/components/Enum/locale/zh-CN.js
@@ -0,0 +1,33 @@
+const message = {
+ DegreeJuniorHigh: "初中",
+ DegreeSecondaryVocational: "中专",
+ DegreeSeniorHigh: "高中",
+ DegreeJuniorCollege: "大专",
+ DegreeBachelor: "本科",
+ DegreeMaster: "硕士研究生",
+ DegreeDoctor: "博士研究生",
+ DegreePostDoc: "博士后",
+ DegreeUnlimited: "学历不限",
+ PhoneStateEmpty: "空号",
+ PhoneStateValid: "实号",
+ PhoneStateSuspended: "停机",
+ PhoneStateNotFound: "库无",
+ PhoneStateSilent: "沉默号",
+ PhoneStateRisk: "风险号",
+ OpenStatusOpen: "开启",
+ OpenStatusClosed: "关闭",
+ CommonStatusOpen: "开启",
+ CommonStatusClose: "关闭",
+ GenderMale: "男",
+ GenderFemale: "女",
+ MaritalMarried: "已婚",
+ MaritalSingle: "未婚",
+ ConfirmYes: "是",
+ ConfirmNo: "否",
+ PoliticalPartyMember: "中共党员",
+ PoliticalLeagueMember: "共青团员",
+ PoliticalMasses: "群众",
+ PoliticalOther: "其他党派"
+};
+
+export default message;
diff --git a/src/components/Enum/marital.js b/src/components/Enum/marital.js
new file mode 100644
index 00000000..dfbfedca
--- /dev/null
+++ b/src/components/Enum/marital.js
@@ -0,0 +1,12 @@
+import { createFormatMessage } from './withLocale';
+
+const marital = ({ locale }) => {
+ const formatMessage = createFormatMessage(locale);
+ return [{
+ description: formatMessage({ id: 'MaritalMarried' }), value: "Y",
+ }, {
+ description: formatMessage({ id: 'MaritalSingle' }), value: "N",
+ }];
+};
+
+export default marital;
diff --git a/src/components/Enum/openStatus.js b/src/components/Enum/openStatus.js
new file mode 100644
index 00000000..5b09fcd2
--- /dev/null
+++ b/src/components/Enum/openStatus.js
@@ -0,0 +1,12 @@
+import { createFormatMessage } from './withLocale';
+
+const openStatus = ({ locale }) => {
+ const formatMessage = createFormatMessage(locale);
+ return [{
+ value: 'open', description: formatMessage({ id: 'OpenStatusOpen' }), type: 'success',
+ }, {
+ value: 'closed', description: formatMessage({ id: 'OpenStatusClosed' }), type: 'danger'
+ }];
+};
+
+export default openStatus;
diff --git a/src/components/Enum/phoneState.js b/src/components/Enum/phoneState.js
new file mode 100644
index 00000000..c1d4b2a2
--- /dev/null
+++ b/src/components/Enum/phoneState.js
@@ -0,0 +1,20 @@
+import { createFormatMessage } from './withLocale';
+
+const phoneState = ({ locale }) => {
+ const formatMessage = createFormatMessage(locale);
+ return [{
+ value: 0, description: formatMessage({ id: 'PhoneStateEmpty' }),
+ }, {
+ value: 1, description: formatMessage({ id: 'PhoneStateValid' }),
+ }, {
+ value: 2, description: formatMessage({ id: 'PhoneStateSuspended' }),
+ }, {
+ value: 3, description: formatMessage({ id: 'PhoneStateNotFound' }),
+ }, {
+ value: 4, description: formatMessage({ id: 'PhoneStateSilent' }),
+ }, {
+ value: 5, description: formatMessage({ id: 'PhoneStateRisk' }),
+ }];
+};
+
+export default phoneState;
diff --git a/src/components/Enum/political.js b/src/components/Enum/political.js
new file mode 100644
index 00000000..1ceff728
--- /dev/null
+++ b/src/components/Enum/political.js
@@ -0,0 +1,16 @@
+import { createFormatMessage } from './withLocale';
+
+const political = ({ locale }) => {
+ const formatMessage = createFormatMessage(locale);
+ return [{
+ description: formatMessage({ id: 'PoliticalPartyMember' }), value: "中共党员",
+ }, {
+ description: formatMessage({ id: 'PoliticalLeagueMember' }), value: "共青团员",
+ }, {
+ description: formatMessage({ id: 'PoliticalMasses' }), value: "群众",
+ }, {
+ description: formatMessage({ id: 'PoliticalOther' }), value: "其他党派",
+ }];
+};
+
+export default political;
diff --git a/src/components/Enum/withLocale.js b/src/components/Enum/withLocale.js
new file mode 100644
index 00000000..386b6a14
--- /dev/null
+++ b/src/components/Enum/withLocale.js
@@ -0,0 +1,22 @@
+import {createWithIntlProvider, createIntl} from '@kne/react-intl';
+import zhCN from './locale/zh-CN';
+import enUS from './locale/en-US';
+
+const withLocale = createWithIntlProvider({
+ defaultLocale: 'zh-CN', messages: {
+ 'zh-CN': zhCN, 'en-US': enUS
+ }, namespace: 'Enum'
+});
+
+export const createFormatMessage = locale => {
+ const {formatMessage} = createIntl({
+ locale,
+ messages: {
+ 'zh-CN': zhCN, 'en-US': enUS
+ },
+ namespace: 'Enum'
+ });
+ return formatMessage;
+};
+
+export default withLocale;
diff --git a/src/components/Filter/AdvancedFilter/fields/CheckboxFilterItem.js b/src/components/Filter/AdvancedFilter/fields/CheckboxFilterItem.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/components/Filter/AdvancedFilter/fields/CityFilterItem.js b/src/components/Filter/AdvancedFilter/fields/CityFilterItem.js
deleted file mode 100644
index 450c48bf..00000000
--- a/src/components/Filter/AdvancedFilter/fields/CityFilterItem.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import {App, Tag} from "antd";
-import AddressSelectField, {
- getLabelForLocal,
- withAddressApi,
-} from "@common/components/AddressSelectField";
-import {FormattedMessage, useIntl} from "@components/Intl";
-import {usePreset} from "@components/Global";
-import {useMemo} from "react";
-import style from "../../style.module.scss";
-
-const {CheckableTag} = Tag;
-
-const CityFilterItemInner = ({
- value,
- onChange,
- single = false,
- maxLength = 5,
- addressApi,
- ...props
- }) => {
- const {message} = App.useApp();
- const {locale} = usePreset();
- const {formatMessage} = useIntl({moduleName: "Filter"});
- const cityList = useMemo(() => {
- return addressApi.getChinaHotCities();
- }, [addressApi]);
- return (
- <>
- {cityList.map((city) => {
- const {code} = city;
- const name = getLabelForLocal(city, locale);
- return (
- value === code)
- }
- onChange={(checked) => {
- if (single) {
- onChange(checked ? {value: code, label: name} : null);
- return;
- }
- const newValue = (value || []).slice(0);
- checked
- ? newValue.push({value: code, label: name})
- : (() => {
- const index = newValue.findIndex(
- ({value}) => value === code
- );
- newValue.splice(index, 1);
- })();
- if (newValue.length > maxLength) {
- message.error(
- formatMessage(
- {id: "maxSelectedCount"},
- {count: maxLength}
- )
- );
- return;
- }
- onChange(newValue);
- }}
- >
- {name}
-
- );
- })}
- 0) &&
- !cityList.find(({code}) =>
- single
- ? value?.value === code
- : !!(value || []).find(({value}) => value === code)
- )
- }
- >
-
- value)
- }
- single={single}
- onChange={(value, ...args) => {
- const getCityValue = (value) => {
- const {city} = addressApi.getCity(value);
- return {value: city?.code, label: city?.name};
- };
- onChange(
- single
- ? getCityValue(value)
- : value.map((value) => getCityValue(value))
- );
- }}
- />
-
- >
- );
-};
-const CityFilterItem = withAddressApi(CityFilterItemInner);
-export default CityFilterItem;
diff --git a/src/components/Filter/AdvancedFilter/fields/InputFilterItem.js b/src/components/Filter/AdvancedFilter/fields/InputFilterItem.js
deleted file mode 100644
index 003684f5..00000000
--- a/src/components/Filter/AdvancedFilter/fields/InputFilterItem.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { Input, Space, Button } from "antd";
-import { useState, useEffect, useRef } from "react";
-import useSimulationBlur from "@kne/use-simulation-blur";
-import { useIntl } from "@components/Intl";
-
-const InputFilterItem = ({ value, label, onChange, ...props }) => {
- const propsValue = value?.value;
- const [inputValue, setInputValue] = useState(propsValue || "");
- const [active, setActive] = useState(false);
- const { formatMessage } = useIntl({ moduleName: "Filter" });
- const searchHandler = () => {
- onChange(inputValue ? { label: inputValue, value: inputValue } : null);
- };
- const ref = useSimulationBlur(() => {
- setActive(false);
- searchHandler();
- });
- const inputValueRef = useRef("");
- inputValueRef.current = inputValue;
-
- useEffect(() => {
- if (propsValue !== inputValueRef.current) {
- setInputValue(propsValue);
- }
- }, [propsValue]);
- return (
-
-
- {
- setActive(true);
- }}
- onChange={(e) => {
- setInputValue(e.target.value);
- }}
- onPressEnter={searchHandler}
- />
- {active && (
-
- )}
-
-
- );
-};
-
-export default InputFilterItem;
diff --git a/src/components/Filter/AdvancedFilter/fields/ListFilterItem.js b/src/components/Filter/AdvancedFilter/fields/ListFilterItem.js
deleted file mode 100644
index f7f48ef8..00000000
--- a/src/components/Filter/AdvancedFilter/fields/ListFilterItem.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import {Tag, App} from "antd";
-import isEqual from "lodash/isEqual";
-import * as fields from "../../fields";
-import {useIntl} from "@components/Intl";
-
-const {CheckableTag} = Tag;
-const ListFilterItem = ({
- value,
- onChange,
- label,
- single = false,
- maxLength = 5,
- items = [],
- custom,
- }) => {
- const {message} = App.useApp();
- const {formatMessage} = useIntl({moduleName: "Filter"});
- return (
- <>
- {items.map(({label, value: itemValue}) => {
- return (
- isEqual(itemValue, value))
- }
- onChange={(checked) => {
- if (single) {
- onChange(checked ? {value: itemValue, label} : null);
- return;
- }
- const newValue = (value || []).slice(0);
- checked
- ? newValue.push({value: itemValue, label})
- : (() => {
- const index = newValue.find(({value}) =>
- isEqual(itemValue, value)
- );
- newValue.splice(index, 1);
- })();
- if (newValue.length > maxLength) {
- message.error(
- formatMessage(
- {id: "maxSelectedCount"},
- {count: maxLength}
- )
- );
- return;
- }
- onChange(newValue);
- }}
- >
- {label}
-
- );
- })}
- {custom &&
- (() => {
- const ComponentItem = Object.values(fields).find(
- (item) => item === custom.type
- );
- if (!ComponentItem) {
- return null;
- }
- return (
-
- );
- })()}
- >
- );
-};
-
-export default ListFilterItem;
diff --git a/src/components/Filter/AdvancedFilter/fields/SelectFilterItem.js b/src/components/Filter/AdvancedFilter/fields/SelectFilterItem.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/components/Filter/AdvancedFilter/fields/index.js b/src/components/Filter/AdvancedFilter/fields/index.js
deleted file mode 100644
index 38cb5177..00000000
--- a/src/components/Filter/AdvancedFilter/fields/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import CityFilterItem from "./CityFilterItem";
-import ListFilterItem from "./ListFilterItem";
-import InputFilterItem from "./InputFilterItem";
-
-const fields = { CityFilterItem, ListFilterItem, InputFilterItem };
-
-export default fields;
diff --git a/src/components/Filter/AdvancedFilter/index.js b/src/components/Filter/AdvancedFilter/index.js
deleted file mode 100644
index 98a82250..00000000
--- a/src/components/Filter/AdvancedFilter/index.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import FilterOuter from "../FilterOuter";
-import MoreFilterLines from "../FilterLines";
-import { Flex } from "antd";
-import advancedFields from "./fields";
-import { createWithIntl, useIntl } from "@components/Intl";
-import get from "lodash/get";
-import { useContext } from "../context";
-import style from "../style.module.scss";
-import FilterValueDisplay from "../FilterValueDisplay";
-import importMessages from "../locale";
-
-const Line = ({ list }) => {
- const { value, onChange } = useContext();
- return (
-
- {list.map((item, index) => {
- const ComponentItem = item.type;
- return (
-
- {item.props.label}:
-
-
- onChange({
- name: item.props.name,
- label: item.props.label,
- value,
- })
- : item.props.onChange
- }
- />
-
-
- );
- })}
-
- );
-};
-
-const AdvancedFilter = createWithIntl({ importMessages, moduleName: "Filter" })(
- (props) => {
- const { formatMessage } = useIntl({ moduleName: "Filter" });
- return (
-
- {({ value, onChange, props }) => {
- const { list, more } = props;
- return (
-
-
- {list.map((item, index) => {
- return ;
- })}
- {more && (
-
- )}
-
- {value && value.length > 0 && (
-
- )}
-
- );
- }}
-
- );
- }
-);
-
-AdvancedFilter.fields = advancedFields;
-export default AdvancedFilter;
-
-export { advancedFields };
diff --git a/src/components/Filter/Filter.js b/src/components/Filter/Filter.js
deleted file mode 100644
index 99b66fb9..00000000
--- a/src/components/Filter/Filter.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import FilterLines from "./FilterLines";
-import FilterValueDisplay from "./FilterValueDisplay";
-import FilterOuter from "./FilterOuter";
-
-const Filter = ({defaultValue=[],...props}) => {
- return (
-
- {({ props, value, onChange }) => {
- const { extraExpand, ...others } = props;
- return (
- <>
-
- {value && value.length > 0 && (
-
- )}
- >
- );
- }}
-
- );
-};
-
-export default Filter;
diff --git a/src/components/Filter/FilterItem.js b/src/components/Filter/FilterItem.js
deleted file mode 100644
index 22aec609..00000000
--- a/src/components/Filter/FilterItem.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import classnames from "classnames";
-import { Space } from "antd";
-import Icon from "@components/Icon";
-import style from "./style.module.scss";
-
-const FilterItem = ({ open, active, label, children }) => {
- return (
-
-
-
- {label}
-
-
-
{children}
-
-
- );
-};
-
-export default FilterItem;
diff --git a/src/components/Filter/FilterItemContainer.js b/src/components/Filter/FilterItemContainer.js
deleted file mode 100644
index df1d1ecd..00000000
--- a/src/components/Filter/FilterItemContainer.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const FilterItemContainer = ({ children, ...props }) => {
- return children(props);
-};
-
-export default FilterItemContainer;
diff --git a/src/components/Filter/FilterLines.js b/src/components/Filter/FilterLines.js
deleted file mode 100644
index 2357c75b..00000000
--- a/src/components/Filter/FilterLines.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import classnames from "classnames";
-import {useState} from "react";
-import Icon from "@components/Icon";
-import style from "./style.module.scss";
-import {Col, Row, Space} from "antd";
-import {FormattedMessage, IntlProvider} from "@components/Intl";
-import importMessages from "./locale";
-import {useContext} from "./context";
-import get from "lodash/get";
-
-const Line = ({list, children}) => {
- const {value, onChange} = useContext();
- return (
- {list.filter((item) => !!item.type).map((item, index) => {
- if (typeof item === "function") {
- return item((props) => {
- return {
- index,
- value: value ? get(value.get(props?.name), "value") : props?.value,
- onChange: onChange ? (value) => onChange({
- name: props?.name, label: props?.label, value,
- }) : props?.onChange,
- };
- });
- }
- const ComponentItem = item.type;
- return ( onChange({
- name: item.props.name, label: item.props.label, value,
- }) : item.props.onChange,
- })}
- key={item.key || item.props.name || index}
- />);
- })}
- {children}
-
);
-};
-
-const FilterLines = ({
- className, list = [], displayLine = 1, label, extra, children,
- }) => {
- const hasMore = list.length > displayLine;
- const [isExpand, setIsExpand] = useState(false);
- return (
-
-
- {list && list.length > 0 && (label || )}
-
-
-
- {list.slice(0, displayLine).map((item, index) => (
- {hasMore && isExpand === false && index === displayLine - 1 ? ( {
- setIsExpand((value) => !value);
- }}
- >
-
-
- ) : null}
- ))}
-
- {extra}
-
-
-
- {children}
-
-
-
-
-
-
- {list.slice(displayLine).map((item, index) => (
- {index === list.length - displayLine - 1 && (<>
-
-
-
-
-
-
- {
- setIsExpand((value) => !value);
- }}
- >
-
-
-
-
-
- >)}
- ))}
-
-
- );
-};
-
-export default FilterLines;
diff --git a/src/components/Filter/FilterOuter.js b/src/components/Filter/FilterOuter.js
deleted file mode 100644
index b2197ab4..00000000
--- a/src/components/Filter/FilterOuter.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import classnames from "classnames";
-import style from "./style.module.scss";
-import FilterProvider from './FilterProvider';
-
-const FilterOuter = ({children, className, ...props}) => {
- return
- {(context) =>
- {children(context)}
-
}
-
-
-};
-
-export default FilterOuter;
diff --git a/src/components/Filter/FilterProvider.js b/src/components/Filter/FilterProvider.js
deleted file mode 100644
index bbf488d1..00000000
--- a/src/components/Filter/FilterProvider.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import {Provider} from "./context";
-import useControlValue from "@kne/use-control-value";
-import clone from "lodash/clone";
-import {useMemo} from "react";
-import {isNotEmpty} from "@components/Common";
-import importMessages from "./locale";
-
-import {IntlProvider} from "@components/Intl";
-
-const FilterOuter = ({children, className, defaultValue = [], ...props}) => {
- const [valueBase, onChange] = useControlValue(props);
-
- const value = useMemo(() => {
- return valueBase.filter((item) => isNotEmpty(item.value));
- }, [valueBase]);
-
- const filterValue = useMemo(() => {
- return new Map(value.map((item) => [item.name, item]));
- }, [value]);
-
- return (
-
- {
- const newFilterValue = clone(filterValue);
- item.value
- ? newFilterValue.set(item.name, item)
- : newFilterValue.delete(item.name);
- onChange?.(Array.from(newFilterValue.values()));
- },
- }}
- >
- {typeof children === 'function' ? children({props, value, onChange}) : children}
-
-
- );
-};
-
-export default FilterOuter;
diff --git a/src/components/Filter/FilterValueDisplay.js b/src/components/Filter/FilterValueDisplay.js
deleted file mode 100644
index f3d923b5..00000000
--- a/src/components/Filter/FilterValueDisplay.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import { Button, Space } from "antd";
-import StateTag from "@components/StateTag";
-import { FormattedMessage, IntlProvider } from "@components/Intl";
-import style from "@components/Filter/style.module.scss";
-import classnames from "classnames";
-import importMessages from "@components/Filter/locale";
-
-const FilterValueDisplay = ({ value: filterValue, extraExpand, onChange }) => {
- return (
-
-
-
-
-
- {/**/}
-
- {filterValue.map(({ name, label, value }, index) => {
- return (
- {
- return item.label;
- })
- .join(",")
- : value.label
- }
- closable
- onClose={() => {
- const newValue = filterValue.slice(0);
- newValue.splice(index, 1);
- onChange(newValue);
- }}
- />
- );
- })}
-
- {extraExpand}
-
-
-
- {extraExpand}
-
-
-
-
- {/*
*/}
-
-
- );
-};
-
-export default FilterValueDisplay;
diff --git a/src/components/Filter/PopoverItem.js b/src/components/Filter/PopoverItem.js
deleted file mode 100644
index 49f4e15d..00000000
--- a/src/components/Filter/PopoverItem.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import {useState, useMemo} from "react";
-import {Button, Col, Popover, Row} from "antd";
-import FilterItem from "./FilterItem";
-import isNotEmpty from "@common/utils/isNotEmpty";
-import classnames from "classnames";
-import {FormattedMessage} from "@components/Intl";
-import style from "./style.module.scss";
-
-const PopoverItem = ({
- value,
- label,
- onValidate,
- overlayClassName,
- placement = 'bottomLeft',
- onOpenChange,
- onChange,
- children,
- }) => {
- const [state, setState] = useState(value);
- const [open, setOpen] = useState(false);
- const disabled = useMemo(() => {
- return onValidate && !onValidate(state);
- }, [onValidate, state]);
- return ( {
- setOpen(open);
- setState(value);
- onOpenChange && onOpenChange(open);
- }}
- content={ {
- e.stopPropagation();
- }}
- >
-
- {children({value: state, onChange: setState})}
-
-
-
-
-
-
-
-
-
- }
- >
-
-
-
- );
-};
-
-export default PopoverItem;
diff --git a/src/components/Filter/README.md b/src/components/Filter/README.md
index 4b350a47..84e069b1 100644
--- a/src/components/Filter/README.md
+++ b/src/components/Filter/README.md
@@ -1,407 +1,219 @@
-# Filter
+# react-filter
-### 概述
+### 描述
-Filter 是一个功能强大的筛选组件库,用于构建灵活的筛选条件界面。该组件提供了多种预置的筛选字段类型,支持自定义筛选项,并提供了完整的筛选值管理和展示功能。
+A React filter component library with multiple filter types, flexible layouts, and URL parameter synchronization.
-核心特性包括:丰富的预置筛选字段,涵盖文本输入、日期选择、城市选择、用户选择、行业选择、职能选择等多种类型;灵活的筛选值管理,支持受控和非受控模式;声明式筛选值映射(`createFilterValueMapper`),统一处理多选、单选、自定义转换等值提取逻辑;URL 参数序列化与初始化(`filterToUrlParams` / `createUrlFilterReader` / `useUrlFilter`),筛选值以 `filterParams[key]` 格式序列化到 URL(前缀可自定义),从 URL 参数构建初始筛选状态并自动清理已消费参数;值格式拦截器(`filterInterceptors`),自动处理 SuperSelect 组件 `{ id, name }` 与 Filter 上下文 `{ label, value }` 格式之间的转换;支持展开/收起筛选项,避免筛选条件过多导致界面混乱;提供高级筛选组件,适用于复杂筛选场景;支持自定义字段和组合使用,满足各种业务需求;内置搜索输入框和筛选值展示组件,提升用户体验。
+### 安装
-适用于数据列表、表格筛选、报表查询等需要多条件筛选的场景。组件采用 Context API 进行状态管理,支持嵌套使用和组合,能够满足企业级应用中各种复杂的筛选需求。
+```shell
+npm i --save @kne/react-filter
+```
-### 示例(全屏)
+### 概述
-#### 示例代码
+### React Filter
-- 基础用法
-- 展示 Filter 组件的基本使用方式,包括各种常见的筛选字段类型
-- _Filter(@components/Filter)
+一个功能强大的 React 筛选组件库,支持多种筛选字段类型、灵活的布局方式,以及完善的 URL 参数双向同步能力。
-```jsx
-const {
- default: Filter,
- InputFilterItem,
- DatePickerFilterItem,
- DateRangePickerFilterItem,
- TypeDateRangePickerFilterItem,
- CityFilterItem,
- AdvancedSelectFilterItem,
- SuperSelectFilterItem,
- SuperSelectUserFilterItem,
- UserFilterItem,
- FunctionSelectFilterItem,
- IndustrySelectFilterItem,
- getFilterValue,
- FilterItemContainer,
-} = _Filter;
-const { useState } = React;
-const BaseExample = () => {
- const [value, onChange] = useState([]);
- return (
- {
- console.log(getFilterValue(value));
- onChange(value);
- }}
- extra={}
- list={[
- [
- ,
- ,
-
- {(props) => (
-
-
{
- return {
- pageData: [
- { label: "第一项", value: 1 },
- {
- label: "第二项",
- value: 2,
- disabled: true,
- },
- {
- label: "第三项",
- value: 3,
- },
- ],
- };
- },
- }}
- />
-
- )}
- ,
- ,
- ,
- ,
- ,
- {
- return {
- pageData: [
- {
- label: "用户一",
- value: 1,
- description: "我是用户描述",
- },
- {
- label: "用户二",
- value: 2,
- description: "我是用户描述",
- },
- {
- label: "用户三",
- value: 3,
- description: "我是用户描述",
- },
- ],
- };
- },
- }}
- />,
- ,
- ,
- ,
- ,
- ,
- ,
- ],
- ]}
- />
- );
-};
+### 主要特性
-render();
+- **多种筛选字段类型**:支持输入框、数字区间、日期选择、日期范围、下拉选择等常用筛选类型,以及职能、行业、城市等业务选择器
+- **灵活布局**:支持普通筛选(横向布局)和高级筛选(垂直布局)两种模式
+- **展开收起**:筛选行支持展开收起功能,优化页面空间利用
+- **已选值展示**:自动展示已选筛选条件,支持单独删除和清空全部
+- **弹出层交互**:支持弹出层形式的筛选交互,确认后才生效
+- **URL 参数同步**:支持筛选值与 URL 参数的双向序列化/反序列化,自动清除已消费参数
+- **数据格式拦截器**:内置 `{id, name}` ↔ `{label, value}` 格式转换拦截器,适配 SuperSelect 场景
+- **声明式值映射**:提供 `createFilterValueMapper` 按字段声明转换规则,简化 `getFilterValue` 结果处理
+- **国际化支持**:内置中英文语言包,支持多语言切换
+- **高阶组件**:提供 `withFilterValue` 和 `withFieldItem` 高阶组件,便于扩展自定义字段
-```
+### 适用场景
-- 展示和Enum一起使用
--
-- _Filter(@components/Filter),_Enum(@components/Enum)
+- 数据列表页面的筛选功能
+- 复杂表单的筛选条件配置
+- 多条件组合查询场景
+- 需要展示已选筛选条件的场景
+- 需要筛选状态与 URL 参数同步保持的页面
-```jsx
-const {
- default: Filter, SuperSelectFilterItem, getFilterValue
-} = _Filter;
-const {default: Enum} = _Enum;
-const {useState} = React;
-const BaseExample = () => {
- const [value, onChange] = useState([]);
- return ( {
- console.log(getFilterValue(value));
- onChange(value);
- }}
- list={[[ {
- return {(options) => children({options})}
- }}/>]]}
- />);
-};
+### 快速开始
-render();
+```javascript
+import Filter, { fields } from '@kne/react-filter';
+import '@kne/react-filter/dist/index.css';
-```
+const { InputFilterItem, NumberRangeFilterItem, DatePickerFilterItem } = fields;
-- 高级筛选
-- 展示 AdvancedFilter 组件的高级筛选功能,适用于复杂筛选场景
-- _Filter(@components/Filter)
+function MyComponent() {
+ const [filterValue, setFilterValue] = useState([]);
-```jsx
-const {
- default: Filter,
- AdvancedFilter,
- InputFilterItem,
- DatePickerFilterItem,
- DateRangePickerFilterItem,
- TypeDateRangePickerFilterItem,
- CityFilterItem,
- AdvancedSelectFilterItem,
- UserFilterItem,
- FunctionSelectFilterItem,
- IndustrySelectFilterItem,
- NumberRangeFilterItem,
- getFilterValue,
- FilterItemContainer,
-} = _Filter;
-const { useState } = React;
+ const handleSearch = () => {
+ const params = Filter.getFilterValue(filterValue);
+ console.log('筛选参数:', params);
+ };
-const {
- CityFilterItem: CityAdvancedFilterItem,
- ListFilterItem,
- InputFilterItem: InputAdvancedFilterItem,
-} = AdvancedFilter.fields;
-const BaseExample = () => {
- const [value, onChange] = useState([]);
return (
- {
- console.log(getFilterValue(value));
- onChange(value);
- }}
+ ],
- [],
[
- }
- />,
+ { type: InputFilterItem, props: { name: 'keyword', label: '关键词' } },
+ { type: NumberRangeFilterItem, props: { name: 'amount', label: '金额' } }
],
- [],
- ]}
- more={[
- ,
- ,
-
- {(props) => (
-
-
{
- return {
- pageData: [
- { label: "第一项", value: 1 },
- {
- label: "第二项",
- value: 2,
- disabled: true,
- },
- {
- label: "第三项",
- value: 3,
- },
- ],
- };
- },
- }}
- />
-
- )}
- ,
- ,
- ,
- ,
- {
- return {
- pageData: [
- {
- label: "用户一",
- value: 1,
- description: "我是用户描述",
- },
- {
- label: "用户二",
- value: 2,
- description: "我是用户描述",
- },
- {
- label: "用户三",
- value: 3,
- description: "我是用户描述",
- },
- ],
- };
- },
- }}
- />,
- ,
- ,
+ [
+ { type: DatePickerFilterItem, props: { name: 'date', label: '日期' } }
+ ]
]}
+ displayLine={1}
+ extra={}
/>
);
-};
+}
+```
-render();
+### 核心组件
+
+| 组件 | 说明 |
+|------|------|
+| `Filter` | 主筛选组件,横向布局,支持展开收起 |
+| `AdvancedFilter` | 高级筛选组件,垂直布局 |
+| `FilterValueDisplay` | 已选值展示组件 |
+| `PopoverItem` | 弹出层筛选项组件 |
+| `FilterItem` | 筛选项容器组件 |
+| `FilterLines` | 筛选行组件 |
+| `FilterProvider` | 状态管理组件 |
+
+### 筛选字段
+
+| 字段组件 | 说明 |
+|----------|------|
+| `InputFilterItem` | 输入框筛选 |
+| `NumberRangeFilterItem` | 数字区间筛选 |
+| `DatePickerFilterItem` | 日期选择筛选 |
+| `DateRangePickerFilterItem` | 日期范围筛选 |
+| `TypeDateRangePickerFilterItem` | 类型日期范围筛选(日/周/月切换) |
+| `SuperSelectFilterItem` | 通用选择器筛选(单选/多选/搜索/全选) |
+| `SelectFunctionFilterItem` | 职能筛选(多级数据、拼音搜索) |
+| `SelectIndustryFilterItem` | 行业筛选(多级数据、拼音搜索) |
+| `SelectAddressFilterItem` | 城市筛选(国内外城市搜索) |
+
+### URL 参数工具
+
+| 工具 | 说明 |
+|------|------|
+| `useUrlFilter` | 从 URL 参数初始化筛选状态的 hook |
+| `useUrlFilterValue` | 简化版 URL 筛选 hook,自动解析 filterParams[key] 格式 |
+| `filterToUrlParams` | 将筛选值序列化为 URL 参数 |
+| `parseFilterEntry` | 解析 URL 参数中的单个筛选值项 |
+| `takeFilterEntry` | 从 URL 参数中读取筛选值项 |
+| `createUrlFilterReader` | 创建 URL 筛选参数读取器 |
+| `createUrlParamsReader` | 创建通用 URL 参数读取器 |
+| `stripConsumedUrlParams` | 移除已消费的 URL 参数 |
+
+### 其他工具
+
+| 工具 | 说明 |
+|------|------|
+| `pickSelectValues` | 从筛选值中提取原始值数组 |
+| `createFilterValueMapper` | 声明式创建 mapFilterValue 函数 |
+| `filterInterceptors` | `{single, multi}` 拦截器集合 |
+| `singleSelectInterceptor` | 单选格式转换拦截器 |
+| `multiSelectInterceptor` | 多选格式转换拦截器 |
+
+
+### 示例
-```
+#### 示例代码
-- 树形筛选
-- 展示 TreeFilterItem 树形选择组件的使用
-- _Filter(@components/Filter),antd(antd),_data(@components/Filter/doc/mock/tree-data.json)
+- 基础筛选
+- 使用 Filter 主组件,展示关键词、金额、日期、部门等多种筛选字段的组合使用
+- _ReactFilter(@kne/react-filter)[import * as _ReactFilter from "@kne/react-filter"],(@kne/react-filter/dist/index.css),antd(antd)
```jsx
-const { default: Filter, TreeFilterItem } = _Filter;
-const { default: treeData } = _data;
+const { default: Filter, fields } = _ReactFilter;
+const {
+ InputFilterItem, NumberRangeFilterItem, DatePickerFilterItem,
+ DateRangePickerFilterItem, TypeDateRangePickerFilterItem,
+ SuperSelectFilterItem, SelectFunctionFilterItem,
+ SelectIndustryFilterItem, SelectAddressFilterItem
+} = fields;
+const { Flex, Button, message } = antd;
const { useState } = React;
-const { Space } = antd;
+
+const departmentOptions = [
+ { value: 'tech', label: '技术研发部' },
+ { value: 'product', label: '产品设计部' },
+ { value: 'operation', label: '运营管理部' },
+ { value: 'hr', label: '人力资源部' },
+ { value: 'finance', label: '财务部' },
+ { value: 'marketing', label: '市场营销部' }
+];
const BaseExample = () => {
- const [filter, setFilter] = useState([]);
- const [filter2, setFilter2] = useState([]);
+ const [filterValue, setFilterValue] = useState([]);
+
+ const handleSearch = () => {
+ const params = Filter.getFilterValue(filterValue);
+ message.info(`搜索参数: ${JSON.stringify(params, null, 2)}`);
+ console.log('筛选参数:', params);
+ };
return (
-
+
{
- return treeData.children;
- },
- }}
- />,
+ {
+ type: InputFilterItem,
+ props: { name: 'keyword', label: '关键词', placeholder: '请输入关键词搜索' }
+ },
+ {
+ type: NumberRangeFilterItem,
+ props: { name: 'amount', label: '金额', unit: '元', min: 0, max: 999999 }
+ },
+ {
+ type: DatePickerFilterItem,
+ props: { name: 'createTime', label: '创建时间', format: 'YYYY-MM-DD' }
+ },
+ {
+ type: DateRangePickerFilterItem,
+ props: { name: 'dateRange', label: '日期范围', format: 'YYYY-MM-DD' }
+ },
+ {
+ type: TypeDateRangePickerFilterItem,
+ props: { name: 'typeDateRange', label: '快捷日期' }
+ }
],
- ]}
- />
- {
- return treeData.children;
- },
- }}
- />,
- ],
+ {
+ type: SuperSelectFilterItem,
+ props: { name: 'department', label: '部门', options: departmentOptions }
+ },
+ {
+ type: SelectFunctionFilterItem,
+ props: { name: 'function', label: '职能' }
+ },
+ {
+ type: SelectIndustryFilterItem,
+ props: { name: 'industry', label: '行业' }
+ },
+ {
+ type: SelectAddressFilterItem,
+ props: { name: 'city', label: '城市' }
+ }
+ ]
]}
+ displayLine={1}
/>
-
+
+ 当前筛选值:
+ {JSON.stringify(filterValue, null, 2)}
+
+
);
};
@@ -409,1548 +221,1142 @@ render();
```
-- 筛选值展示
-- 展示 FilterValueDisplay、FilterItem、FilterLines、PopoverItem 等组件的独立使用
-- _Filter(@components/Filter),antd(antd)
+- 高级筛选
+- 使用 AdvancedFilter 组件实现更复杂的筛选布局
+- _ReactFilter(@kne/react-filter)[import * as _ReactFilter from "@kne/react-filter"],(@kne/react-filter/dist/index.css),antd(antd)
```jsx
-const {
- FilterValueDisplay,
- FilterItem,
- FilterLines,
- PopoverItem,
- InputFilterItem,
- CityFilterItem,
- AdvancedSelectFilterItem,
- UserFilterItem,
- FunctionSelectFilterItem,
- IndustrySelectFilterItem,
-} = _Filter;
-const { Space, Input } = antd;
+const { AdvancedFilter } = _ReactFilter;
+const { InputFilterItem, ListFilterItem, CityFilterItem } = AdvancedFilter.fields;
+const { Flex, Button, message } = antd;
const { useState } = React;
-const BaseExample = () => {
- const [value, setValue] = useState([
- {
- label: "城市",
- name: "city",
- value: [
- { label: "上海", value: "010" },
- { label: "北京", value: "020" },
- ],
- },
- {
- label: "职能",
- name: "function",
- value: [
- { label: "产品经理", value: "010" },
- { label: "销售", value: "020" },
- {
- label: "客户经理",
- value: "030",
- },
- ],
- },
- ]);
+
+const AdvancedFilterExample = () => {
+ const [filterValue, setFilterValue] = useState([]);
+
+ const handleSearch = () => {
+ const params = {};
+ filterValue.forEach(item => {
+ params[item.name] = Array.isArray(item.value)
+ ? item.value.map(v => v.value)
+ : item.value?.value;
+ });
+ message.info(`搜索参数: ${JSON.stringify(params, null, 2)}`);
+ console.log('筛选参数:', params);
+ };
+
return (
-
-
-
-
-
-
-
-
-
+ ,
- ,
- ,
- ],
- [
- ,
- ,
- ,
+ {
+ type: InputFilterItem,
+ props: {
+ name: 'name',
+ label: '姓名'
+ }
+ },
+ {
+ type: InputFilterItem,
+ props: {
+ name: 'phone',
+ label: '手机号'
+ }
+ }
],
[
- ,
- ,
- ,
+ {
+ type: ListFilterItem,
+ props: {
+ name: 'status',
+ label: '状态',
+ single: true,
+ items: [
+ { label: '待处理', value: 'pending' },
+ { label: '处理中', value: 'processing' },
+ { label: '已完成', value: 'completed' },
+ { label: '已取消', value: 'cancelled' }
+ ]
+ }
+ }
],
[
- ,
- ,
- ,
+ {
+ type: ListFilterItem,
+ props: {
+ name: 'tags',
+ label: '标签',
+ single: false,
+ maxLength: 3,
+ items: [
+ { label: '前端', value: 'frontend' },
+ { label: '后端', value: 'backend' },
+ { label: '全栈', value: 'fullstack' },
+ { label: 'UI设计', value: 'ui' },
+ { label: '产品', value: 'product' }
+ ]
+ }
+ }
],
- ]}
- />
-
- {({ value, onChange }) => (
- onChange(e.target.value)} />
- )}
-
- ,
- ,
- {
- return {
- pageData: [
- { label: "第一项", value: 1 },
- { label: "第二项", value: 2, disabled: true },
- {
- label: "第三项",
- value: 3,
- },
- ],
- };
- },
- }}
- />,
- {
- return {
- pageData: [
- {
- label: "用户一",
- value: 1,
- description: "我是用户描述",
- },
- {
- label: "用户二",
- value: 2,
- description: "我是用户描述",
- },
- {
- label: "用户三",
- value: 3,
- description: "我是用户描述",
- },
- ],
- };
- },
- }}
- />,
- ,
- ,
- ],
+ {
+ type: CityFilterItem,
+ props: {
+ name: 'city',
+ label: '城市',
+ maxLength: 3
+ }
+ }
+ ]
]}
/>
-
+
+
+
+
+ 当前筛选值:
+
+ {JSON.stringify(filterValue, null, 2)}
+
+
+
);
};
-render();
+render();
```
-- 数值范围筛选
-- 展示 NumberRangeFilterItem 数值范围筛选组件的使用
-- _Filter(@components/Filter)
+- 筛选字段组件
+- 展示所有筛选字段组件类型,包括输入筛选、数字区间、日期选择、下拉选择以及 SuperSelect 业务选择器(职能/行业/城市)
+- _ReactFilter(@kne/react-filter)[import * as _ReactFilter from "@kne/react-filter"],(@kne/react-filter/dist/index.css),antd(antd)
```jsx
+const { fields, PopoverItem } = _ReactFilter;
const {
- default: Filter,
- NumberRangeFilterItem,
- getFilterValue,
-} = _Filter;
+ InputFilterItem, NumberRangeFilterItem, DatePickerFilterItem,
+ DateRangePickerFilterItem, TypeDateRangePickerFilterItem,
+ SuperSelectFilterItem, SelectFunctionFilterItem,
+ SelectIndustryFilterItem, SelectAddressFilterItem
+} = fields;
+const { Input, InputNumber, Space, Flex, Select, Divider, Tag } = antd;
const { useState } = React;
-const BaseExample = () => {
- const [value, onChange] = useState([]);
-
+// 自定义下拉选择筛选项
+const SelectFilterItem = ({ label, value, onChange, options = [] }) => {
return (
- {
- console.log('筛选值:', getFilterValue(value));
- onChange(value);
- }}
- list={[
- [
- ,
- ,
- ,
- ],
- ]}
- />
+ onChange={onChange}
+ >
+ {({ value, onChange }) => (
+