From 8fde136fefc3bc74660dff6700855591a3d86aa1 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Mon, 7 Apr 2025 18:44:19 +0800 Subject: [PATCH 01/22] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=94=B5?= =?UTF-8?q?=E6=A2=AF=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/address.scss | 10 +- src/packages/address/address.tsx | 148 +++++--- src/packages/address/demos/h5/demo1.tsx | 13 + src/packages/address/elevator.scss | 105 ++++++ src/packages/address/elevatorRender.taro.tsx | 84 +++++ src/packages/address/elevatorRender.tsx | 342 +++++++++++++++++++ 6 files changed, 649 insertions(+), 53 deletions(-) create mode 100644 src/packages/address/elevator.scss create mode 100644 src/packages/address/elevatorRender.taro.tsx create mode 100644 src/packages/address/elevatorRender.tsx diff --git a/src/packages/address/address.scss b/src/packages/address/address.scss index c8f6a3ceca..53b3337ad3 100644 --- a/src/packages/address/address.scss +++ b/src/packages/address/address.scss @@ -1,11 +1,11 @@ -@import '../elevator/elevator.scss'; +@import './elevator.scss'; @import '../cascader/cascader.scss'; .nut-address { - &-elevator { - display: flex; - margin-top: 20px; - } + // &-elevator { + // display: flex; + // margin-top: 20px; + // } &-exist { display: block; diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index 08a8e90e73..d308f032f1 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -7,6 +7,7 @@ import React, { import { ArrowLeft } from '@nutui/icons-react' import Popup from '@/packages/popup' import { CustomRender } from './customRender' +import { ElevatorRender } from './elevatorRender' import { ExistRender } from './existRender' import { useConfig } from '@/packages/configprovider' import { @@ -21,12 +22,13 @@ import { usePropsValue } from '@/hooks/use-props-value' const defaultProps = { ...ComponentDefaults, defaultValue: [], - type: 'custom', + type: 'elevator', options: [], optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, format: {}, custom: false, existList: [], + hotList: [], height: '200px', defaultIcon: null, selectIcon: null, @@ -62,6 +64,7 @@ export const InternalAddress: ForwardRefRenderFunction< defaultIcon, closeIcon, backIcon, + hotList, onChange, onExistSelect, onClose, @@ -123,55 +126,104 @@ export const InternalAddress: ForwardRefRenderFunction< } onSwitch && onSwitch({ type: currentType }) } + const renderElevator = () => { + return ( + +
+ { + // 不需要 close,选中切换即关闭弹框。可手动关闭弹框,只关闭弹框不处理逻辑。 + { + onChange?.(val, params) + }} + /> + } +
+
+ ) + } + const renderCascator = () => { + return ( + { + onChange?.(val, params) + }} + /> + ) + } + const renderExist = () => { + return ( + +
+ { + // 不需要 close,选中切换即关闭弹框。可手动关闭弹框,只关闭弹框不处理逻辑。 + + } +
+
+ ) + } return ( <> - {currentType === 'custom' || currentType === 'custom2' ? ( - { - onChange?.(val, params) - }} - /> - ) : ( - -
- { - // 不需要 close,选中切换即关闭弹框。可手动关闭弹框,只关闭弹框不处理逻辑。 - - } -
-
- )} + {currentType === 'elevator' ? renderElevator() : null} + {currentType === 'custom' ? renderCascator() : null} + {currentType === 'exist' ? renderExist() : null} ) } diff --git a/src/packages/address/demos/h5/demo1.tsx b/src/packages/address/demos/h5/demo1.tsx index 945b80217e..0c26181ccb 100644 --- a/src/packages/address/demos/h5/demo1.tsx +++ b/src/packages/address/demos/h5/demo1.tsx @@ -3,6 +3,18 @@ import { Address, Cell } from '@nutui/nutui-react' const Demo1 = () => { const [text, setText] = useState('选择地址') + const [hotList, setHotList] = useState([ + { id: '1', name: '北京' }, + { id: '2', name: '上海' }, + { id: '1601', name: '广州' }, + { id: '1607', name: '深圳' }, + { id: '1213', name: '杭州' }, + { id: '904', name: '南京' }, + { id: '988', name: '苏州' }, + { id: '3', name: '天津' }, + { id: '3', name: '天津' }, + { id: '3', name: '天津' }, + ]) const [optionsDemo1] = useState([ { value: '浙江', @@ -77,6 +89,7 @@ const Demo1 = () => { />
{ diff --git a/src/packages/address/elevator.scss b/src/packages/address/elevator.scss new file mode 100644 index 0000000000..c091f34bb5 --- /dev/null +++ b/src/packages/address/elevator.scss @@ -0,0 +1,105 @@ +@import '../elevator/elevator.scss'; +@import '../cascader/cascader.scss'; + +.nut-address { + &-title { + font-size: 14px; + font-weight: 500; + padding: 16px 16px 12px 16px; + } + &-hotlist { + padding: 0 16px; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: left; + &-item { + display: flex; + justify-content: center; + align-items: center; + width: 63px; + height: 28px; + font-size: 12px; + border-radius: 4px; + margin-bottom: 7px; + background-color: $color-background-sunken; + color: $color-title; + &:last-child { + margin-right: 0; + } + } + + &:has(.nut-address-hotlist-item:nth-child(5)) { + justify-content: space-between; + } + } + + &-selected { + width: 100%; + height: 60px; + padding: 0 16px; + display: flex; + flex-wrap: wrap; + align-items: center; + border-bottom: 1px solid $color-border; + &-item { + font-size: 12px; + // display: flex; + display: inline-block; + // justify-content: center; + // align-items: center; + height: 48px; + line-height: 48px; + padding: 0 12px; + border-radius: 4px; + background-color: $color-background-sunken; + } + &-border { + margin: 0 2px; + color: $color-text-disabled; + } + } + + &-elevator { + margin-top: 0; + .nut-elevator-list { + &-item { + position: relative; + padding-left: 20px; + } + &-item-code { + display: inline; + position: absolute; + left: 0; + top: 0; + height: 30px; + line-height: 30px; + border-bottom: 0; + color: $color-text-help; + font-weight: 500; + } + } + .nut-elevator-bars { + top: 40%; + padding: 0; + background: none; + + &-inner-item { + display: flex; + justify-content: center; + align-items: center; + width: 16px; + height: 16px; + font-size: 10px; + border-radius: 16px; + margin-bottom: 2px; + color: $color-text-help; + &-active { + background-color: $color-primary; + color: $color-background-overlay; + font-weight: 400; + } + } + } + } +} diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx new file mode 100644 index 0000000000..ab2fd80289 --- /dev/null +++ b/src/packages/address/elevatorRender.taro.tsx @@ -0,0 +1,84 @@ +import React, { FunctionComponent } from 'react' +import { + TaroCascaderProps, + CascaderOption, + CascaderValue, + CascaderOptionKey, +} from '@/types' +import { ComponentDefaults } from '@/utils/typings' +import Cascader from '@/packages/cascader/index.taro' + +export interface AddressProps extends TaroCascaderProps { + visible: boolean // popup visible + type: string + options: CascaderOption[] + value: CascaderValue + defaultValue: CascaderValue + optionKey: CascaderOptionKey + format: Record + height: string | number +} + +const defaultProps = { + ...ComponentDefaults, + visible: false, + type: 'custom', + options: [], + optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, + format: {}, + height: '200px', +} as unknown as AddressProps + +export const CustomRender: FunctionComponent< + Partial & + Omit< + React.HTMLAttributes, + 'title' | 'defaultValue' | 'onChange' + > +> = (props) => { + const { + children, + visible, + type, + height, + options, + title, + left, + value, + defaultValue, + optionKey, + format, + onClose, + onChange, + onPathChange, + ...rest + } = { + ...defaultProps, + ...props, + } + + return ( + <> + {type === 'custom' && ( + { + onClose?.() + }} + onChange={(val, params) => { + onChange?.(val, params) + }} + onPathChange={onPathChange} + {...rest} + /> + )} + + ) +} diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx new file mode 100644 index 0000000000..f437291f62 --- /dev/null +++ b/src/packages/address/elevatorRender.tsx @@ -0,0 +1,342 @@ +import React, { FunctionComponent, useState } from 'react' +import { + WebCascaderProps, + CascaderOption, + CascaderValue, + CascaderOptionKey, +} from '@/types' +import { ComponentDefaults } from '@/utils/typings' +import Elevator from '../elevator' + +// 支持热区快速定位 +// 支持电梯快速定位 +// 已选省份地区放在顶部,独立展示 + +export interface AddressProps extends WebCascaderProps { + visible: boolean // popup visible + type: string + options: CascaderOption[] + hotList: [] + value: CascaderValue + defaultValue: CascaderValue + optionKey: CascaderOptionKey + format: Record + height: string | number +} + +const defaultProps = { + ...ComponentDefaults, + visible: false, + type: 'elevator', + options: [], + optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, + format: {}, + height: '200px', +} as unknown as AddressProps + +export const ElevatorRender: FunctionComponent< + Partial & + Omit< + React.HTMLAttributes, + 'title' | 'defaultValue' | 'onChange' + > +> = (props) => { + const { + children, + visible, + type, + height, + options, + hotList, + title, + left, + value, + defaultValue, + optionKey, + format, + onClose, + onChange, + onPathChange, + ...rest + } = { + ...defaultProps, + ...props, + } + const prefixCls = 'nut-address' + const prefixEleCls = 'nut-address-elevator' + + const [addressTip, setAddressTip] = useState('选择省份/地区') + const [selectedRegion, setSelectedRegion] = useState([ + // '新疆', + // '克孜勒苏柯尔克孜自治州', + ]) + + const formatData = () => { + return [ + { + title: 'A', + list: [ + { + name: '安徽', + id: 14, + }, + ], + }, + { + title: 'B', + list: [ + { + name: '北京', + id: 1, + }, + ], + }, + { + title: 'C', + list: [ + { + name: '重庆', + id: 4, + }, + ], + }, + { + title: 'F', + list: [ + { + name: '福建', + id: 16, + }, + ], + }, + { + title: 'G', + list: [ + { + name: '贵州', + id: 24, + }, + { + name: '广东', + id: 19, + }, + { + name: '广西', + id: 20, + }, + { + name: '甘肃', + id: 28, + }, + ], + }, + { + title: 'H', + list: [ + { + name: '河北', + id: 5, + }, + { + name: '河南', + id: 7, + }, + { + name: '湖北', + id: 17, + }, + { + name: '湖南', + id: 18, + }, + { + name: '海南', + id: 23, + }, + { + name: '黑龙江', + id: 10, + }, + ], + }, + { + title: 'J', + list: [ + { + name: '江苏', + id: 12, + }, + { + name: '江西', + id: 21, + }, + { + name: '吉林', + id: 9, + }, + { + name: '辽宁', + id: 8, + }, + ], + }, + { + title: 'N', + list: [ + { + name: '内蒙古', + id: 11, + }, + { + name: '宁夏', + id: 30, + }, + ], + }, + { + title: 'Q', + list: [ + { + name: '青海', + id: 29, + }, + ], + }, + { + title: 'S', + list: [ + { + name: '山东', + id: 13, + }, + { + name: '山西', + id: 6, + }, + { + name: '上海', + id: 2, + }, + { + name: '陕西', + id: 27, + }, + { + name: '四川', + id: 22, + }, + ], + }, + { + title: 'T', + list: [ + { + name: '天津', + id: 3, + }, + ], + }, + { + title: 'X', + list: [ + { + name: '西藏', + id: 26, + }, + { + name: '新疆', + id: 31, + }, + ], + }, + { + title: 'Y', + list: [ + { + name: '云南', + id: 25, + }, + ], + }, + { + title: 'Z', + list: [ + { + name: '浙江', + id: 15, + }, + ], + }, + ] + } + + const renderHotArea = () => { + return ( + <> +
热门城市
+
+ {hotList.map((item, index) => ( +
+ {item.name} +
+ ))} +
+ + ) + } + + const renderSelectedArea = () => { + return ( +
+ {selectedRegion.map((item, index) => ( + <> +
+ {item} +
+ {selectedRegion.length - 1 > index ? ( +
-
+ ) : null} + + ))} +
+ ) + } + + const renderArea = () => { + return ( + <> +
{addressTip}
+ + {/* { + onClose?.() + }} + onChange={(val, params) => { + onChange?.(val, params) + }} + onPathChange={onPathChange} + {...rest} + /> */} + + ) + } + + return ( + <> + {selectedRegion.length ? renderSelectedArea() : renderHotArea()} + {renderArea()} + + ) +} From a32b2172aa33feb296f9aed5a56d4cc51184a797 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Thu, 10 Apr 2025 15:20:38 +0800 Subject: [PATCH 02/22] =?UTF-8?q?feat:=20=E6=9E=84=E9=80=A0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/address.tsx | 20 + src/packages/address/demos/h5/demo1.tsx | 226 +++++++--- src/packages/address/elevatorRender.tsx | 561 +++++++++++++----------- src/packages/address/utils.ts | 40 ++ 4 files changed, 523 insertions(+), 324 deletions(-) create mode 100644 src/packages/address/utils.ts diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index d308f032f1..303f40d010 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -127,6 +127,26 @@ export const InternalAddress: ForwardRefRenderFunction< onSwitch && onSwitch({ type: currentType }) } const renderElevator = () => { + return ( + { + onChange?.(val, params) + }} + /> + ) return ( { @@ -15,69 +15,165 @@ const Demo1 = () => { { id: '3', name: '天津' }, { id: '3', name: '天津' }, ]) - const [optionsDemo1] = useState([ - { - value: '浙江', - text: '浙江', - children: [ - { - value: '杭州', - text: '杭州', - disabled: true, - children: [ - { value: '西湖区', text: '西湖区', disabled: true }, - { value: '余杭区', text: '余杭区' }, - ], - }, - { - value: '温州', - text: '温州', - children: [ - { value: '鹿城区', text: '鹿城区' }, - { value: '瓯海区', text: '瓯海区' }, - ], - }, - ], - }, - { - value: '湖南', - text: '湖南', - disabled: true, - children: [ - { - value: '长沙', - text: '长沙', - disabled: true, - children: [ - { value: '西湖区', text: '西湖区' }, - { value: '余杭区', text: '余杭区' }, - ], - }, - { - value: '温州', - text: '温州', - children: [ - { value: '鹿城区', text: '鹿城区' }, - { value: '瓯海区', text: '瓯海区' }, - ], - }, - ], - }, - { - value: '福建', - text: '福建', - children: [ - { - value: '福州', - text: '福州', - children: [ - { value: '鼓楼区', text: '鼓楼区' }, - { value: '台江区', text: '台江区' }, - ], - }, - ], - }, - ]) + const [options, setOptions] = useState([]) + useEffect(() => { + setOptions([ + { + value: '安徽', + text: '安徽', + wordCode: 'A', + children: [ + { + value: '安庆市', + text: '安庆市', + wordCode: 'A', + disabled: true, + children: [ + { + value: '大观区', + text: '大观区', + disabled: true, + wordCode: 'D', + }, + { value: '怀宁县', text: '怀宁县', wordCode: 'H' }, + { value: '岳西县', text: '岳西县', wordCode: 'Y' }, + { value: '迎江区', text: '迎江区', wordCode: 'Y' }, + { value: '宜秀区', text: '宜秀区', wordCode: 'Y' }, + ], + }, + { + value: '合肥市', + text: '合肥市', + wordCode: 'H', + children: [ + { value: '合肥高新', text: '合肥高新', wordCode: 'H' }, + { value: '合肥经济', text: '合肥经济', wordCode: 'H' }, + ], + }, + { + value: '淮北市', + text: '淮北市', + wordCode: 'H', + children: [ + { value: '杜集区', text: '杜集区', wordCode: 'D' }, + { value: '烈山区', text: '杜集区', wordCode: 'L' }, + ], + }, + { + value: '淮南市', + text: '淮南市', + wordCode: 'H', + children: [{ value: '八公山区', text: '八公山区', wordCode: 'B' }], + }, + { + value: '黄山市', + text: '黄山市', + wordCode: 'H', + children: [ + { value: '黄山区', text: '黄山区', wordCode: 'H' }, + { value: '徽州区', text: '徽州区', wordCode: 'H' }, + ], + }, + ], + }, + { + value: '北京', + text: '北京', + wordCode: 'B', + children: [ + { + value: '朝阳区', + text: '朝阳区', + wordCode: 'C', + }, + { + value: '昌平区', + text: '昌平区', + wordCode: 'C', + }, + { + value: '大兴区', + text: '大兴区', + wordCode: 'D', + }, + { + value: '东城区', + text: '东城区', + wordCode: 'D', + }, + { + value: '房山区', + text: '房山区', + wordCode: 'F', + }, + { + value: '丰台区', + text: '丰台区', + wordCode: 'F', + }, + ], + }, + { + value: '重庆', + text: '重庆', + wordCode: 'C', + }, + { + value: '福建', + text: '福建', + wordCode: 'F', + }, + { + value: '贵州', + text: '贵州', + wordCode: 'G', + }, + { + value: '广东', + text: '广东', + wordCode: 'G', + }, + { + value: '广西', + text: '广西', + wordCode: 'G', + }, + { + value: '甘肃', + text: '甘肃', + wordCode: 'G', + }, + { + value: '河北', + text: '河北', + wordCode: 'H', + disabled: true, + }, + { + value: '河南', + text: '河南', + wordCode: 'H', + disabled: true, + }, + { + value: '湖南', + text: '湖南', + wordCode: 'H', + disabled: true, + }, + { + value: '湖北', + text: '湖北', + wordCode: 'H', + disabled: true, + }, + { + value: '浙江', + text: '浙江', + wordCode: 'Z', + }, + ]) + }, []) const [visible, setVisible] = useState(false) return ( @@ -90,7 +186,7 @@ const Demo1 = () => {
{ setText(value.join('')) diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index f437291f62..63f703a80b 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -1,22 +1,43 @@ -import React, { FunctionComponent, useState } from 'react' +import React, { + FunctionComponent, + useEffect, + useMemo, + useRef, + useState, +} from 'react' + +import Popup from '@/packages/popup' +import Elevator from '../elevator' +import { + normalizeListOptions, + normalizeOptions, +} from '@/packages/cascader/utils' +import { transformData } from './utils' import { - WebCascaderProps, CascaderOption, + WebCascaderProps, CascaderValue, CascaderOptionKey, } from '@/types' import { ComponentDefaults } from '@/utils/typings' -import Elevator from '../elevator' +import { mergeProps } from '@/utils/merge-props' +import { usePropsValue } from '@/hooks/use-props-value' +import { isEmpty } from '@/utils/is-empty' +import { useConfig } from '@/packages/configprovider' // 支持热区快速定位 // 支持电梯快速定位 // 已选省份地区放在顶部,独立展示 - +type AreaInfo = { + name: string + id: string | number + children: any +} export interface AddressProps extends WebCascaderProps { visible: boolean // popup visible type: string options: CascaderOption[] - hotList: [] + hotList: AreaInfo[] value: CascaderValue defaultValue: CascaderValue optionKey: CascaderOptionKey @@ -32,6 +53,16 @@ const defaultProps = { optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, format: {}, height: '200px', + activeColor: '', + activeIcon: 'checklist', + popup: true, + closeable: false, + closeIconPosition: 'top-right', + closeIcon: 'close', + lazy: false, + onClose: () => {}, + onChange: () => {}, + onPathChange: () => {}, } as unknown as AddressProps export const ElevatorRender: FunctionComponent< @@ -43,240 +74,213 @@ export const ElevatorRender: FunctionComponent< > = (props) => { const { children, - visible, type, height, - options, hotList, title, left, - value, defaultValue, optionKey, format, onClose, onChange, onPathChange, + activeColor, + activeIcon, + popup, + popupProps = {}, + visible: outerVisible, + options: outerOptions, + value: outerValue, + defaultValue: outerDefaultValue, + closeable, + closeIconPosition, + closeIcon, + lazy, + onLoad, ...rest - } = { - ...defaultProps, - ...props, - } - const prefixCls = 'nut-address' + } = mergeProps(defaultProps, props) + const { locale } = useConfig() + + const classPrefix = 'nut-address' const prefixEleCls = 'nut-address-elevator' + const [tabActiveIndex, setTabActiveIndex] = useState(0) + const [innerOptions, setInnerOptions] = useState(outerOptions) + // const innerOptions = getRefValue(optionsRef) + const [loading, setLoading] = useState<{ [key: string]: any }>({}) + + const [value, setValue] = usePropsValue({ + value: outerValue, + defaultValue: outerDefaultValue, + finalValue: [], + onChange: (value) => { + props.onChange?.(value, pathNodes.current) + props.onPathChange?.(value, pathNodes.current) + }, + }) + + const [innerValue, setInnerValue] = useState(value) + const [addressTip, setAddressTip] = useState('选择省份/地区') - const [selectedRegion, setSelectedRegion] = useState([ - // '新疆', - // '克孜勒苏柯尔克孜自治州', - ]) + const [selectedRegion, setSelectedRegion] = useState([]) + + const options = useMemo(() => { + console.log('inneroptions changes', innerOptions) + let currOptions = innerOptions + if (!isEmpty(format)) { + currOptions = normalizeListOptions(innerOptions, format) + } else if (!isEmpty(optionKey)) { + currOptions = normalizeOptions(innerOptions, optionKey) || [] + } + return transformData(currOptions) + }, [innerOptions, optionKey, format, innerValue]) + + const [elevatorOptions, setElevatorOptions] = useState([]) - const formatData = () => { - return [ - { - title: 'A', - list: [ - { - name: '安徽', - id: 14, - }, - ], - }, - { - title: 'B', - list: [ - { - name: '北京', - id: 1, - }, - ], - }, - { - title: 'C', - list: [ - { - name: '重庆', - id: 4, - }, - ], - }, - { - title: 'F', - list: [ - { - name: '福建', - id: 16, - }, - ], - }, - { - title: 'G', - list: [ - { - name: '贵州', - id: 24, - }, - { - name: '广东', - id: 19, - }, - { - name: '广西', - id: 20, - }, - { - name: '甘肃', - id: 28, - }, - ], - }, - { - title: 'H', - list: [ - { - name: '河北', - id: 5, - }, - { - name: '河南', - id: 7, - }, - { - name: '湖北', - id: 17, - }, - { - name: '湖南', - id: 18, - }, - { - name: '海南', - id: 23, - }, - { - name: '黑龙江', - id: 10, - }, - ], - }, - { - title: 'J', - list: [ - { - name: '江苏', - id: 12, - }, - { - name: '江西', - id: 21, - }, - { - name: '吉林', - id: 9, - }, - { - name: '辽宁', - id: 8, - }, - ], - }, - { - title: 'N', - list: [ - { - name: '内蒙古', - id: 11, - }, - { - name: '宁夏', - id: 30, - }, - ], - }, - { - title: 'Q', - list: [ - { - name: '青海', - id: 29, - }, - ], - }, - { - title: 'S', - list: [ - { - name: '山东', - id: 13, - }, - { - name: '山西', - id: 6, - }, - { - name: '上海', - id: 2, - }, - { - name: '陕西', - id: 27, - }, - { - name: '四川', - id: 22, - }, - ], - }, - { - title: 'T', - list: [ - { - name: '天津', - id: 3, - }, - ], - }, - { - title: 'X', - list: [ - { - name: '西藏', - id: 26, - }, - { - name: '新疆', - id: 31, - }, - ], - }, - { - title: 'Y', - list: [ - { - name: '云南', - id: 25, - }, - ], - }, - { - title: 'Z', - list: [ - { - name: '浙江', - id: 15, - }, - ], - }, - ] + useEffect(() => { + setElevatorOptions(options) + }, [options]) + + const pathNodes = useRef([]) + + const levels: any[] = useMemo(() => { + const next = [] + let end = false + let currentOptions = options + for (const [index, val] of innerValue.entries()) { + const opt = currentOptions?.find((o: CascaderOption) => o.value === val) + next.push({ + selected: val, + pane: currentOptions, + }) + pathNodes.current[index] = opt + if (opt?.children) { + currentOptions = opt.children + } else { + end = true + break + } + } + if (!end) { + next.push({ + selected: null, + pane: currentOptions, + }) + } + return next + }, [innerValue, options, innerOptions]) + + const [visible, setVisible] = usePropsValue({ + value: outerVisible, + defaultValue: undefined, + onChange: (value) => { + if (value === false) { + props.onClose?.() + } + }, + }) + // const actions: CascaderActions = { + // open: () => { + // setVisible(true) + // }, + // close: () => { + // setVisible(false) + // }, + // } + // useImperativeHandle(ref, () => actions) + + useEffect(() => { + if (!visible) { + setInnerValue(value) + } + }, [visible, value]) + + useEffect(() => { + setInnerOptions(outerOptions) + }, [outerOptions]) + + useEffect(() => { + setTabActiveIndex(levels.length - 1) + }, [innerValue, innerOptions, outerOptions]) + + useEffect(() => { + const max = levels.length - 1 + if (tabActiveIndex > max) { + setTabActiveIndex(max) + } + }, [tabActiveIndex, levels, innerOptions, outerOptions]) + + useEffect(() => { + const load = async () => { + const parent = { children: [] } + try { + await innerValue.reduce(async (promise: Promise, val, key) => { + const pane = await onLoad({ value: val }, key) + const parent = await promise + parent.children = pane + if (key === innerValue.length - 1) { + return Promise.resolve(parent) + } + if (pane) { + const node = pane.find((p) => p.value === val) + return Promise.resolve(node) + } + }, Promise.resolve(parent)) + + // 如果需要处理最终结果,可以在这里使用 last + setInnerOptions(parent.children) + } catch (error) { + console.error('Error loading data:', error) + } + } + + if (lazy) load() + }, [lazy]) + + const renderTab = () => { + console.log('selectedRegion', levels, selectedRegion) + return ( +
+ {selectedRegion.map((item, index) => ( + <> +
{ + onTabChange(item) + // props.onTabsChange?.(Number(index)) + // setTabActiveIndex(Number(index)) + }} + > + {item.name} + {/* {levels.map((pane, index) => ( + +
+ {renderCascaderItem(pane, index)} +
+
+ ))} */} +
+ {selectedRegion.length - 1 > index ? ( +
-
+ ) : null} + + ))} +
+ ) } const renderHotArea = () => { return ( <> -
热门城市
-
+
热门城市
+
{hotList.map((item, index) => ( -
+
{item.name}
))} @@ -285,58 +289,97 @@ export const ElevatorRender: FunctionComponent< ) } - const renderSelectedArea = () => { - return ( -
- {selectedRegion.map((item, index) => ( - <> -
- {item} -
- {selectedRegion.length - 1 > index ? ( -
-
- ) : null} - - ))} -
- ) + const onTabChange = (item: any) => { + console.log('item', item, item.parent) + } + + const onElevatorItemClick = (key: string, item: AreaInfo) => { + console.log('onitem click', item) + setSelectedRegion((pre) => [...pre, item]) + if (item.children?.length) { + setElevatorOptions(item.children) + } else { + console.log('close popup') + } } const renderArea = () => { return ( <> -
{addressTip}
+
{addressTip}
+ onElevatorItemClick(key, item) + } + height="300px" /> - {/* { - onClose?.() - }} - onChange={(val, params) => { - onChange?.(val, params) - }} - onPathChange={onPathChange} - {...rest} - /> */} ) } - return ( - <> - {selectedRegion.length ? renderSelectedArea() : renderHotArea()} - {renderArea()} - + const chooseItem = async (pane: CascaderOption, levelIndex: number) => { + if (pane.disabled) return + console.log('chooseItem', pane, levelIndex) + const nextValue = innerValue.slice(0, levelIndex) + const nextPathNodes = pathNodes.current.slice(0, levelIndex) + if (pane.value) { + setLoading(!!onLoad && { [levelIndex]: pane.value }) + nextValue[levelIndex] = pane.value + nextPathNodes[levelIndex] = pane + pathNodes.current = nextPathNodes + props?.onPathChange?.(nextValue, pathNodes.current) + } + if (onLoad) { + // 叶子节点不操作 + if (!pane.leaf) { + const asyncOptions = await onLoad(pane, levelIndex) + // 修改 options 触发渲染逻辑 + if (asyncOptions) pane.children = asyncOptions + } else { + setVisible(false) + setValue(nextValue) + } + } + if (!pane.children && !onLoad) { + setVisible(false) + setValue(nextValue) + } + setInnerValue(nextValue) + setLoading({}) + } + + const renderElevatorList = () => { + return ( + <> + {selectedRegion.length ? renderTab() : null} + {renderHotArea()} + {renderArea()} + + ) + } + + return popup ? ( + setVisible(false)} + onCloseIconClick={() => setVisible(false)} + > + {renderElevatorList()} + + ) : ( + renderElevatorList() ) } + +ElevatorRender.displayName = 'NutElevatorRender' diff --git a/src/packages/address/utils.ts b/src/packages/address/utils.ts new file mode 100644 index 0000000000..b15b2030ee --- /dev/null +++ b/src/packages/address/utils.ts @@ -0,0 +1,40 @@ +const generateId = (name: string) => { + // 简单实现:根据 name 生成一个随机 ID + return name.charCodeAt(0) + name.charCodeAt(1) // 使用字符的 Unicode 值作为 ID +} + +export const transformData = (data: any) => { + const groupByWordCode = (data: any) => { + return data?.reduce((acc: any, item: any) => { + const { wordCode } = item + if (!acc[wordCode]) { + acc[wordCode] = [] + } + acc[wordCode].push({ + name: item.value, + wordCode: item.wordCode, + id: generateId(item.value), + children: (item.children && groupByWordCode(item.children)) || {}, + }) + + return acc + }, {}) + } + + const extractTitles = (obj: any) => { + return Object.keys(obj).map((key) => ({ + title: key, + list: obj[key].map((item: any) => { + console.log('item', item) + if (item.children) { + item.children = extractTitles(item.children) + } + return item + }), + })) + } + + const middleData = groupByWordCode(data) + const resultData = extractTitles(middleData) + return resultData +} From 91b1e705ba304a034799da8cc0f7f31cbfeb2598 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Fri, 11 Apr 2025 13:40:32 +0800 Subject: [PATCH 03/22] =?UTF-8?q?feat:=20tabs=20=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/elevator.scss | 6 + src/packages/address/elevatorRender.tsx | 147 ++++++++++++------------ src/packages/address/utils.ts | 4 +- 3 files changed, 79 insertions(+), 78 deletions(-) diff --git a/src/packages/address/elevator.scss b/src/packages/address/elevator.scss index c091f34bb5..8e38695507 100644 --- a/src/packages/address/elevator.scss +++ b/src/packages/address/elevator.scss @@ -53,6 +53,12 @@ padding: 0 12px; border-radius: 4px; background-color: $color-background-sunken; + + &.active { + border: 1px solid $color-primary; + background-color: $color-primary-light-pressed; + color: $color-primary; + } } &-border { margin: 0 2px; diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index 63f703a80b..5e16dfd184 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -107,7 +107,6 @@ export const ElevatorRender: FunctionComponent< const [tabActiveIndex, setTabActiveIndex] = useState(0) const [innerOptions, setInnerOptions] = useState(outerOptions) - // const innerOptions = getRefValue(optionsRef) const [loading, setLoading] = useState<{ [key: string]: any }>({}) const [value, setValue] = usePropsValue({ @@ -123,10 +122,9 @@ export const ElevatorRender: FunctionComponent< const [innerValue, setInnerValue] = useState(value) const [addressTip, setAddressTip] = useState('选择省份/地区') - const [selectedRegion, setSelectedRegion] = useState([]) + // 初始化数据,只格式化一次;动态数据todo const options = useMemo(() => { - console.log('inneroptions changes', innerOptions) let currOptions = innerOptions if (!isEmpty(format)) { currOptions = normalizeListOptions(innerOptions, format) @@ -134,7 +132,7 @@ export const ElevatorRender: FunctionComponent< currOptions = normalizeOptions(innerOptions, optionKey) || [] } return transformData(currOptions) - }, [innerOptions, optionKey, format, innerValue]) + }, [innerOptions, optionKey, format]) const [elevatorOptions, setElevatorOptions] = useState([]) @@ -148,28 +146,41 @@ export const ElevatorRender: FunctionComponent< const next = [] let end = false let currentOptions = options + console.log('levels', innerValue) for (const [index, val] of innerValue.entries()) { - const opt = currentOptions?.find((o: CascaderOption) => o.value === val) + const opt = currentOptions?.flatMap((o: any) => { + // console.log( + // 'currentOptions', + // o, + // val, + // o.list.find((item: any) => item.name === val) + // ) + const foundItem = o.list.find((item: any) => item.name === val) + return foundItem + })[0] + next.push({ - selected: val, - pane: currentOptions, + name: val, + children: currentOptions, + levelIndex: index, + current: index === tabActiveIndex, }) - pathNodes.current[index] = opt + // pathNodes.current[index] = opt if (opt?.children) { currentOptions = opt.children } else { end = true - break + // break } } if (!end) { next.push({ - selected: null, - pane: currentOptions, + name: null, + children: currentOptions, }) } return next - }, [innerValue, options, innerOptions]) + }, [innerValue, options, tabActiveIndex]) const [visible, setVisible] = usePropsValue({ value: outerVisible, @@ -202,14 +213,7 @@ export const ElevatorRender: FunctionComponent< useEffect(() => { setTabActiveIndex(levels.length - 1) - }, [innerValue, innerOptions, outerOptions]) - - useEffect(() => { - const max = levels.length - 1 - if (tabActiveIndex > max) { - setTabActiveIndex(max) - } - }, [tabActiveIndex, levels, innerOptions, outerOptions]) + }, [innerValue]) useEffect(() => { const load = async () => { @@ -239,33 +243,25 @@ export const ElevatorRender: FunctionComponent< }, [lazy]) const renderTab = () => { - console.log('selectedRegion', levels, selectedRegion) + console.log('tabs', levels) return (
- {selectedRegion.map((item, index) => ( + {levels.map((item, index) => ( <>
{ - onTabChange(item) - // props.onTabsChange?.(Number(index)) - // setTabActiveIndex(Number(index)) + onClick={() => { + console.log('index', Number(index), item.children) + props.onTabsChange?.(Number(index)) + setTabActiveIndex(Number(index)) + setLevelIndex(index) + setElevatorOptions(item.children) }} > {item.name} - {/* {levels.map((pane, index) => ( - -
- {renderCascaderItem(pane, index)} -
-
- ))} */}
- {selectedRegion.length - 1 > index ? ( + {levels.length - 1 > index ? (
-
) : null} @@ -289,20 +285,6 @@ export const ElevatorRender: FunctionComponent< ) } - const onTabChange = (item: any) => { - console.log('item', item, item.parent) - } - - const onElevatorItemClick = (key: string, item: AreaInfo) => { - console.log('onitem click', item) - setSelectedRegion((pre) => [...pre, item]) - if (item.children?.length) { - setElevatorOptions(item.children) - } else { - console.log('close popup') - } - } - const renderArea = () => { return ( <> @@ -311,7 +293,7 @@ export const ElevatorRender: FunctionComponent< className={`${classPrefix}-elevator`} list={elevatorOptions} onItemClick={(key: string, item: any) => - onElevatorItemClick(key, item) + onElevatorItemClick(item, levelIndex) } height="300px" /> @@ -319,33 +301,46 @@ export const ElevatorRender: FunctionComponent< ) } - const chooseItem = async (pane: CascaderOption, levelIndex: number) => { - if (pane.disabled) return - console.log('chooseItem', pane, levelIndex) - const nextValue = innerValue.slice(0, levelIndex) - const nextPathNodes = pathNodes.current.slice(0, levelIndex) - if (pane.value) { - setLoading(!!onLoad && { [levelIndex]: pane.value }) - nextValue[levelIndex] = pane.value - nextPathNodes[levelIndex] = pane - pathNodes.current = nextPathNodes - props?.onPathChange?.(nextValue, pathNodes.current) + const [levelIndex, setLevelIndex] = useState(0) + + const onElevatorItemClick = (elevatorItem: AreaInfo, levelIndex: number) => { + console.log('onitem click', elevatorItem, innerValue, levelIndex) + if (elevatorItem?.disabled) return + const distIndex = levelIndex + 1 + setLevelIndex(distIndex) + + if (elevatorItem.children?.length) { + setElevatorOptions(elevatorItem.children) + } else { + console.log('close popup') } - if (onLoad) { - // 叶子节点不操作 - if (!pane.leaf) { - const asyncOptions = await onLoad(pane, levelIndex) - // 修改 options 触发渲染逻辑 - if (asyncOptions) pane.children = asyncOptions - } else { - setVisible(false) - setValue(nextValue) - } + + const nextValue = innerValue.slice(0, levelIndex) + console.log('nextvalue', nextValue) + // const nextPathNodes = pathNodes.current.slice(0, levelIndex) + if (elevatorItem.name) { + setLoading(!!onLoad && { [levelIndex]: elevatorItem.name }) + nextValue[levelIndex] = elevatorItem.name + // nextPathNodes[levelIndex] = elevatorItem + // pathNodes.current = nextPathNodes + // props?.onPathChange?.(nextValue, pathNodes.current) } - if (!pane.children && !onLoad) { + // if (onLoad) { + // // 叶子节点不操作 + // if (!elevatorItem.leaf) { + // const asyncOptions = await onLoad(elevatorItem, levelIndex) + // // 修改 options 触发渲染逻辑 + // if (asyncOptions) elevatorItem.children = asyncOptions + // } else { + // setVisible(false) + // setValue(nextValue) + // } + // } + if (!elevatorItem.children && !onLoad) { setVisible(false) setValue(nextValue) } + console.log('330 ', nextValue) setInnerValue(nextValue) setLoading({}) } @@ -353,7 +348,7 @@ export const ElevatorRender: FunctionComponent< const renderElevatorList = () => { return ( <> - {selectedRegion.length ? renderTab() : null} + {levels.length ? renderTab() : null} {renderHotArea()} {renderArea()} diff --git a/src/packages/address/utils.ts b/src/packages/address/utils.ts index b15b2030ee..383f49807b 100644 --- a/src/packages/address/utils.ts +++ b/src/packages/address/utils.ts @@ -14,7 +14,7 @@ export const transformData = (data: any) => { name: item.value, wordCode: item.wordCode, id: generateId(item.value), - children: (item.children && groupByWordCode(item.children)) || {}, + children: (item.children && groupByWordCode(item.children)) || null, }) return acc @@ -25,7 +25,7 @@ export const transformData = (data: any) => { return Object.keys(obj).map((key) => ({ title: key, list: obj[key].map((item: any) => { - console.log('item', item) + // console.log('item', item) if (item.children) { item.children = extractTitles(item.children) } From 3a4ee6d6df9364a7696db772f92c05cdbf7a0d65 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Thu, 17 Apr 2025 13:51:50 +0800 Subject: [PATCH 04/22] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8D=E6=9C=80?= =?UTF-8?q?=E5=90=8E=E4=B8=80=E4=B8=AA=E5=85=83=E7=B4=A0=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E4=B8=80=E7=9B=B4=E8=A2=AB=E6=B7=BB=E5=8A=A0=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/elevatorRender.tsx | 149 +++++++----------------- 1 file changed, 44 insertions(+), 105 deletions(-) diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index 5e16dfd184..9729c00b34 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -103,7 +103,6 @@ export const ElevatorRender: FunctionComponent< const { locale } = useConfig() const classPrefix = 'nut-address' - const prefixEleCls = 'nut-address-elevator' const [tabActiveIndex, setTabActiveIndex] = useState(0) const [innerOptions, setInnerOptions] = useState(outerOptions) @@ -120,8 +119,8 @@ export const ElevatorRender: FunctionComponent< }) const [innerValue, setInnerValue] = useState(value) - const [addressTip, setAddressTip] = useState('选择省份/地区') + const [levelIndex, setLevelIndex] = useState(0) // 初始化数据,只格式化一次;动态数据todo const options = useMemo(() => { @@ -146,15 +145,8 @@ export const ElevatorRender: FunctionComponent< const next = [] let end = false let currentOptions = options - console.log('levels', innerValue) for (const [index, val] of innerValue.entries()) { const opt = currentOptions?.flatMap((o: any) => { - // console.log( - // 'currentOptions', - // o, - // val, - // o.list.find((item: any) => item.name === val) - // ) const foundItem = o.list.find((item: any) => item.name === val) return foundItem })[0] @@ -191,15 +183,6 @@ export const ElevatorRender: FunctionComponent< } }, }) - // const actions: CascaderActions = { - // open: () => { - // setVisible(true) - // }, - // close: () => { - // setVisible(false) - // }, - // } - // useImperativeHandle(ref, () => actions) useEffect(() => { if (!visible) { @@ -213,55 +196,30 @@ export const ElevatorRender: FunctionComponent< useEffect(() => { setTabActiveIndex(levels.length - 1) + setAddressTip(innerValue.length ? '请选择' : '选择省份/地区') }, [innerValue]) - useEffect(() => { - const load = async () => { - const parent = { children: [] } - try { - await innerValue.reduce(async (promise: Promise, val, key) => { - const pane = await onLoad({ value: val }, key) - const parent = await promise - parent.children = pane - if (key === innerValue.length - 1) { - return Promise.resolve(parent) - } - if (pane) { - const node = pane.find((p) => p.value === val) - return Promise.resolve(node) - } - }, Promise.resolve(parent)) - - // 如果需要处理最终结果,可以在这里使用 last - setInnerOptions(parent.children) - } catch (error) { - console.error('Error loading data:', error) - } - } - - if (lazy) load() - }, [lazy]) - const renderTab = () => { - console.log('tabs', levels) + if (!levels[0].name) return return (
{levels.map((item, index) => ( <> -
{ - console.log('index', Number(index), item.children) - props.onTabsChange?.(Number(index)) - setTabActiveIndex(Number(index)) - setLevelIndex(index) - setElevatorOptions(item.children) - }} - > - {item.name} -
- {levels.length - 1 > index ? ( + {item.name ? ( +
{ + props.onTabsChange?.(Number(index)) + setTabActiveIndex(Number(index)) + setLevelIndex(index) + setElevatorOptions(item.children) + }} + > + {item.name} +
+ ) : null} + {levels[index + 1]?.name ? (
-
) : null} @@ -270,7 +228,32 @@ export const ElevatorRender: FunctionComponent< ) } + const onElevatorItemClick = (elevatorItem: AreaInfo, levelIndex: number) => { + if (elevatorItem?.disabled) return + if (elevatorItem.children?.length) { + setElevatorOptions(elevatorItem.children) + const distIndex = levelIndex + 1 + setLevelIndex(distIndex) + } else { + console.log('close popup') + } + + const nextValue = innerValue.slice(0, levelIndex) + if (elevatorItem.name) { + setLoading(!!onLoad && { [levelIndex]: elevatorItem.name }) + nextValue[levelIndex] = elevatorItem.name + } + if (!elevatorItem.children && !onLoad) { + setVisible(false) + setValue(nextValue) + } + setInnerValue(nextValue) + setLoading({}) + } + const renderHotArea = () => { + // 选中省份/直辖市时,会展示热门城市 + if (levels.length && tabActiveIndex !== 0) return return ( <>
热门城市
@@ -301,54 +284,10 @@ export const ElevatorRender: FunctionComponent< ) } - const [levelIndex, setLevelIndex] = useState(0) - - const onElevatorItemClick = (elevatorItem: AreaInfo, levelIndex: number) => { - console.log('onitem click', elevatorItem, innerValue, levelIndex) - if (elevatorItem?.disabled) return - const distIndex = levelIndex + 1 - setLevelIndex(distIndex) - - if (elevatorItem.children?.length) { - setElevatorOptions(elevatorItem.children) - } else { - console.log('close popup') - } - - const nextValue = innerValue.slice(0, levelIndex) - console.log('nextvalue', nextValue) - // const nextPathNodes = pathNodes.current.slice(0, levelIndex) - if (elevatorItem.name) { - setLoading(!!onLoad && { [levelIndex]: elevatorItem.name }) - nextValue[levelIndex] = elevatorItem.name - // nextPathNodes[levelIndex] = elevatorItem - // pathNodes.current = nextPathNodes - // props?.onPathChange?.(nextValue, pathNodes.current) - } - // if (onLoad) { - // // 叶子节点不操作 - // if (!elevatorItem.leaf) { - // const asyncOptions = await onLoad(elevatorItem, levelIndex) - // // 修改 options 触发渲染逻辑 - // if (asyncOptions) elevatorItem.children = asyncOptions - // } else { - // setVisible(false) - // setValue(nextValue) - // } - // } - if (!elevatorItem.children && !onLoad) { - setVisible(false) - setValue(nextValue) - } - console.log('330 ', nextValue) - setInnerValue(nextValue) - setLoading({}) - } - const renderElevatorList = () => { return ( <> - {levels.length ? renderTab() : null} + {renderTab()} {renderHotArea()} {renderArea()} From 0fdc60366b4f5e2740272387f907adc998b719c5 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Thu, 17 Apr 2025 15:37:16 +0800 Subject: [PATCH 05/22] =?UTF-8?q?feat:=20taro=20=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/address.taro.tsx | 127 +++++--- src/packages/address/address.tsx | 66 +--- src/packages/address/demo.taro.tsx | 6 + src/packages/address/demo.tsx | 6 + src/packages/address/demos/h5/demo1.tsx | 243 ++++----------- src/packages/address/demos/h5/demo11.tsx | 200 ++++++++++++ src/packages/address/demos/taro/demo11.tsx | 200 ++++++++++++ src/packages/address/elevatorRender.taro.tsx | 303 ++++++++++++++++--- src/packages/address/utils.ts | 2 +- 9 files changed, 843 insertions(+), 310 deletions(-) create mode 100644 src/packages/address/demos/h5/demo11.tsx create mode 100644 src/packages/address/demos/taro/demo11.tsx diff --git a/src/packages/address/address.taro.tsx b/src/packages/address/address.taro.tsx index fef8a23fea..64e77cc901 100644 --- a/src/packages/address/address.taro.tsx +++ b/src/packages/address/address.taro.tsx @@ -8,6 +8,7 @@ import { View } from '@tarojs/components' import { ArrowLeft } from '@nutui/icons-react-taro' import Popup from '@/packages/popup/index.taro' import { ExistRender } from './existRender.taro' +import { ElevatorRender } from './elevatorRender.taro' import { CustomRender } from './customRender.taro' import { useConfig } from '@/packages/configprovider/index.taro' import { ComponentDefaults } from '@/utils/typings' @@ -28,6 +29,7 @@ const defaultProps = { format: {}, custom: false, existList: [], + hotList: [], height: '200px', defaultIcon: null, selectIcon: null, @@ -63,6 +65,7 @@ const InternalAddress: ForwardRefRenderFunction< defaultIcon, closeIcon, backIcon, + hotList, onChange, onExistSelect, onClose, @@ -125,55 +128,85 @@ const InternalAddress: ForwardRefRenderFunction< } onSwitch && onSwitch({ type: currentType }) } + const renderElevator = () => { + return ( + { + onChange?.(val, params) + }} + /> + ) + } + const renderCascator = () => { + return ( + { + onChange?.(val, params) + }} + /> + ) + } + const renderExist = () => { + return ( + + + { + // 不需要 close,选中切换即关闭弹框。可手动关闭弹框,只关闭弹框不处理逻辑。 + + } + + + ) + } return ( <> - {currentType === 'custom' || currentType === 'custom2' ? ( - { - onChange?.(val, params) - }} - /> - ) : ( - - - { - // 不需要 close,选中切换即关闭弹框。可手动关闭弹框,只关闭弹框不处理逻辑。 - - } - - - )} + {currentType === 'elevator' ? renderElevator() : null} + {currentType === 'custom' ? renderCascator() : null} + {currentType === 'exist' ? renderExist() : null} ) } diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index 303f40d010..a5eed44238 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -22,7 +22,7 @@ import { usePropsValue } from '@/hooks/use-props-value' const defaultProps = { ...ComponentDefaults, defaultValue: [], - type: 'elevator', + type: 'custom', options: [], optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, format: {}, @@ -99,18 +99,19 @@ export const InternalAddress: ForwardRefRenderFunction< } const renderLeftOnCustomSwitch = () => { - if (custom) { - return ( -
- {React.isValidElement(backIcon) ? ( - backIcon - ) : ( - - )} -
- ) - } - return null + return ( + <> + {custom && ( +
+ {React.isValidElement(backIcon) ? ( + backIcon + ) : ( + + )} +
+ )} + + ) } const selectedExistItem = (data: AddressList) => { @@ -147,45 +148,6 @@ export const InternalAddress: ForwardRefRenderFunction< }} /> ) - return ( - -
- { - // 不需要 close,选中切换即关闭弹框。可手动关闭弹框,只关闭弹框不处理逻辑。 - { - onChange?.(val, params) - }} - /> - } -
-
- ) } const renderCascator = () => { return ( diff --git a/src/packages/address/demo.taro.tsx b/src/packages/address/demo.taro.tsx index 0e95965cbb..d7abd348ad 100644 --- a/src/packages/address/demo.taro.tsx +++ b/src/packages/address/demo.taro.tsx @@ -9,10 +9,12 @@ import Demo3 from './demos/taro/demo3' import Demo4 from './demos/taro/demo4' import Demo5 from './demos/taro/demo5' import Demo6 from './demos/taro/demo6' +import Demo11 from './demos/taro/demo11' const AddressDemo = () => { const [translated] = useTranslate({ 'zh-CN': { + elevator: '电梯地址', customAddress: '选择自定义地址', selectCity: '选中省市区', existList: '选择已有地址', @@ -21,6 +23,7 @@ const AddressDemo = () => { uncontrolled: '非受控方式', }, 'zh-TW': { + elevator: '电梯地址', customAddress: '選擇自定義地址', selectCity: '選中省市區', existList: '選擇已有地址', @@ -29,6 +32,7 @@ const AddressDemo = () => { uncontrolled: '非受控方式', }, 'en-US': { + elevator: 'Elevator Address', customAddress: 'Choose Custom Address', selectCity: 'Choose City', existList: 'Choose Exist Address', @@ -42,6 +46,8 @@ const AddressDemo = () => { <>
+ {translated.elevator} + {translated.customAddress} {translated.selectCity} diff --git a/src/packages/address/demo.tsx b/src/packages/address/demo.tsx index 79f6745e77..57209eb510 100644 --- a/src/packages/address/demo.tsx +++ b/src/packages/address/demo.tsx @@ -6,10 +6,12 @@ import Demo3 from './demos/h5/demo3' import Demo4 from './demos/h5/demo4' import Demo5 from './demos/h5/demo5' import Demo6 from './demos/h5/demo6' +import Demo11 from './demos/h5/demo11' const AddressDemo = () => { const [translated] = useTranslate({ 'zh-CN': { + elevator: '电梯地址', customAddress: '选择自定义地址', selectCity: '选中省市区', existList: '选择已有地址', @@ -18,6 +20,7 @@ const AddressDemo = () => { uncontrolled: '非受控方式', }, 'zh-TW': { + elevator: '电梯地址', customAddress: '選擇自定義地址', selectCity: '選中省市區', existList: '選擇已有地址', @@ -26,6 +29,7 @@ const AddressDemo = () => { uncontrolled: '非受控方式', }, 'en-US': { + elevator: 'Elevator Address', customAddress: 'Choose Custom Address', selectCity: 'Choose City', existList: 'Choose Exist Address', @@ -38,6 +42,8 @@ const AddressDemo = () => { return ( <>
+

{translated.elevator}

+

{translated.customAddress}

{translated.selectCity}

diff --git a/src/packages/address/demos/h5/demo1.tsx b/src/packages/address/demos/h5/demo1.tsx index f6b4d7437c..b646b2c500 100644 --- a/src/packages/address/demos/h5/demo1.tsx +++ b/src/packages/address/demos/h5/demo1.tsx @@ -1,194 +1,85 @@ -import React, { useEffect, useState } from 'react' +import React, { useState } from 'react' import { Address, Cell } from '@nutui/nutui-react' const Demo1 = () => { - const [text, setText] = useState('选择地址') - const [hotList, setHotList] = useState([ - { id: '1', name: '北京' }, - { id: '2', name: '上海' }, - { id: '1601', name: '广州' }, - { id: '1607', name: '深圳' }, - { id: '1213', name: '杭州' }, - { id: '904', name: '南京' }, - { id: '988', name: '苏州' }, - { id: '3', name: '天津' }, - { id: '3', name: '天津' }, - { id: '3', name: '天津' }, + const [text, setText] = useState('请选择地址') + const [optionsDemo1] = useState([ + { + value: '浙江', + text: '浙江', + children: [ + { + value: '杭州', + text: '杭州', + disabled: true, + children: [ + { value: '西湖区', text: '西湖区', disabled: true }, + { value: '余杭区', text: '余杭区' }, + ], + }, + { + value: '温州', + text: '温州', + children: [ + { value: '鹿城区', text: '鹿城区' }, + { value: '瓯海区', text: '瓯海区' }, + ], + }, + ], + }, + { + value: '湖南', + text: '湖南', + disabled: true, + children: [ + { + value: '长沙', + text: '长沙', + disabled: true, + children: [ + { value: '西湖区', text: '西湖区' }, + { value: '余杭区', text: '余杭区' }, + ], + }, + { + value: '温州', + text: '温州', + children: [ + { value: '鹿城区', text: '鹿城区' }, + { value: '瓯海区', text: '瓯海区' }, + ], + }, + ], + }, + { + value: '福建', + text: '福建', + children: [ + { + value: '福州', + text: '福州', + children: [ + { value: '鼓楼区', text: '鼓楼区' }, + { value: '台江区', text: '台江区' }, + ], + }, + ], + }, ]) - const [options, setOptions] = useState([]) - useEffect(() => { - setOptions([ - { - value: '安徽', - text: '安徽', - wordCode: 'A', - children: [ - { - value: '安庆市', - text: '安庆市', - wordCode: 'A', - disabled: true, - children: [ - { - value: '大观区', - text: '大观区', - disabled: true, - wordCode: 'D', - }, - { value: '怀宁县', text: '怀宁县', wordCode: 'H' }, - { value: '岳西县', text: '岳西县', wordCode: 'Y' }, - { value: '迎江区', text: '迎江区', wordCode: 'Y' }, - { value: '宜秀区', text: '宜秀区', wordCode: 'Y' }, - ], - }, - { - value: '合肥市', - text: '合肥市', - wordCode: 'H', - children: [ - { value: '合肥高新', text: '合肥高新', wordCode: 'H' }, - { value: '合肥经济', text: '合肥经济', wordCode: 'H' }, - ], - }, - { - value: '淮北市', - text: '淮北市', - wordCode: 'H', - children: [ - { value: '杜集区', text: '杜集区', wordCode: 'D' }, - { value: '烈山区', text: '杜集区', wordCode: 'L' }, - ], - }, - { - value: '淮南市', - text: '淮南市', - wordCode: 'H', - children: [{ value: '八公山区', text: '八公山区', wordCode: 'B' }], - }, - { - value: '黄山市', - text: '黄山市', - wordCode: 'H', - children: [ - { value: '黄山区', text: '黄山区', wordCode: 'H' }, - { value: '徽州区', text: '徽州区', wordCode: 'H' }, - ], - }, - ], - }, - { - value: '北京', - text: '北京', - wordCode: 'B', - children: [ - { - value: '朝阳区', - text: '朝阳区', - wordCode: 'C', - }, - { - value: '昌平区', - text: '昌平区', - wordCode: 'C', - }, - { - value: '大兴区', - text: '大兴区', - wordCode: 'D', - }, - { - value: '东城区', - text: '东城区', - wordCode: 'D', - }, - { - value: '房山区', - text: '房山区', - wordCode: 'F', - }, - { - value: '丰台区', - text: '丰台区', - wordCode: 'F', - }, - ], - }, - { - value: '重庆', - text: '重庆', - wordCode: 'C', - }, - { - value: '福建', - text: '福建', - wordCode: 'F', - }, - { - value: '贵州', - text: '贵州', - wordCode: 'G', - }, - { - value: '广东', - text: '广东', - wordCode: 'G', - }, - { - value: '广西', - text: '广西', - wordCode: 'G', - }, - { - value: '甘肃', - text: '甘肃', - wordCode: 'G', - }, - { - value: '河北', - text: '河北', - wordCode: 'H', - disabled: true, - }, - { - value: '河南', - text: '河南', - wordCode: 'H', - disabled: true, - }, - { - value: '湖南', - text: '湖南', - wordCode: 'H', - disabled: true, - }, - { - value: '湖北', - text: '湖北', - wordCode: 'H', - disabled: true, - }, - { - value: '浙江', - text: '浙江', - wordCode: 'Z', - }, - ]) - }, []) const [visible, setVisible] = useState(false) return ( <> setVisible(true)} />
{ + onChange={(value, params) => { setText(value.join('')) }} onClose={() => setVisible(false)} diff --git a/src/packages/address/demos/h5/demo11.tsx b/src/packages/address/demos/h5/demo11.tsx new file mode 100644 index 0000000000..d34c0946f7 --- /dev/null +++ b/src/packages/address/demos/h5/demo11.tsx @@ -0,0 +1,200 @@ +import React, { useEffect, useState } from 'react' +import { Address, Cell } from '@nutui/nutui-react' + +const Demo1 = () => { + const [text, setText] = useState('选择地址') + const [hotList, setHotList] = useState([ + { id: '1', name: '北京' }, + { id: '2', name: '上海' }, + { id: '1601', name: '广州' }, + { id: '1607', name: '深圳' }, + { id: '1213', name: '杭州' }, + { id: '904', name: '南京' }, + { id: '988', name: '苏州' }, + { id: '3', name: '天津' }, + { id: '3', name: '天津' }, + { id: '3', name: '天津' }, + ]) + const [options, setOptions] = useState([]) + useEffect(() => { + setOptions([ + { + value: '安徽', + text: '安徽', + wordCode: 'A', + children: [ + { + value: '安庆市', + text: '安庆市', + wordCode: 'A', + disabled: true, + children: [ + { + value: '大观区', + text: '大观区', + disabled: true, + wordCode: 'D', + }, + { value: '怀宁县', text: '怀宁县', wordCode: 'H' }, + { value: '岳西县', text: '岳西县', wordCode: 'Y' }, + { value: '迎江区', text: '迎江区', wordCode: 'Y' }, + { value: '宜秀区', text: '宜秀区', wordCode: 'Y' }, + ], + }, + { + value: '合肥市', + text: '合肥市', + wordCode: 'H', + children: [ + { value: '合肥高新', text: '合肥高新', wordCode: 'H' }, + { value: '合肥经济', text: '合肥经济', wordCode: 'H' }, + ], + }, + { + value: '淮北市', + text: '淮北市', + wordCode: 'H', + children: [ + { value: '杜集区', text: '杜集区', wordCode: 'D' }, + { value: '烈山区', text: '杜集区', wordCode: 'L' }, + ], + }, + { + value: '淮南市', + text: '淮南市', + wordCode: 'H', + children: [{ value: '八公山区', text: '八公山区', wordCode: 'B' }], + }, + { + value: '黄山市', + text: '黄山市', + wordCode: 'H', + children: [ + { value: '黄山区', text: '黄山区', wordCode: 'H' }, + { value: '徽州区', text: '徽州区', wordCode: 'H' }, + ], + }, + ], + }, + { + value: '北京', + text: '北京', + wordCode: 'B', + children: [ + { + value: '朝阳区', + text: '朝阳区', + wordCode: 'C', + }, + { + value: '昌平区', + text: '昌平区', + wordCode: 'C', + }, + { + value: '大兴区', + text: '大兴区', + wordCode: 'D', + }, + { + value: '东城区', + text: '东城区', + wordCode: 'D', + }, + { + value: '房山区', + text: '房山区', + wordCode: 'F', + }, + { + value: '丰台区', + text: '丰台区', + wordCode: 'F', + }, + ], + }, + { + value: '重庆', + text: '重庆', + wordCode: 'C', + }, + { + value: '福建', + text: '福建', + wordCode: 'F', + }, + { + value: '贵州', + text: '贵州', + wordCode: 'G', + }, + { + value: '广东', + text: '广东', + wordCode: 'G', + }, + { + value: '广西', + text: '广西', + wordCode: 'G', + }, + { + value: '甘肃', + text: '甘肃', + wordCode: 'G', + }, + { + value: '河北', + text: '河北', + wordCode: 'H', + disabled: true, + }, + { + value: '河南', + text: '河南', + wordCode: 'H', + disabled: true, + }, + { + value: '湖南', + text: '湖南', + wordCode: 'H', + disabled: true, + }, + { + value: '湖北', + text: '湖北', + wordCode: 'H', + disabled: true, + }, + { + value: '浙江', + text: '浙江', + wordCode: 'Z', + }, + ]) + }, []) + const [visible, setVisible] = useState(false) + + return ( + <> + setVisible(true)} + /> +
{ + setText(value.join('')) + }} + onClose={() => setVisible(false)} + /> + + ) +} +export default Demo1 diff --git a/src/packages/address/demos/taro/demo11.tsx b/src/packages/address/demos/taro/demo11.tsx new file mode 100644 index 0000000000..13a294610e --- /dev/null +++ b/src/packages/address/demos/taro/demo11.tsx @@ -0,0 +1,200 @@ +import React, { useEffect, useState } from 'react' +import { Address, Cell } from '@nutui/nutui-react-taro' + +const Demo1 = () => { + const [text, setText] = useState('选择地址') + const [hotList, setHotList] = useState([ + { id: '1', name: '北京' }, + { id: '2', name: '上海' }, + { id: '1601', name: '广州' }, + { id: '1607', name: '深圳' }, + { id: '1213', name: '杭州' }, + { id: '904', name: '南京' }, + { id: '988', name: '苏州' }, + { id: '3', name: '天津' }, + { id: '3', name: '天津' }, + { id: '3', name: '天津' }, + ]) + const [options, setOptions] = useState([]) + useEffect(() => { + setOptions([ + { + value: '安徽', + text: '安徽', + wordCode: 'A', + children: [ + { + value: '安庆市', + text: '安庆市', + wordCode: 'A', + disabled: true, + children: [ + { + value: '大观区', + text: '大观区', + disabled: true, + wordCode: 'D', + }, + { value: '怀宁县', text: '怀宁县', wordCode: 'H' }, + { value: '岳西县', text: '岳西县', wordCode: 'Y' }, + { value: '迎江区', text: '迎江区', wordCode: 'Y' }, + { value: '宜秀区', text: '宜秀区', wordCode: 'Y' }, + ], + }, + { + value: '合肥市', + text: '合肥市', + wordCode: 'H', + children: [ + { value: '合肥高新', text: '合肥高新', wordCode: 'H' }, + { value: '合肥经济', text: '合肥经济', wordCode: 'H' }, + ], + }, + { + value: '淮北市', + text: '淮北市', + wordCode: 'H', + children: [ + { value: '杜集区', text: '杜集区', wordCode: 'D' }, + { value: '烈山区', text: '杜集区', wordCode: 'L' }, + ], + }, + { + value: '淮南市', + text: '淮南市', + wordCode: 'H', + children: [{ value: '八公山区', text: '八公山区', wordCode: 'B' }], + }, + { + value: '黄山市', + text: '黄山市', + wordCode: 'H', + children: [ + { value: '黄山区', text: '黄山区', wordCode: 'H' }, + { value: '徽州区', text: '徽州区', wordCode: 'H' }, + ], + }, + ], + }, + { + value: '北京', + text: '北京', + wordCode: 'B', + children: [ + { + value: '朝阳区', + text: '朝阳区', + wordCode: 'C', + }, + { + value: '昌平区', + text: '昌平区', + wordCode: 'C', + }, + { + value: '大兴区', + text: '大兴区', + wordCode: 'D', + }, + { + value: '东城区', + text: '东城区', + wordCode: 'D', + }, + { + value: '房山区', + text: '房山区', + wordCode: 'F', + }, + { + value: '丰台区', + text: '丰台区', + wordCode: 'F', + }, + ], + }, + { + value: '重庆', + text: '重庆', + wordCode: 'C', + }, + { + value: '福建', + text: '福建', + wordCode: 'F', + }, + { + value: '贵州', + text: '贵州', + wordCode: 'G', + }, + { + value: '广东', + text: '广东', + wordCode: 'G', + }, + { + value: '广西', + text: '广西', + wordCode: 'G', + }, + { + value: '甘肃', + text: '甘肃', + wordCode: 'G', + }, + { + value: '河北', + text: '河北', + wordCode: 'H', + disabled: true, + }, + { + value: '河南', + text: '河南', + wordCode: 'H', + disabled: true, + }, + { + value: '湖南', + text: '湖南', + wordCode: 'H', + disabled: true, + }, + { + value: '湖北', + text: '湖北', + wordCode: 'H', + disabled: true, + }, + { + value: '浙江', + text: '浙江', + wordCode: 'Z', + }, + ]) + }, []) + const [visible, setVisible] = useState(false) + + return ( + <> + setVisible(true)} + /> +
{ + setText(value.join('')) + }} + onClose={() => setVisible(false)} + /> + + ) +} +export default Demo1 diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index ab2fd80289..bdb2efb013 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -1,17 +1,43 @@ -import React, { FunctionComponent } from 'react' +import React, { + FunctionComponent, + useEffect, + useMemo, + useRef, + useState, +} from 'react' + +import Popup from '@/packages/popup/index.taro' +import Elevator from '../elevator/index.taro' +import { + normalizeListOptions, + normalizeOptions, +} from '@/packages/cascader/utils' +import { transformData } from './utils' import { - TaroCascaderProps, CascaderOption, + WebCascaderProps, CascaderValue, CascaderOptionKey, } from '@/types' import { ComponentDefaults } from '@/utils/typings' -import Cascader from '@/packages/cascader/index.taro' +import { mergeProps } from '@/utils/merge-props' +import { usePropsValue } from '@/hooks/use-props-value' +import { isEmpty } from '@/utils/is-empty' +import { useConfig } from '@/packages/configprovider' -export interface AddressProps extends TaroCascaderProps { +// 支持热区快速定位 +// 支持电梯快速定位 +// 已选省份地区放在顶部,独立展示 +type AreaInfo = { + name: string + id: string | number + children: any +} +export interface AddressProps extends WebCascaderProps { visible: boolean // popup visible type: string options: CascaderOption[] + hotList: AreaInfo[] value: CascaderValue defaultValue: CascaderValue optionKey: CascaderOptionKey @@ -22,14 +48,24 @@ export interface AddressProps extends TaroCascaderProps { const defaultProps = { ...ComponentDefaults, visible: false, - type: 'custom', + type: 'elevator', options: [], optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, format: {}, height: '200px', + activeColor: '', + activeIcon: 'checklist', + popup: true, + closeable: false, + closeIconPosition: 'top-right', + closeIcon: 'close', + lazy: false, + onClose: () => {}, + onChange: () => {}, + onPathChange: () => {}, } as unknown as AddressProps -export const CustomRender: FunctionComponent< +export const ElevatorRender: FunctionComponent< Partial & Omit< React.HTMLAttributes, @@ -38,47 +74,246 @@ export const CustomRender: FunctionComponent< > = (props) => { const { children, - visible, type, height, - options, + hotList, title, left, - value, defaultValue, optionKey, format, onClose, onChange, onPathChange, + activeColor, + activeIcon, + popup, + popupProps = {}, + visible: outerVisible, + options: outerOptions, + value: outerValue, + defaultValue: outerDefaultValue, + closeable, + closeIconPosition, + closeIcon, + lazy, + onLoad, ...rest - } = { - ...defaultProps, - ...props, + } = mergeProps(defaultProps, props) + const { locale } = useConfig() + + const classPrefix = 'nut-address' + + const [tabActiveIndex, setTabActiveIndex] = useState(0) + const [innerOptions, setInnerOptions] = useState(outerOptions) + const [loading, setLoading] = useState<{ [key: string]: any }>({}) + + const [value, setValue] = usePropsValue({ + value: outerValue, + defaultValue: outerDefaultValue, + finalValue: [], + onChange: (value) => { + props.onChange?.(value, pathNodes.current) + props.onPathChange?.(value, pathNodes.current) + }, + }) + + const [innerValue, setInnerValue] = useState(value) + const [addressTip, setAddressTip] = useState('选择省份/地区') + const [levelIndex, setLevelIndex] = useState(0) + + // 初始化数据,只格式化一次;动态数据todo + const options = useMemo(() => { + let currOptions = innerOptions + if (!isEmpty(format)) { + currOptions = normalizeListOptions(innerOptions, format) + } else if (!isEmpty(optionKey)) { + currOptions = normalizeOptions(innerOptions, optionKey) || [] + } + return transformData(currOptions) + }, [innerOptions, optionKey, format]) + + const [elevatorOptions, setElevatorOptions] = useState([]) + + useEffect(() => { + setElevatorOptions(options) + }, [options]) + + const pathNodes = useRef([]) + + const levels: any[] = useMemo(() => { + const next = [] + let end = false + let currentOptions = options + for (const [index, val] of innerValue.entries()) { + const opt = currentOptions?.flatMap((o: any) => { + const foundItem = o.list.find((item: any) => item.name === val) + return foundItem + })[0] + + next.push({ + name: val, + children: currentOptions, + levelIndex: index, + current: index === tabActiveIndex, + }) + // pathNodes.current[index] = opt + if (opt?.children) { + currentOptions = opt.children + } else { + end = true + // break + } + } + if (!end) { + next.push({ + name: null, + children: currentOptions, + }) + } + return next + }, [innerValue, options, tabActiveIndex]) + + const [visible, setVisible] = usePropsValue({ + value: outerVisible, + defaultValue: undefined, + onChange: (value) => { + if (value === false) { + props.onClose?.() + } + }, + }) + + useEffect(() => { + if (!visible) { + setInnerValue(value) + } + }, [visible, value]) + + useEffect(() => { + setInnerOptions(outerOptions) + }, [outerOptions]) + + useEffect(() => { + setTabActiveIndex(levels.length - 1) + setAddressTip(innerValue.length ? '请选择' : '选择省份/地区') + }, [innerValue]) + + const renderTab = () => { + if (!levels[0].name) return + return ( +
+ {levels.map((item, index) => ( + <> + {item.name ? ( +
{ + props.onTabsChange?.(Number(index)) + setTabActiveIndex(Number(index)) + setLevelIndex(index) + setElevatorOptions(item.children) + }} + > + {item.name} +
+ ) : null} + {levels[index + 1]?.name ? ( +
-
+ ) : null} + + ))} +
+ ) + } + + const onElevatorItemClick = (elevatorItem: AreaInfo, levelIndex: number) => { + if (elevatorItem?.disabled) return + if (elevatorItem.children?.length) { + setElevatorOptions(elevatorItem.children) + const distIndex = levelIndex + 1 + setLevelIndex(distIndex) + } else { + console.log('close popup') + } + + const nextValue = innerValue.slice(0, levelIndex) + if (elevatorItem.name) { + setLoading(!!onLoad && { [levelIndex]: elevatorItem.name }) + nextValue[levelIndex] = elevatorItem.name + } + if (!elevatorItem.children && !onLoad) { + setVisible(false) + setValue(nextValue) + } + setInnerValue(nextValue) + setLoading({}) + } + + const renderHotArea = () => { + // 选中省份/直辖市时,会展示热门城市 + if (levels.length && tabActiveIndex !== 0) return + return ( + <> +
热门城市
+
+ {hotList.map((item, index) => ( +
+ {item.name} +
+ ))} +
+ + ) } - return ( - <> - {type === 'custom' && ( - { - onClose?.() - }} - onChange={(val, params) => { - onChange?.(val, params) - }} - onPathChange={onPathChange} - {...rest} + const renderArea = () => { + return ( + <> +
{addressTip}
+ + onElevatorItemClick(item, levelIndex) + } + height="300px" /> - )} - + + ) + } + + const renderElevatorList = () => { + return ( + <> + {renderTab()} + {renderHotArea()} + {renderArea()} + + ) + } + + return popup ? ( + setVisible(false)} + onCloseIconClick={() => setVisible(false)} + > + {renderElevatorList()} + + ) : ( + renderElevatorList() ) } + +ElevatorRender.displayName = 'NutElevatorRender' diff --git a/src/packages/address/utils.ts b/src/packages/address/utils.ts index 383f49807b..1ff917da98 100644 --- a/src/packages/address/utils.ts +++ b/src/packages/address/utils.ts @@ -1,6 +1,6 @@ const generateId = (name: string) => { // 简单实现:根据 name 生成一个随机 ID - return name.charCodeAt(0) + name.charCodeAt(1) // 使用字符的 Unicode 值作为 ID + return name.split('').reduce((sum, char) => sum + char.charCodeAt(0), 0) // 使用字符的 Unicode 值作为 ID } export const transformData = (data: any) => { From 8e91e2e0639d27be11899bda8316e70400aca809 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Thu, 17 Apr 2025 21:18:35 +0800 Subject: [PATCH 06/22] =?UTF-8?q?feat:=20=E7=83=AD=E9=97=A8=E5=9F=8E?= =?UTF-8?q?=E5=B8=82=E5=8F=8D=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/demos/h5/demo11.tsx | 115 ++++++++++++++++-- src/packages/address/demos/taro/demo11.tsx | 117 +++++++++++++++++-- src/packages/address/elevatorRender.taro.tsx | 35 ++++-- src/packages/address/elevatorRender.tsx | 41 +++++-- src/packages/address/utils.ts | 34 +++++- src/packages/elevator/elevator.tsx | 2 +- 6 files changed, 300 insertions(+), 44 deletions(-) diff --git a/src/packages/address/demos/h5/demo11.tsx b/src/packages/address/demos/h5/demo11.tsx index d34c0946f7..240ee912af 100644 --- a/src/packages/address/demos/h5/demo11.tsx +++ b/src/packages/address/demos/h5/demo11.tsx @@ -3,17 +3,17 @@ import { Address, Cell } from '@nutui/nutui-react' const Demo1 = () => { const [text, setText] = useState('选择地址') - const [hotList, setHotList] = useState([ - { id: '1', name: '北京' }, - { id: '2', name: '上海' }, - { id: '1601', name: '广州' }, - { id: '1607', name: '深圳' }, - { id: '1213', name: '杭州' }, - { id: '904', name: '南京' }, - { id: '988', name: '苏州' }, - { id: '3', name: '天津' }, - { id: '3', name: '天津' }, - { id: '3', name: '天津' }, + const [hotList] = useState([ + { name: '北京' }, + { name: '上海' }, + { name: '广州' }, + { name: '深圳' }, + { name: '杭州' }, + { name: '南京' }, + { name: '苏州' }, + { name: '天津' }, + { name: '武汉' }, + { name: '长沙' }, ]) const [options, setOptions] = useState([]) useEffect(() => { @@ -132,6 +132,62 @@ const Demo1 = () => { value: '广东', text: '广东', wordCode: 'G', + children: [ + { + value: '广州市', + text: '广州市', + wordCode: 'G', + children: [ + { + value: '白云区', + text: '白云区', + wordCode: 'B', + }, + { + value: '黄埔区', + text: '黄埔区', + wordCode: 'H', + }, + { + value: '花都区', + text: '花都区', + wordCode: 'H', + }, + { + value: '海珠区', + text: '海珠区', + wordCode: 'H', + }, + ], + }, + { + value: '深圳市', + text: '深圳市', + wordCode: 'S', + children: [ + { + value: '宝安区', + text: '宝安区', + wordCode: 'B', + }, + { + value: '罗湖区', + text: '罗湖区', + wordCode: 'L', + }, + { + value: '龙岗区', + text: '龙岗区', + wordCode: 'L', + }, + { + value: '龙华区', + text: '龙华区', + wordCode: 'L', + }, + ], + }, + ], }, { value: '广西', @@ -167,6 +223,43 @@ const Demo1 = () => { wordCode: 'H', disabled: true, }, + { + value: '上海', + text: '上海', + wordCode: 'S', + children: [ + { + value: '宝山区', + text: '宝山区', + wordCode: 'B', + }, + { + value: '黄埔区', + text: '黄埔区', + wordCode: 'H', + }, + { + value: '虹口区', + text: '虹口区', + wordCode: 'H', + }, + { + value: '嘉定区', + text: '嘉定区', + wordCode: 'J', + }, + { + value: '静安区', + text: '静安区', + wordCode: 'J', + }, + { + value: '金山区', + text: '金山区', + wordCode: 'J', + }, + ], + }, { value: '浙江', text: '浙江', diff --git a/src/packages/address/demos/taro/demo11.tsx b/src/packages/address/demos/taro/demo11.tsx index 13a294610e..57f69cd7a7 100644 --- a/src/packages/address/demos/taro/demo11.tsx +++ b/src/packages/address/demos/taro/demo11.tsx @@ -3,17 +3,17 @@ import { Address, Cell } from '@nutui/nutui-react-taro' const Demo1 = () => { const [text, setText] = useState('选择地址') - const [hotList, setHotList] = useState([ - { id: '1', name: '北京' }, - { id: '2', name: '上海' }, - { id: '1601', name: '广州' }, - { id: '1607', name: '深圳' }, - { id: '1213', name: '杭州' }, - { id: '904', name: '南京' }, - { id: '988', name: '苏州' }, - { id: '3', name: '天津' }, - { id: '3', name: '天津' }, - { id: '3', name: '天津' }, + const [hotList] = useState([ + { name: '北京' }, + { name: '上海' }, + { name: '广州' }, + { name: '深圳' }, + { name: '杭州' }, + { name: '南京' }, + { name: '苏州' }, + { name: '天津' }, + { name: '武汉' }, + { name: '长沙' }, ]) const [options, setOptions] = useState([]) useEffect(() => { @@ -132,6 +132,62 @@ const Demo1 = () => { value: '广东', text: '广东', wordCode: 'G', + children: [ + { + value: '广州市', + text: '广州市', + wordCode: 'G', + children: [ + { + value: '白云区', + text: '白云区', + wordCode: 'B', + }, + { + value: '黄埔区', + text: '黄埔区', + wordCode: 'H', + }, + { + value: '花都区', + text: '花都区', + wordCode: 'H', + }, + { + value: '海珠区', + text: '海珠区', + wordCode: 'H', + }, + ], + }, + { + value: '深圳市', + text: '深圳市', + wordCode: 'S', + children: [ + { + value: '宝安区', + text: '宝安区', + wordCode: 'B', + }, + { + value: '罗湖区', + text: '罗湖区', + wordCode: 'L', + }, + { + value: '龙岗区', + text: '龙岗区', + wordCode: 'L', + }, + { + value: '龙华区', + text: '龙华区', + wordCode: 'L', + }, + ], + }, + ], }, { value: '广西', @@ -167,6 +223,43 @@ const Demo1 = () => { wordCode: 'H', disabled: true, }, + { + value: '上海', + text: '上海', + wordCode: 'S', + children: [ + { + value: '宝山区', + text: '宝山区', + wordCode: 'B', + }, + { + value: '黄埔区', + text: '黄埔区', + wordCode: 'H', + }, + { + value: '虹口区', + text: '虹口区', + wordCode: 'H', + }, + { + value: '嘉定区', + text: '嘉定区', + wordCode: 'J', + }, + { + value: '静安区', + text: '静安区', + wordCode: 'J', + }, + { + value: '金山区', + text: '金山区', + wordCode: 'J', + }, + ], + }, { value: '浙江', text: '浙江', @@ -179,7 +272,7 @@ const Demo1 = () => { return ( <> setVisible(true)} /> diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index bdb2efb013..e4246386a2 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -12,7 +12,7 @@ import { normalizeListOptions, normalizeOptions, } from '@/packages/cascader/utils' -import { transformData } from './utils' +import { transformData, findDataByName } from './utils' import { CascaderOption, WebCascaderProps, @@ -146,10 +146,12 @@ export const ElevatorRender: FunctionComponent< let end = false let currentOptions = options for (const [index, val] of innerValue.entries()) { - const opt = currentOptions?.flatMap((o: any) => { - const foundItem = o.list.find((item: any) => item.name === val) - return foundItem - })[0] + const opt = currentOptions + ?.flatMap((o: any) => { + const foundItem = o.list.find((item: any) => item.name === val) + return foundItem + }) + .filter((item) => item !== undefined)[0] next.push({ name: val, @@ -201,6 +203,7 @@ export const ElevatorRender: FunctionComponent< const renderTab = () => { if (!levels[0].name) return + // console.log('tabs', levels) return (
{levels.map((item, index) => ( @@ -237,7 +240,6 @@ export const ElevatorRender: FunctionComponent< } else { console.log('close popup') } - const nextValue = innerValue.slice(0, levelIndex) if (elevatorItem.name) { setLoading(!!onLoad && { [levelIndex]: elevatorItem.name }) @@ -248,7 +250,20 @@ export const ElevatorRender: FunctionComponent< setValue(nextValue) } setInnerValue(nextValue) - setLoading({}) + } + + const onHotItemClick = (hotItem: any) => { + // 通过修改 innerValue 构造 level 数据 + const distData = findDataByName(options, hotItem.name) + // 热门城市主要是一级城市和二级城市,可以扩展。TODO + if (distData) { + const innerValue = [distData.pName, distData.name].filter( + (item) => item !== '' + ) + setInnerValue(innerValue) + setElevatorOptions(distData.children) + setLevelIndex(innerValue.length) + } } const renderHotArea = () => { @@ -259,7 +274,11 @@ export const ElevatorRender: FunctionComponent<
热门城市
{hotList.map((item, index) => ( -
+
onHotItemClick(item)} + > {item.name}
))} diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index 9729c00b34..b49ca5d04d 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -12,7 +12,7 @@ import { normalizeListOptions, normalizeOptions, } from '@/packages/cascader/utils' -import { transformData } from './utils' +import { transformData, findDataByName } from './utils' import { CascaderOption, WebCascaderProps, @@ -142,14 +142,19 @@ export const ElevatorRender: FunctionComponent< const pathNodes = useRef([]) const levels: any[] = useMemo(() => { + // console.log('inner', innerValue) const next = [] let end = false let currentOptions = options for (const [index, val] of innerValue.entries()) { - const opt = currentOptions?.flatMap((o: any) => { - const foundItem = o.list.find((item: any) => item.name === val) - return foundItem - })[0] + // console.log('33333333', currentOptions, val) + const opt = currentOptions + ?.flatMap((o: any) => { + const foundItem = o.list.find((item: any) => item.name === val) + // console.log('444444', o.list, o.title, foundItem) + return foundItem + }) + .filter((item) => item !== undefined)[0] next.push({ name: val, @@ -171,6 +176,7 @@ export const ElevatorRender: FunctionComponent< children: currentOptions, }) } + // console.log('next', next) return next }, [innerValue, options, tabActiveIndex]) @@ -201,6 +207,7 @@ export const ElevatorRender: FunctionComponent< const renderTab = () => { if (!levels[0].name) return + // console.log('tabs', levels) return (
{levels.map((item, index) => ( @@ -214,6 +221,7 @@ export const ElevatorRender: FunctionComponent< setTabActiveIndex(Number(index)) setLevelIndex(index) setElevatorOptions(item.children) + // console.log('tab click item children', item.children) }} > {item.name} @@ -248,7 +256,20 @@ export const ElevatorRender: FunctionComponent< setValue(nextValue) } setInnerValue(nextValue) - setLoading({}) + } + + const onHotItemClick = (hotItem: any) => { + // 通过修改 innerValue 构造 level 数据 + const distData = findDataByName(options, hotItem.name) + // 热门城市主要是一级城市和二级城市,可以扩展。TODO + if (distData) { + const innerValue = [distData.pName, distData.name].filter( + (item) => item !== '' + ) + setInnerValue(innerValue) + setElevatorOptions(distData.children) + setLevelIndex(innerValue.length) + } } const renderHotArea = () => { @@ -259,7 +280,11 @@ export const ElevatorRender: FunctionComponent<
热门城市
{hotList.map((item, index) => ( -
+
onHotItemClick(item)} + > {item.name}
))} @@ -268,6 +293,8 @@ export const ElevatorRender: FunctionComponent< ) } + // console.log('elevatorOptions', elevatorOptions) + const renderArea = () => { return ( <> diff --git a/src/packages/address/utils.ts b/src/packages/address/utils.ts index 1ff917da98..6efba04c78 100644 --- a/src/packages/address/utils.ts +++ b/src/packages/address/utils.ts @@ -4,19 +4,28 @@ const generateId = (name: string) => { } export const transformData = (data: any) => { - const groupByWordCode = (data: any) => { + const groupByWordCode = ( + data: any, + parentId: string | number, + parentName: string + ) => { return data?.reduce((acc: any, item: any) => { const { wordCode } = item if (!acc[wordCode]) { acc[wordCode] = [] } + const currentId = generateId(item.value) acc[wordCode].push({ name: item.value, wordCode: item.wordCode, - id: generateId(item.value), - children: (item.children && groupByWordCode(item.children)) || null, + id: currentId, + pId: parentId, + pName: parentName, + children: + (item.children && + groupByWordCode(item.children, currentId, item.text)) || + null, }) - return acc }, {}) } @@ -34,7 +43,22 @@ export const transformData = (data: any) => { })) } - const middleData = groupByWordCode(data) + const middleData = groupByWordCode(data, '', '') const resultData = extractTitles(middleData) return resultData } + +export const findDataByName: any = (data: any, name: string) => { + for (const item of data) { + if (item.name?.indexOf(name) === 0) return item + if (item.children) { + const found = findDataByName(item.children, name) + if (found) return found + } + if (item.list) { + const found = findDataByName(item.list, name) + if (found) return found + } + } + return null // 如果没有找到,返回 null +} diff --git a/src/packages/elevator/elevator.tsx b/src/packages/elevator/elevator.tsx index 0c30b54d05..6d84e20a85 100644 --- a/src/packages/elevator/elevator.tsx +++ b/src/packages/elevator/elevator.tsx @@ -274,7 +274,7 @@ export const Elevator: FunctionComponent< className={classNames({ [`${classPrefix}-bars-inner-item`]: true, [`${classPrefix}-bars-inner-item-active`]: - item[floorKey] === list[currentIndex][floorKey], + item[floorKey] === list[currentIndex]?.[floorKey], })} data-index={index} key={index} From 91a0008aecad6db1efcf96ae3ece27650aeba15c Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Fri, 18 Apr 2025 13:47:19 +0800 Subject: [PATCH 07/22] =?UTF-8?q?feat:=20=E8=B5=B0=E6=9F=A5=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locales/base.ts | 2 + src/locales/en-US.ts | 2 + src/locales/id-ID.ts | 2 + src/locales/tr-TR.ts | 2 + src/locales/zh-CN.ts | 2 + src/locales/zh-TW.ts | 2 + src/locales/zh-UG.ts | 2 + src/packages/address/demos/h5/demo11.tsx | 3 +- src/packages/address/doc.md | 2 +- src/packages/address/elevator.scss | 7 +- src/packages/address/elevatorRender.taro.tsx | 166 ++++++++----------- src/packages/address/elevatorRender.tsx | 163 +++++++----------- 12 files changed, 151 insertions(+), 204 deletions(-) diff --git a/src/locales/base.ts b/src/locales/base.ts index bc4e0010c5..a79f62c2bf 100644 --- a/src/locales/base.ts +++ b/src/locales/base.ts @@ -65,6 +65,8 @@ export interface BaseLang { selectRegion: string deliveryTo: string chooseAnotherAddress: string + hotCity: string + selectProvice: string } signature: { reSign: string diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index e812d330ae..126e98b687 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -65,6 +65,8 @@ const enUS: BaseLang = { selectRegion: 'Choose Address', deliveryTo: 'Delivery To', chooseAnotherAddress: 'Choose Another Address', + hotCity: 'Hot City', + selectProvice: 'Choose Provice or City', }, signature: { reSign: 'Re Sign', diff --git a/src/locales/id-ID.ts b/src/locales/id-ID.ts index 7ba1328ad0..222bad6805 100644 --- a/src/locales/id-ID.ts +++ b/src/locales/id-ID.ts @@ -66,6 +66,8 @@ const idID: BaseLang = { selectRegion: 'Pilih Daerah', deliveryTo: 'Kirim Ke', chooseAnotherAddress: 'Pilih alamat lain', + hotCity: 'Kota-kota populer', + selectProvice: 'Pilih provinsi/wilayah', }, signature: { reSign: 'Masuk Kembali', diff --git a/src/locales/tr-TR.ts b/src/locales/tr-TR.ts index cc13028177..5fecdf82c2 100644 --- a/src/locales/tr-TR.ts +++ b/src/locales/tr-TR.ts @@ -74,6 +74,8 @@ const trTR: BaseLang = { selectRegion: 'Lütfen bölgenizi seçin', deliveryTo: 'Teslimat yeri', chooseAnotherAddress: 'Başka bir adres seçin', + hotCity: 'Popüler şehirler', + selectProvice: 'İl/bölge seçin', }, signature: { reSign: 'Yeniden imzala', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 896064def4..635d664884 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -67,6 +67,8 @@ const zhCN: BaseLang = { selectRegion: '请选择地址', deliveryTo: '配送至', chooseAnotherAddress: '选择其他地址', + hotCity: '热门城市', + selectProvice: '选择省份/地区', }, signature: { reSign: '重签', diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index 1aff33151e..ced63b0587 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -67,6 +67,8 @@ const zhCN: BaseLang = { selectRegion: '請選擇地址', deliveryTo: '配送至', chooseAnotherAddress: '選擇其他地址', + hotCity: '熱門城市', + selectProvice: '選擇省份/地區', }, signature: { reSign: '重簽', diff --git a/src/locales/zh-UG.ts b/src/locales/zh-UG.ts index 62dc80c998..c8122f9334 100644 --- a/src/locales/zh-UG.ts +++ b/src/locales/zh-UG.ts @@ -65,6 +65,8 @@ const zhUG: BaseLang = { selectRegion: 'ئادىرىسنى تاللاڭ', deliveryTo: 'قەيەرگە', chooseAnotherAddress: 'باشقىنى تاللاش', + hotCity: 'ئاۋات شەھەرلەر', + selectProvice: 'ئۆلكە / شەھەرنى تاللاڭ', }, signature: { reSign: 'قايتا', diff --git a/src/packages/address/demos/h5/demo11.tsx b/src/packages/address/demos/h5/demo11.tsx index 240ee912af..6f851aa045 100644 --- a/src/packages/address/demos/h5/demo11.tsx +++ b/src/packages/address/demos/h5/demo11.tsx @@ -278,11 +278,12 @@ const Demo1 = () => { />
{ + console.log('value', value) setText(value.join('')) }} onClose={() => setVisible(false)} diff --git a/src/packages/address/doc.md b/src/packages/address/doc.md index 46066dfd34..45d14e696f 100644 --- a/src/packages/address/doc.md +++ b/src/packages/address/doc.md @@ -1,6 +1,6 @@ # Address 地址 -地址选择,在2.0中,地址改用级联组件实现。截止当前版本,只支持级联,不支持级联+电梯模式,开发中。 +地址选择,在2.0中,地址改用级联组件实现。新增 电梯模式,支持热门城市的快速定位。 ## 引入 diff --git a/src/packages/address/elevator.scss b/src/packages/address/elevator.scss index 8e38695507..5316433397 100644 --- a/src/packages/address/elevator.scss +++ b/src/packages/address/elevator.scss @@ -44,12 +44,9 @@ border-bottom: 1px solid $color-border; &-item { font-size: 12px; - // display: flex; display: inline-block; - // justify-content: center; - // align-items: center; - height: 48px; - line-height: 48px; + height: 28px; + line-height: 28px; padding: 0 12px; border-radius: 4px; background-color: $color-background-sunken; diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index e4246386a2..332cd0d7b3 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -1,11 +1,6 @@ -import React, { - FunctionComponent, - useEffect, - useMemo, - useRef, - useState, -} from 'react' +import React, { FunctionComponent, useEffect, useMemo, useState } from 'react' +import { View } from '@tarojs/components' import Popup from '@/packages/popup/index.taro' import Elevator from '../elevator/index.taro' import { @@ -25,9 +20,6 @@ import { usePropsValue } from '@/hooks/use-props-value' import { isEmpty } from '@/utils/is-empty' import { useConfig } from '@/packages/configprovider' -// 支持热区快速定位 -// 支持电梯快速定位 -// 已选省份地区放在顶部,独立展示 type AreaInfo = { name: string id: string | number @@ -73,20 +65,14 @@ export const ElevatorRender: FunctionComponent< > > = (props) => { const { - children, - type, - height, hotList, title, left, - defaultValue, optionKey, format, onClose, onChange, onPathChange, - activeColor, - activeIcon, popup, popupProps = {}, visible: outerVisible, @@ -96,30 +82,29 @@ export const ElevatorRender: FunctionComponent< closeable, closeIconPosition, closeIcon, - lazy, - onLoad, - ...rest } = mergeProps(defaultProps, props) - const { locale } = useConfig() - + const { + locale: { + select, + address: { hotCity, selectProvice }, + }, + } = useConfig() const classPrefix = 'nut-address' const [tabActiveIndex, setTabActiveIndex] = useState(0) const [innerOptions, setInnerOptions] = useState(outerOptions) - const [loading, setLoading] = useState<{ [key: string]: any }>({}) - const [value, setValue] = usePropsValue({ value: outerValue, defaultValue: outerDefaultValue, finalValue: [], onChange: (value) => { - props.onChange?.(value, pathNodes.current) - props.onPathChange?.(value, pathNodes.current) + onChange(value, []) + onPathChange(value, []) }, }) const [innerValue, setInnerValue] = useState(value) - const [addressTip, setAddressTip] = useState('选择省份/地区') + const [addressTip, setAddressTip] = useState(selectProvice) const [levelIndex, setLevelIndex] = useState(0) // 初始化数据,只格式化一次;动态数据todo @@ -139,18 +124,13 @@ export const ElevatorRender: FunctionComponent< setElevatorOptions(options) }, [options]) - const pathNodes = useRef([]) - const levels: any[] = useMemo(() => { const next = [] let end = false let currentOptions = options for (const [index, val] of innerValue.entries()) { const opt = currentOptions - ?.flatMap((o: any) => { - const foundItem = o.list.find((item: any) => item.name === val) - return foundItem - }) + ?.flatMap((o: any) => o.list.find((item: any) => item.name === val)) .filter((item) => item !== undefined)[0] next.push({ @@ -159,12 +139,10 @@ export const ElevatorRender: FunctionComponent< levelIndex: index, current: index === tabActiveIndex, }) - // pathNodes.current[index] = opt if (opt?.children) { currentOptions = opt.children } else { end = true - // break } } if (!end) { @@ -181,15 +159,13 @@ export const ElevatorRender: FunctionComponent< defaultValue: undefined, onChange: (value) => { if (value === false) { - props.onClose?.() + onClose() } }, }) useEffect(() => { - if (!visible) { - setInnerValue(value) - } + if (!visible) setInnerValue(value) }, [visible, value]) useEffect(() => { @@ -198,61 +174,30 @@ export const ElevatorRender: FunctionComponent< useEffect(() => { setTabActiveIndex(levels.length - 1) - setAddressTip(innerValue.length ? '请选择' : '选择省份/地区') + setAddressTip(innerValue.length ? select : selectProvice) }, [innerValue]) - const renderTab = () => { - if (!levels[0].name) return - // console.log('tabs', levels) - return ( -
- {levels.map((item, index) => ( - <> - {item.name ? ( -
{ - props.onTabsChange?.(Number(index)) - setTabActiveIndex(Number(index)) - setLevelIndex(index) - setElevatorOptions(item.children) - }} - > - {item.name} -
- ) : null} - {levels[index + 1]?.name ? ( -
-
- ) : null} - - ))} -
- ) - } - - const onElevatorItemClick = (elevatorItem: AreaInfo, levelIndex: number) => { - if (elevatorItem?.disabled) return + const handleElevatorItemClick = ( + elevatorItem: AreaInfo, + levelIndex: number + ) => { + // if (elevatorItem?.disabled) return + const nextValue = innerValue.slice(0, levelIndex) + if (elevatorItem.name) { + nextValue[levelIndex] = elevatorItem.name + } if (elevatorItem.children?.length) { setElevatorOptions(elevatorItem.children) const distIndex = levelIndex + 1 setLevelIndex(distIndex) } else { - console.log('close popup') - } - const nextValue = innerValue.slice(0, levelIndex) - if (elevatorItem.name) { - setLoading(!!onLoad && { [levelIndex]: elevatorItem.name }) - nextValue[levelIndex] = elevatorItem.name - } - if (!elevatorItem.children && !onLoad) { setVisible(false) setValue(nextValue) } setInnerValue(nextValue) } - const onHotItemClick = (hotItem: any) => { + const handleHotItemClick = (hotItem: any) => { // 通过修改 innerValue 构造 level 数据 const distData = findDataByName(options, hotItem.name) // 热门城市主要是一级城市和二级城市,可以扩展。TODO @@ -265,24 +210,51 @@ export const ElevatorRender: FunctionComponent< setLevelIndex(innerValue.length) } } + const renderTabs = () => { + if (!levels[0].name) return null + return ( + + {levels.map((item, index) => ( + <> + {item.name && ( + { + props.onTabsChange?.(Number(index)) + setTabActiveIndex(Number(index)) + setLevelIndex(index) + setElevatorOptions(item.children) + }} + > + {item.name} + + )} + {levels[index + 1]?.name && ( + - + )} + + ))} + + ) + } - const renderHotArea = () => { - // 选中省份/直辖市时,会展示热门城市 + const renderHotCity = () => { if (levels.length && tabActiveIndex !== 0) return return ( <> -
热门城市
-
+ {hotCity} + {hotList.map((item, index) => ( -
onHotItemClick(item)} + onClick={() => handleHotItemClick(item)} > {item.name} -
+
))} -
+ ) } @@ -290,12 +262,12 @@ export const ElevatorRender: FunctionComponent< const renderArea = () => { return ( <> -
{addressTip}
+ {addressTip} - onElevatorItemClick(item, levelIndex) + handleElevatorItemClick(item, levelIndex) } height="300px" /> @@ -303,11 +275,11 @@ export const ElevatorRender: FunctionComponent< ) } - const renderElevatorList = () => { + const renderContent = () => { return ( <> - {renderTab()} - {renderHotArea()} + {renderTabs()} + {renderHotCity()} {renderArea()} ) @@ -323,15 +295,15 @@ export const ElevatorRender: FunctionComponent< closeIcon={closeIcon} closeable={closeable} closeIconPosition={closeIconPosition} - title={props.title} - left={props.left} + title={title} + left={left} onOverlayClick={() => setVisible(false)} onCloseIconClick={() => setVisible(false)} > - {renderElevatorList()} + {renderContent()} ) : ( - renderElevatorList() + renderContent() ) } diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index b49ca5d04d..7450228b51 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -1,10 +1,4 @@ -import React, { - FunctionComponent, - useEffect, - useMemo, - useRef, - useState, -} from 'react' +import React, { FunctionComponent, useEffect, useMemo, useState } from 'react' import Popup from '@/packages/popup' import Elevator from '../elevator' @@ -25,9 +19,6 @@ import { usePropsValue } from '@/hooks/use-props-value' import { isEmpty } from '@/utils/is-empty' import { useConfig } from '@/packages/configprovider' -// 支持热区快速定位 -// 支持电梯快速定位 -// 已选省份地区放在顶部,独立展示 type AreaInfo = { name: string id: string | number @@ -73,20 +64,14 @@ export const ElevatorRender: FunctionComponent< > > = (props) => { const { - children, - type, - height, hotList, title, left, - defaultValue, optionKey, format, onClose, onChange, onPathChange, - activeColor, - activeIcon, popup, popupProps = {}, visible: outerVisible, @@ -96,30 +81,29 @@ export const ElevatorRender: FunctionComponent< closeable, closeIconPosition, closeIcon, - lazy, - onLoad, - ...rest } = mergeProps(defaultProps, props) - const { locale } = useConfig() - + const { + locale: { + select, + address: { hotCity, selectProvice }, + }, + } = useConfig() const classPrefix = 'nut-address' const [tabActiveIndex, setTabActiveIndex] = useState(0) const [innerOptions, setInnerOptions] = useState(outerOptions) - const [loading, setLoading] = useState<{ [key: string]: any }>({}) - const [value, setValue] = usePropsValue({ value: outerValue, defaultValue: outerDefaultValue, finalValue: [], onChange: (value) => { - props.onChange?.(value, pathNodes.current) - props.onPathChange?.(value, pathNodes.current) + onChange(value, []) + onPathChange(value, []) }, }) const [innerValue, setInnerValue] = useState(value) - const [addressTip, setAddressTip] = useState('选择省份/地区') + const [addressTip, setAddressTip] = useState(selectProvice) const [levelIndex, setLevelIndex] = useState(0) // 初始化数据,只格式化一次;动态数据todo @@ -139,21 +123,13 @@ export const ElevatorRender: FunctionComponent< setElevatorOptions(options) }, [options]) - const pathNodes = useRef([]) - const levels: any[] = useMemo(() => { - // console.log('inner', innerValue) const next = [] let end = false let currentOptions = options for (const [index, val] of innerValue.entries()) { - // console.log('33333333', currentOptions, val) const opt = currentOptions - ?.flatMap((o: any) => { - const foundItem = o.list.find((item: any) => item.name === val) - // console.log('444444', o.list, o.title, foundItem) - return foundItem - }) + ?.flatMap((o: any) => o.list.find((item: any) => item.name === val)) .filter((item) => item !== undefined)[0] next.push({ @@ -162,12 +138,10 @@ export const ElevatorRender: FunctionComponent< levelIndex: index, current: index === tabActiveIndex, }) - // pathNodes.current[index] = opt if (opt?.children) { currentOptions = opt.children } else { end = true - // break } } if (!end) { @@ -176,7 +150,6 @@ export const ElevatorRender: FunctionComponent< children: currentOptions, }) } - // console.log('next', next) return next }, [innerValue, options, tabActiveIndex]) @@ -185,15 +158,13 @@ export const ElevatorRender: FunctionComponent< defaultValue: undefined, onChange: (value) => { if (value === false) { - props.onClose?.() + onClose() } }, }) useEffect(() => { - if (!visible) { - setInnerValue(value) - } + if (!visible) setInnerValue(value) }, [visible, value]) useEffect(() => { @@ -202,63 +173,30 @@ export const ElevatorRender: FunctionComponent< useEffect(() => { setTabActiveIndex(levels.length - 1) - setAddressTip(innerValue.length ? '请选择' : '选择省份/地区') + setAddressTip(innerValue.length ? select : selectProvice) }, [innerValue]) - const renderTab = () => { - if (!levels[0].name) return - // console.log('tabs', levels) - return ( -
- {levels.map((item, index) => ( - <> - {item.name ? ( -
{ - props.onTabsChange?.(Number(index)) - setTabActiveIndex(Number(index)) - setLevelIndex(index) - setElevatorOptions(item.children) - // console.log('tab click item children', item.children) - }} - > - {item.name} -
- ) : null} - {levels[index + 1]?.name ? ( -
-
- ) : null} - - ))} -
- ) - } - - const onElevatorItemClick = (elevatorItem: AreaInfo, levelIndex: number) => { - if (elevatorItem?.disabled) return + const handleElevatorItemClick = ( + elevatorItem: AreaInfo, + levelIndex: number + ) => { + // if (elevatorItem?.disabled) return + const nextValue = innerValue.slice(0, levelIndex) + if (elevatorItem.name) { + nextValue[levelIndex] = elevatorItem.name + } if (elevatorItem.children?.length) { setElevatorOptions(elevatorItem.children) const distIndex = levelIndex + 1 setLevelIndex(distIndex) } else { - console.log('close popup') - } - - const nextValue = innerValue.slice(0, levelIndex) - if (elevatorItem.name) { - setLoading(!!onLoad && { [levelIndex]: elevatorItem.name }) - nextValue[levelIndex] = elevatorItem.name - } - if (!elevatorItem.children && !onLoad) { setVisible(false) setValue(nextValue) } setInnerValue(nextValue) } - const onHotItemClick = (hotItem: any) => { + const handleHotItemClick = (hotItem: any) => { // 通过修改 innerValue 构造 level 数据 const distData = findDataByName(options, hotItem.name) // 热门城市主要是一级城市和二级城市,可以扩展。TODO @@ -271,19 +209,46 @@ export const ElevatorRender: FunctionComponent< setLevelIndex(innerValue.length) } } + const renderTabs = () => { + if (!levels[0].name) return null + return ( +
+ {levels.map((item, index) => ( + <> + {item.name && ( +
{ + props.onTabsChange?.(Number(index)) + setTabActiveIndex(Number(index)) + setLevelIndex(index) + setElevatorOptions(item.children) + }} + > + {item.name} +
+ )} + {levels[index + 1]?.name && ( +
-
+ )} + + ))} +
+ ) + } - const renderHotArea = () => { - // 选中省份/直辖市时,会展示热门城市 + const renderHotCity = () => { if (levels.length && tabActiveIndex !== 0) return return ( <> -
热门城市
+
{hotCity}
{hotList.map((item, index) => (
onHotItemClick(item)} + onClick={() => handleHotItemClick(item)} > {item.name}
@@ -293,8 +258,6 @@ export const ElevatorRender: FunctionComponent< ) } - // console.log('elevatorOptions', elevatorOptions) - const renderArea = () => { return ( <> @@ -303,7 +266,7 @@ export const ElevatorRender: FunctionComponent< className={`${classPrefix}-elevator`} list={elevatorOptions} onItemClick={(key: string, item: any) => - onElevatorItemClick(item, levelIndex) + handleElevatorItemClick(item, levelIndex) } height="300px" /> @@ -311,11 +274,11 @@ export const ElevatorRender: FunctionComponent< ) } - const renderElevatorList = () => { + const renderContent = () => { return ( <> - {renderTab()} - {renderHotArea()} + {renderTabs()} + {renderHotCity()} {renderArea()} ) @@ -331,15 +294,15 @@ export const ElevatorRender: FunctionComponent< closeIcon={closeIcon} closeable={closeable} closeIconPosition={closeIconPosition} - title={props.title} - left={props.left} + title={title} + left={left} onOverlayClick={() => setVisible(false)} onCloseIconClick={() => setVisible(false)} > - {renderElevatorList()} + {renderContent()} ) : ( - renderElevatorList() + renderContent() ) } From 8cc6934d27aadac314c286279f2b6aeaccaecd83 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Fri, 18 Apr 2025 14:46:05 +0800 Subject: [PATCH 08/22] feat: add docs and fix types --- src/packages/address/address.taro.tsx | 6 ++-- src/packages/address/address.tsx | 6 ++-- src/packages/address/doc.en-US.md | 10 ++++++- src/packages/address/doc.md | 11 ++++++- src/packages/address/doc.taro.md | 11 ++++++- src/packages/address/doc.zh-TW.md | 10 ++++++- src/packages/address/elevatorRender.taro.tsx | 31 ++++++++------------ src/packages/address/elevatorRender.tsx | 20 +++++-------- src/types/spec/address/base.ts | 1 + 9 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/packages/address/address.taro.tsx b/src/packages/address/address.taro.tsx index 64e77cc901..3aec73206b 100644 --- a/src/packages/address/address.taro.tsx +++ b/src/packages/address/address.taro.tsx @@ -19,6 +19,7 @@ import { CascaderValue, TaroAddressProps, } from '@/types' +import { mergeProps } from '@/utils/merge-props' const defaultProps = { ...ComponentDefaults, @@ -71,10 +72,7 @@ const InternalAddress: ForwardRefRenderFunction< onClose, onSwitch, ...rest - } = { - ...defaultProps, - ...props, - } + } = mergeProps(defaultProps, props) const classPrefix = 'nut-address' const [currentType, setCurrentType] = useState(type) const [innerVisible, setInnerVisible] = usePropsValue({ diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index a5eed44238..b8429d0e41 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -18,6 +18,7 @@ import { } from '@/types' import { ComponentDefaults } from '@/utils/typings' import { usePropsValue } from '@/hooks/use-props-value' +import { mergeProps } from '@/utils/merge-props' const defaultProps = { ...ComponentDefaults, @@ -70,10 +71,7 @@ export const InternalAddress: ForwardRefRenderFunction< onClose, onSwitch, ...rest - } = { - ...defaultProps, - ...props, - } + } = mergeProps(defaultProps, props) const classPrefix = 'nut-address' const [currentType, setCurrentType] = useState(type) const [innerVisible, setInnerVisible] = usePropsValue({ diff --git a/src/packages/address/doc.en-US.md b/src/packages/address/doc.en-US.md index 9f8e235685..c257e69381 100644 --- a/src/packages/address/doc.en-US.md +++ b/src/packages/address/doc.en-US.md @@ -10,6 +10,14 @@ import { Address } from '@nutui/nutui-react' ## Demo +### Elevator Address + +:::demo + + + +::: + ### Choose Custom Address :::demo @@ -66,7 +74,7 @@ If you want to select a province, you need to set the region ID in the order of | --- | --- | --- | --- | | visible | Whether to open address | `boolean` | `-` | | defaultVisible | Initial open/close state of the address selection | `boolean` | - | -| type | Choose type: exist/custom | `string` | `custom` | +| type | Choose type: exist/custom/elevator | `string` | `custom` | | existList | Exist address list data | `Array` | `[]` | | defaultIcon | Exist address default icon | `ReactNode` | `-` | | selectIcon | Exist address selected icon | `ReactNode` | `-` | diff --git a/src/packages/address/doc.md b/src/packages/address/doc.md index 45d14e696f..924999e9fa 100644 --- a/src/packages/address/doc.md +++ b/src/packages/address/doc.md @@ -10,6 +10,14 @@ import { Address } from '@nutui/nutui-react' ## 示例代码 +### 电梯地址 + +:::demo + + + +::: + ### 选择自定义地址 :::demo @@ -68,13 +76,14 @@ import { Address } from '@nutui/nutui-react' | --- | --- | --- | --- | | visible | 是否打开地址选择 | `boolean` | `-` | | defaultVisible | 初始地址选择打开/关闭状态 | `boolean` | `-` | -| type | 地址选择类型 exist/custom | `string` | `custom` | +| type | 地址选择类型 exist/custom/elevator | `string` | `custom` | | existList | 已存在地址列表,每个地址对象中,必传值provinceName、cityName、countyName、townName、addressDetail、selectedAddress(字段解释见下) | `Array` | `[]` | | defaultIcon | 已有地址列表默认图标,type='exist' 时生效 | `ReactNode` | `-` | | selectIcon | 已有地址列表选中图标,type='exist' 时生效 | `ReactNode` | `-` | | closeIcon | 自定义关闭弹框按钮图标 | `ReactNode` | `-` | | backIcon | 自定义地址与已有地址切换时,自定义返回的按钮图标 | `ReactNode` | `-` | | custom | 是否可以切换自定义地址选择,type='exist' 时生效 | `boolean` \| `string` | `true` | +| hotList | 是否展示热门城市,目前只在电梯模式下有效 | `Array` | - | | onExistSelect | 选择已有地址列表时触发 | `(data: AddressList) => void` | `-` | | onSwitch | 点击'选择其他地址'或自定义地址选择左上角返回按钮触发 | `(data: { type: string }) => void` | `-` | | onClose | 关闭弹框时触发 | `-` | `-` | diff --git a/src/packages/address/doc.taro.md b/src/packages/address/doc.taro.md index 4ed4987c09..64cee8ec08 100644 --- a/src/packages/address/doc.taro.md +++ b/src/packages/address/doc.taro.md @@ -10,6 +10,14 @@ import { Address } from '@nutui/nutui-react-taro' ## 示例代码 +### 电梯地址 + +:::demo + + + +::: + ### 选择自定义地址 :::demo @@ -68,13 +76,14 @@ import { Address } from '@nutui/nutui-react-taro' | --- | --- | --- | --- | | visible | 是否打开地址选择 | `boolean` | `-` | | defaultVisible | 初始地址选择打开/关闭状态 | `boolean` | `-` | -| type | 地址选择类型 exist/custom | `string` | `custom` | +| type | 地址选择类型 exist/custom/elevator | `string` | `custom` | | existList | 已存在地址列表,每个地址对象中,必传值provinceName、cityName、countyName、townName、addressDetail、selectedAddress(字段解释见下) | `Array` | `[]` | | defaultIcon | 已有地址列表默认图标,type='exist' 时生效 | `ReactNode` | `-` | | selectIcon | 已有地址列表选中图标,type='exist' 时生效 | `ReactNode` | `-` | | closeIcon | 自定义关闭弹框按钮图标 | `ReactNode` | `-` | | backIcon | 自定义地址与已有地址切换时,自定义返回的按钮图标 | `ReactNode` | `-` | | custom | 是否可以切换自定义地址选择,type='exist' 时生效 | `boolean` \| `string` | `true` | +| hotList | 是否展示热门城市,目前只在电梯模式下有效 | `Array` | - | | onExistSelect | 选择已有地址列表时触发 | `(data: AddressList) => void` | `-` | | onSwitch | 点击'选择其他地址'或自定义地址选择左上角返回按钮触发 | `(data: { type: string }) => void` | `-` | | onClose | 关闭弹框时触发 | `-` | `-` | diff --git a/src/packages/address/doc.zh-TW.md b/src/packages/address/doc.zh-TW.md index 0559366db6..2e5c216304 100644 --- a/src/packages/address/doc.zh-TW.md +++ b/src/packages/address/doc.zh-TW.md @@ -10,6 +10,14 @@ import { Address } from '@nutui/nutui-react' ## 示例代碼 +### 电梯地址 + +:::demo + + + +::: + ### 選擇自定義地址 :::demo @@ -60,7 +68,7 @@ import { Address } from '@nutui/nutui-react' | --- | --- | --- | --- | | visible | 是否打開地址選擇 | `boolean` | `-` | | defaultVisible | 初始地址選擇打開/關閉狀態 | `boolean` | - | -| type | 地址選擇類型 exist/custom | `string` | `custom` | +| type | 地址選擇類型 exist/custom/elevator | `string` | `custom` | | existList | 已存在地址列錶,每個地址對象中,必傳值provinceName、cityName、countyName、townName、addressDetail、selectedAddress(字段解釋見下) | `Array` | `[]` | | defaultIcon | 已有地址列錶默認圖標,type='exist' 時生效 | `ReactNode` | `-` | | selectIcon | 已有地址列錶選中圖標,type='exist' 時生效 | `ReactNode` | `-` | diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index 332cd0d7b3..8b6ed38d41 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -13,6 +13,7 @@ import { WebCascaderProps, CascaderValue, CascaderOptionKey, + RegionData, } from '@/types' import { ComponentDefaults } from '@/utils/typings' import { mergeProps } from '@/utils/merge-props' @@ -20,16 +21,11 @@ import { usePropsValue } from '@/hooks/use-props-value' import { isEmpty } from '@/utils/is-empty' import { useConfig } from '@/packages/configprovider' -type AreaInfo = { - name: string - id: string | number - children: any -} export interface AddressProps extends WebCascaderProps { visible: boolean // popup visible type: string options: CascaderOption[] - hotList: AreaInfo[] + hotList: RegionData[] value: CascaderValue defaultValue: CascaderValue optionKey: CascaderOptionKey @@ -109,26 +105,26 @@ export const ElevatorRender: FunctionComponent< // 初始化数据,只格式化一次;动态数据todo const options = useMemo(() => { - let currOptions = innerOptions if (!isEmpty(format)) { - currOptions = normalizeListOptions(innerOptions, format) - } else if (!isEmpty(optionKey)) { - currOptions = normalizeOptions(innerOptions, optionKey) || [] + return transformData(normalizeListOptions(innerOptions, format)) + } + if (!isEmpty(optionKey)) { + return transformData(normalizeOptions(innerOptions, optionKey) || []) } - return transformData(currOptions) + return transformData(innerOptions) }, [innerOptions, optionKey, format]) - const [elevatorOptions, setElevatorOptions] = useState([]) + const [elevatorOptions, setElevatorOptions] = useState(options) useEffect(() => { setElevatorOptions(options) }, [options]) - const levels: any[] = useMemo(() => { + const levels = useMemo(() => { const next = [] let end = false let currentOptions = options - for (const [index, val] of innerValue.entries()) { + innerValue.forEach((val, index) => { const opt = currentOptions ?.flatMap((o: any) => o.list.find((item: any) => item.name === val)) .filter((item) => item !== undefined)[0] @@ -144,7 +140,7 @@ export const ElevatorRender: FunctionComponent< } else { end = true } - } + }) if (!end) { next.push({ name: null, @@ -178,7 +174,7 @@ export const ElevatorRender: FunctionComponent< }, [innerValue]) const handleElevatorItemClick = ( - elevatorItem: AreaInfo, + elevatorItem: RegionData, levelIndex: number ) => { // if (elevatorItem?.disabled) return @@ -188,8 +184,7 @@ export const ElevatorRender: FunctionComponent< } if (elevatorItem.children?.length) { setElevatorOptions(elevatorItem.children) - const distIndex = levelIndex + 1 - setLevelIndex(distIndex) + setLevelIndex(levelIndex + 1) } else { setVisible(false) setValue(nextValue) diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index 7450228b51..1c2fd3e1ba 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -12,6 +12,7 @@ import { WebCascaderProps, CascaderValue, CascaderOptionKey, + RegionData, } from '@/types' import { ComponentDefaults } from '@/utils/typings' import { mergeProps } from '@/utils/merge-props' @@ -19,16 +20,11 @@ import { usePropsValue } from '@/hooks/use-props-value' import { isEmpty } from '@/utils/is-empty' import { useConfig } from '@/packages/configprovider' -type AreaInfo = { - name: string - id: string | number - children: any -} export interface AddressProps extends WebCascaderProps { visible: boolean // popup visible type: string options: CascaderOption[] - hotList: AreaInfo[] + hotList: RegionData[] value: CascaderValue defaultValue: CascaderValue optionKey: CascaderOptionKey @@ -90,8 +86,6 @@ export const ElevatorRender: FunctionComponent< } = useConfig() const classPrefix = 'nut-address' - const [tabActiveIndex, setTabActiveIndex] = useState(0) - const [innerOptions, setInnerOptions] = useState(outerOptions) const [value, setValue] = usePropsValue({ value: outerValue, defaultValue: outerDefaultValue, @@ -102,9 +96,12 @@ export const ElevatorRender: FunctionComponent< }, }) + const [innerOptions, setInnerOptions] = useState(outerOptions) const [innerValue, setInnerValue] = useState(value) + const [elevatorOptions, setElevatorOptions] = useState([]) const [addressTip, setAddressTip] = useState(selectProvice) const [levelIndex, setLevelIndex] = useState(0) + const [tabActiveIndex, setTabActiveIndex] = useState(0) // 初始化数据,只格式化一次;动态数据todo const options = useMemo(() => { @@ -117,8 +114,6 @@ export const ElevatorRender: FunctionComponent< return transformData(currOptions) }, [innerOptions, optionKey, format]) - const [elevatorOptions, setElevatorOptions] = useState([]) - useEffect(() => { setElevatorOptions(options) }, [options]) @@ -177,7 +172,7 @@ export const ElevatorRender: FunctionComponent< }, [innerValue]) const handleElevatorItemClick = ( - elevatorItem: AreaInfo, + elevatorItem: RegionData, levelIndex: number ) => { // if (elevatorItem?.disabled) return @@ -187,8 +182,7 @@ export const ElevatorRender: FunctionComponent< } if (elevatorItem.children?.length) { setElevatorOptions(elevatorItem.children) - const distIndex = levelIndex + 1 - setLevelIndex(distIndex) + setLevelIndex(levelIndex + 1) } else { setVisible(false) setValue(nextValue) diff --git a/src/types/spec/address/base.ts b/src/types/spec/address/base.ts index e4ef3a5f5f..e3e0432f83 100644 --- a/src/types/spec/address/base.ts +++ b/src/types/spec/address/base.ts @@ -69,6 +69,7 @@ export interface BaseAddress { defaultIcon: React.ReactNode selectIcon: React.ReactNode backIcon: React.ReactNode + hotList: RegionData[] onSwitch?: (data: { type: string }) => void onExistSelect?: (data: AddressList) => void } From c049920173310639288d004656c0901a56d8a0a6 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Fri, 18 Apr 2025 15:22:59 +0800 Subject: [PATCH 09/22] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E6=9F=90?= =?UTF-8?q?=E4=BA=9B=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/elevatorRender.taro.tsx | 70 ++++++++--------- src/packages/address/elevatorRender.tsx | 79 +++++++++----------- 2 files changed, 69 insertions(+), 80 deletions(-) diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index 8b6ed38d41..3044af9f9c 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -87,8 +87,6 @@ export const ElevatorRender: FunctionComponent< } = useConfig() const classPrefix = 'nut-address' - const [tabActiveIndex, setTabActiveIndex] = useState(0) - const [innerOptions, setInnerOptions] = useState(outerOptions) const [value, setValue] = usePropsValue({ value: outerValue, defaultValue: outerDefaultValue, @@ -99,9 +97,12 @@ export const ElevatorRender: FunctionComponent< }, }) + const [innerOptions, setInnerOptions] = useState(outerOptions) const [innerValue, setInnerValue] = useState(value) + const [elevatorOptions, setElevatorOptions] = useState([]) const [addressTip, setAddressTip] = useState(selectProvice) const [levelIndex, setLevelIndex] = useState(0) + const [tabActiveIndex, setTabActiveIndex] = useState(0) // 初始化数据,只格式化一次;动态数据todo const options = useMemo(() => { @@ -114,8 +115,6 @@ export const ElevatorRender: FunctionComponent< return transformData(innerOptions) }, [innerOptions, optionKey, format]) - const [elevatorOptions, setElevatorOptions] = useState(options) - useEffect(() => { setElevatorOptions(options) }, [options]) @@ -145,6 +144,8 @@ export const ElevatorRender: FunctionComponent< next.push({ name: null, children: currentOptions, + levels: -1, + current: false, }) } return next @@ -154,9 +155,7 @@ export const ElevatorRender: FunctionComponent< value: outerVisible, defaultValue: undefined, onChange: (value) => { - if (value === false) { - onClose() - } + if (value === false) onClose() }, }) @@ -182,6 +181,7 @@ export const ElevatorRender: FunctionComponent< if (elevatorItem.name) { nextValue[levelIndex] = elevatorItem.name } + setInnerValue(nextValue) if (elevatorItem.children?.length) { setElevatorOptions(elevatorItem.children) setLevelIndex(levelIndex + 1) @@ -189,7 +189,6 @@ export const ElevatorRender: FunctionComponent< setVisible(false) setValue(nextValue) } - setInnerValue(nextValue) } const handleHotItemClick = (hotItem: any) => { @@ -210,14 +209,13 @@ export const ElevatorRender: FunctionComponent< return ( {levels.map((item, index) => ( - <> + {item.name && ( { - props.onTabsChange?.(Number(index)) - setTabActiveIndex(Number(index)) + props.onTabsChange?.(index) + setTabActiveIndex(index) setLevelIndex(index) setElevatorOptions(item.children) }} @@ -228,14 +226,14 @@ export const ElevatorRender: FunctionComponent< {levels[index + 1]?.name && ( - )} - + ))} ) } const renderHotCity = () => { - if (levels.length && tabActiveIndex !== 0) return + if (levels.length && tabActiveIndex !== 0) return null return ( <> {hotCity} @@ -254,31 +252,27 @@ export const ElevatorRender: FunctionComponent< ) } - const renderArea = () => { - return ( - <> - {addressTip} - - handleElevatorItemClick(item, levelIndex) - } - height="300px" - /> - - ) - } + const renderArea = () => ( + <> + {addressTip} + + handleElevatorItemClick(item, levelIndex) + } + height="300px" + /> + + ) - const renderContent = () => { - return ( - <> - {renderTabs()} - {renderHotCity()} - {renderArea()} - - ) - } + const renderContent = () => ( + <> + {renderTabs()} + {renderHotCity()} + {renderArea()} + + ) return popup ? ( { - let currOptions = innerOptions if (!isEmpty(format)) { - currOptions = normalizeListOptions(innerOptions, format) - } else if (!isEmpty(optionKey)) { - currOptions = normalizeOptions(innerOptions, optionKey) || [] + return transformData(normalizeListOptions(innerOptions, format)) } - return transformData(currOptions) + if (!isEmpty(optionKey)) { + return transformData(normalizeOptions(innerOptions, optionKey) || []) + } + return transformData(innerOptions) }, [innerOptions, optionKey, format]) useEffect(() => { setElevatorOptions(options) }, [options]) - const levels: any[] = useMemo(() => { + const levels = useMemo(() => { const next = [] let end = false let currentOptions = options - for (const [index, val] of innerValue.entries()) { + innerValue.forEach((val, index) => { const opt = currentOptions ?.flatMap((o: any) => o.list.find((item: any) => item.name === val)) .filter((item) => item !== undefined)[0] @@ -138,11 +138,13 @@ export const ElevatorRender: FunctionComponent< } else { end = true } - } + }) if (!end) { next.push({ name: null, children: currentOptions, + levels: -1, + current: false, }) } return next @@ -152,9 +154,7 @@ export const ElevatorRender: FunctionComponent< value: outerVisible, defaultValue: undefined, onChange: (value) => { - if (value === false) { - onClose() - } + if (value === false) onClose() }, }) @@ -180,6 +180,7 @@ export const ElevatorRender: FunctionComponent< if (elevatorItem.name) { nextValue[levelIndex] = elevatorItem.name } + setInnerValue(nextValue) if (elevatorItem.children?.length) { setElevatorOptions(elevatorItem.children) setLevelIndex(levelIndex + 1) @@ -187,7 +188,6 @@ export const ElevatorRender: FunctionComponent< setVisible(false) setValue(nextValue) } - setInnerValue(nextValue) } const handleHotItemClick = (hotItem: any) => { @@ -208,14 +208,13 @@ export const ElevatorRender: FunctionComponent< return (
{levels.map((item, index) => ( - <> + {item.name && (
{ - props.onTabsChange?.(Number(index)) - setTabActiveIndex(Number(index)) + props.onTabsChange?.(index) + setTabActiveIndex(index) setLevelIndex(index) setElevatorOptions(item.children) }} @@ -226,14 +225,14 @@ export const ElevatorRender: FunctionComponent< {levels[index + 1]?.name && (
-
)} - + ))}
) } const renderHotCity = () => { - if (levels.length && tabActiveIndex !== 0) return + if (levels.length && tabActiveIndex !== 0) return null return ( <>
{hotCity}
@@ -252,31 +251,27 @@ export const ElevatorRender: FunctionComponent< ) } - const renderArea = () => { - return ( - <> -
{addressTip}
- - handleElevatorItemClick(item, levelIndex) - } - height="300px" - /> - - ) - } + const renderArea = () => ( + <> +
{addressTip}
+ + handleElevatorItemClick(item, levelIndex) + } + height="300px" + /> + + ) - const renderContent = () => { - return ( - <> - {renderTabs()} - {renderHotCity()} - {renderArea()} - - ) - } + const renderContent = () => ( + <> + {renderTabs()} + {renderHotCity()} + {renderArea()} + + ) return popup ? ( Date: Sun, 27 Apr 2025 15:15:46 +0800 Subject: [PATCH 10/22] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/nutui-taro-demo/src/pages/index/index.tsx | 2 +- src/config.json | 6 +++--- src/packages/address/address.scss | 5 ----- src/packages/address/address.taro.tsx | 6 +++--- src/packages/address/address.tsx | 6 +++--- src/packages/address/elevator.scss | 1 - 6 files changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/nutui-taro-demo/src/pages/index/index.tsx b/packages/nutui-taro-demo/src/pages/index/index.tsx index 00a634b55b..3c62071dce 100644 --- a/packages/nutui-taro-demo/src/pages/index/index.tsx +++ b/packages/nutui-taro-demo/src/pages/index/index.tsx @@ -82,7 +82,7 @@ const Index = () => { )} {nav.packages.map((com) => - com.show && com.taro && (harmony() ? com.dd : true) && (!search || new RegExp(search, 'ig').test(com.name.toLowerCase())) ? ( + com.show && com.taro && (!search || new RegExp(search, 'ig').test(com.name.toLowerCase())) ? ( { setInnerVisible(false) - onClose && onClose() + onClose() } const renderLeftOnCustomSwitch = () => { @@ -143,7 +143,7 @@ const InternalAddress: ForwardRefRenderFunction< height={height} onClose={handleClose} onChange={(val: CascaderValue, params?: any) => { - onChange?.(val, params) + onChange(val, params) }} /> ) @@ -164,7 +164,7 @@ const InternalAddress: ForwardRefRenderFunction< height={height} onClose={handleClose} onChange={(val: CascaderValue, params?: any) => { - onChange?.(val, params) + onChange(val, params) }} /> ) diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index b8429d0e41..c7dbc82278 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -93,7 +93,7 @@ export const InternalAddress: ForwardRefRenderFunction< const handleClose = () => { setInnerVisible(false) - onClose && onClose() + onClose() } const renderLeftOnCustomSwitch = () => { @@ -142,7 +142,7 @@ export const InternalAddress: ForwardRefRenderFunction< height={height} onClose={handleClose} onChange={(val: CascaderValue, params?: any) => { - onChange?.(val, params) + onChange(val, params) }} /> ) @@ -163,7 +163,7 @@ export const InternalAddress: ForwardRefRenderFunction< height={height} onClose={handleClose} onChange={(val: CascaderValue, params?: any) => { - onChange?.(val, params) + onChange(val, params) }} /> ) diff --git a/src/packages/address/elevator.scss b/src/packages/address/elevator.scss index 5316433397..f6c390009f 100644 --- a/src/packages/address/elevator.scss +++ b/src/packages/address/elevator.scss @@ -39,7 +39,6 @@ height: 60px; padding: 0 16px; display: flex; - flex-wrap: wrap; align-items: center; border-bottom: 1px solid $color-border; &-item { From 624be138aaeb0cc662e64aeb92a880cc7dcde50d Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Sun, 27 Apr 2025 17:03:29 +0800 Subject: [PATCH 11/22] =?UTF-8?q?fix:=20=E9=B8=BF=E8=92=99=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/elevator.scss | 19 ++++++++++++++----- src/packages/address/elevatorRender.taro.tsx | 5 ++++- src/packages/address/elevatorRender.tsx | 5 ++++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/packages/address/elevator.scss b/src/packages/address/elevator.scss index f6c390009f..6a8f3c3005 100644 --- a/src/packages/address/elevator.scss +++ b/src/packages/address/elevator.scss @@ -11,8 +11,7 @@ padding: 0 16px; display: flex; flex-wrap: wrap; - justify-content: flex-start; - align-items: left; + align-items: flex-start; &-item { display: flex; justify-content: center; @@ -22,15 +21,25 @@ font-size: 12px; border-radius: 4px; margin-bottom: 7px; + /* #ifdef harmony*/ + margin-right: 6px; + /* #endif */ + /* #ifndef harmony*/ + margin-right: 7px; + /* #endif */ background-color: $color-background-sunken; color: $color-title; - &:last-child { + &:nth-child(5n) { margin-right: 0; } } - &:has(.nut-address-hotlist-item:nth-child(5)) { - justify-content: space-between; + &.hotlist-more { + .nut-address-hotlist-item { + width: auto; + padding: 0 16px; + margin-right: 7px; + } } } diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index 3044af9f9c..f8ceaadf34 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -86,6 +86,7 @@ export const ElevatorRender: FunctionComponent< }, } = useConfig() const classPrefix = 'nut-address' + const MAX_LENGTH = 10 const [value, setValue] = usePropsValue({ value: outerValue, @@ -237,7 +238,9 @@ export const ElevatorRender: FunctionComponent< return ( <> {hotCity} - + MAX_LENGTH ? 'hotlist-more' : ''}`} + > {hotList.map((item, index) => (
{hotCity}
-
+
MAX_LENGTH ? 'hotlist-more' : ''}`} + > {hotList.map((item, index) => (
Date: Sun, 27 Apr 2025 21:02:45 +0800 Subject: [PATCH 12/22] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E5=B1=95=E7=A4=BA=E6=BB=9A=E5=8A=A8=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/demos/h5/demo11.tsx | 20 ++++++++++++++++++++ src/packages/address/demos/taro/demo11.tsx | 20 ++++++++++++++++++++ src/packages/address/elevatorRender.taro.tsx | 20 ++++++++++++++------ src/packages/address/elevatorRender.tsx | 19 +++++++++++++------ 4 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/packages/address/demos/h5/demo11.tsx b/src/packages/address/demos/h5/demo11.tsx index 6f851aa045..db8ebdb35a 100644 --- a/src/packages/address/demos/h5/demo11.tsx +++ b/src/packages/address/demos/h5/demo11.tsx @@ -223,6 +223,16 @@ const Demo1 = () => { wordCode: 'H', disabled: true, }, + { + value: '山东', + text: '山东', + wordCode: 'S', + }, + { + value: '山西', + text: '山西', + wordCode: 'S', + }, { value: '上海', text: '上海', @@ -260,6 +270,16 @@ const Demo1 = () => { }, ], }, + { + value: '陕西', + text: '陕西', + wordCode: 'S', + }, + { + value: '四川', + text: '四川', + wordCode: 'S', + }, { value: '浙江', text: '浙江', diff --git a/src/packages/address/demos/taro/demo11.tsx b/src/packages/address/demos/taro/demo11.tsx index 57f69cd7a7..8b64c6507e 100644 --- a/src/packages/address/demos/taro/demo11.tsx +++ b/src/packages/address/demos/taro/demo11.tsx @@ -223,6 +223,16 @@ const Demo1 = () => { wordCode: 'H', disabled: true, }, + { + value: '山东', + text: '山东', + wordCode: 'S', + }, + { + value: '山西', + text: '山西', + wordCode: 'S', + }, { value: '上海', text: '上海', @@ -260,6 +270,16 @@ const Demo1 = () => { }, ], }, + { + value: '陕西', + text: '陕西', + wordCode: 'S', + }, + { + value: '四川', + text: '四川', + wordCode: 'S', + }, { value: '浙江', text: '浙江', diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index f8ceaadf34..075e55ab6c 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -2,7 +2,7 @@ import React, { FunctionComponent, useEffect, useMemo, useState } from 'react' import { View } from '@tarojs/components' import Popup from '@/packages/popup/index.taro' -import Elevator from '../elevator/index.taro' +import Elevator from '@/packages/elevator/index.taro' import { normalizeListOptions, normalizeOptions, @@ -177,7 +177,6 @@ export const ElevatorRender: FunctionComponent< elevatorItem: RegionData, levelIndex: number ) => { - // if (elevatorItem?.disabled) return const nextValue = innerValue.slice(0, levelIndex) if (elevatorItem.name) { nextValue[levelIndex] = elevatorItem.name @@ -264,7 +263,9 @@ export const ElevatorRender: FunctionComponent< onItemClick={(key: string, item: any) => handleElevatorItemClick(item, levelIndex) } - height="300px" + // height="67%" + style={{ height: '100%' }} + height="93%" /> ) @@ -272,8 +273,15 @@ export const ElevatorRender: FunctionComponent< const renderContent = () => ( <> {renderTabs()} - {renderHotCity()} - {renderArea()} + + {renderHotCity()} + {renderArea()} + ) @@ -282,7 +290,7 @@ export const ElevatorRender: FunctionComponent< {...popupProps} visible={visible} position="bottom" - style={{ height: '87%' }} + style={{ height: '89%' }} round closeIcon={closeIcon} closeable={closeable} diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index 9bf8c9d59d..3284fc8664 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -1,7 +1,7 @@ import React, { FunctionComponent, useEffect, useMemo, useState } from 'react' import Popup from '@/packages/popup' -import Elevator from '../elevator' +import Elevator from '@/packages/elevator' import { normalizeListOptions, normalizeOptions, @@ -176,7 +176,6 @@ export const ElevatorRender: FunctionComponent< elevatorItem: RegionData, levelIndex: number ) => { - // if (elevatorItem?.disabled) return const nextValue = innerValue.slice(0, levelIndex) if (elevatorItem.name) { nextValue[levelIndex] = elevatorItem.name @@ -263,7 +262,8 @@ export const ElevatorRender: FunctionComponent< onItemClick={(key: string, item: any) => handleElevatorItemClick(item, levelIndex) } - height="300px" + style={{ height: '100%' }} + height="93%" /> ) @@ -271,8 +271,15 @@ export const ElevatorRender: FunctionComponent< const renderContent = () => ( <> {renderTabs()} - {renderHotCity()} - {renderArea()} +
+ {renderHotCity()} + {renderArea()} +
) @@ -281,7 +288,7 @@ export const ElevatorRender: FunctionComponent< {...popupProps} visible={visible} position="bottom" - style={{ height: '87%' }} + style={{ height: '89%' }} round closeIcon={closeIcon} closeable={closeable} From 7f9e385efda6afe50ed7c225c20ded17f9dfdfd0 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Sun, 27 Apr 2025 21:15:51 +0800 Subject: [PATCH 13/22] test: fixed --- src/packages/address/address.taro.tsx | 19 ++++++++----------- src/packages/address/address.tsx | 19 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/packages/address/address.taro.tsx b/src/packages/address/address.taro.tsx index ce87341b48..6801bc25e2 100644 --- a/src/packages/address/address.taro.tsx +++ b/src/packages/address/address.taro.tsx @@ -94,22 +94,19 @@ const InternalAddress: ForwardRefRenderFunction< const handleClose = () => { setInnerVisible(false) - onClose() + onClose && onClose() } const renderLeftOnCustomSwitch = () => { + if (!custom) return null return ( - <> - {custom && ( - - {React.isValidElement(backIcon) ? ( - backIcon - ) : ( - - )} - + + {React.isValidElement(backIcon) ? ( + backIcon + ) : ( + )} - + ) } diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index c7dbc82278..d9cf0ae89c 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -93,22 +93,19 @@ export const InternalAddress: ForwardRefRenderFunction< const handleClose = () => { setInnerVisible(false) - onClose() + onClose && onClose() } const renderLeftOnCustomSwitch = () => { + if (!custom) return null return ( - <> - {custom && ( -
- {React.isValidElement(backIcon) ? ( - backIcon - ) : ( - - )} -
+
+ {React.isValidElement(backIcon) ? ( + backIcon + ) : ( + )} - +
) } From 3edd64c9fb3bedeaabf2b731dc11a4250158a28b Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Sun, 27 Apr 2025 22:14:40 +0800 Subject: [PATCH 14/22] test: fixed --- .../__snapshots__/address.spec.tsx.snap | 10 +- .../address/__test__/address.spec.tsx | 362 +++++++++++++++++- src/packages/address/address.taro.tsx | 2 +- src/packages/address/address.tsx | 2 +- 4 files changed, 368 insertions(+), 8 deletions(-) diff --git a/src/packages/address/__test__/__snapshots__/address.spec.tsx.snap b/src/packages/address/__test__/__snapshots__/address.spec.tsx.snap index f614bc284b..530c61b4eb 100644 --- a/src/packages/address/__test__/__snapshots__/address.spec.tsx.snap +++ b/src/packages/address/__test__/__snapshots__/address.spec.tsx.snap @@ -2,12 +2,14 @@ exports[`Address: exist defaultIcon & selectIcon 1`] = `"
请选择地址
  • 123
    探探鱼
    182****1718
    北京市次渠镇通州区
  • 123
    探探鱼
    182****1718
    钓鱼岛钓鱼岛全区
  • 456
    探探鱼
    182****1718
    北京市大兴区科创十一街18号院京东大厦
"`; -exports[`Address: show custom 1`] = `"
选择地址
请选择
浙江
湖南
福建
"`; +exports[`Address: show custom false 1`] = `"
选择地址
请选择
浙江
湖南
福建
北京
"`; -exports[`Address: show custom 2`] = `"
选择地址
请选择
浙江
湖南
福建
"`; - -exports[`Address: show custom icon 1`] = `"
选择地址
请选择
浙江
湖南
福建
"`; +exports[`Address: show custom icon 1`] = `"
选择地址
请选择
浙江
湖南
福建
北京
"`; exports[`Address: show custom icon 2`] = `"
请选择地址
  • 探探鱼
    182****1718
    北京市次渠镇通州区
  • 探探鱼
    182****1718
    钓鱼岛钓鱼岛全区
  • 探探鱼
    182****1718
    北京市大兴区科创十一街18号院京东大厦
"`; +exports[`Address: show custom true 1`] = `"
选择地址
请选择
浙江
湖南
福建
北京
"`; + +exports[`Address: show elevator 1`] = `"
选择地址
热门城市
选择省份/地区
A
安徽
B
北京
C
重庆
F
福建
G
贵州
广东
广西
甘肃
H
河北
河南
湖南
湖北
S
山东
山西
上海
陕西
四川
Z
浙江
A
B
C
F
G
H
S
Z
"`; + exports[`Address: show exist 1`] = `"
选择地址
  • 探探鱼
    182****1718
    北京市次渠镇通州区
  • 探探鱼
    182****1718
    钓鱼岛钓鱼岛全区
  • 探探鱼
    182****1718
    北京市大兴区科创十一街18号院京东大厦
"`; diff --git a/src/packages/address/__test__/address.spec.tsx b/src/packages/address/__test__/address.spec.tsx index ae9806b843..c1eb2a5fa7 100644 --- a/src/packages/address/__test__/address.spec.tsx +++ b/src/packages/address/__test__/address.spec.tsx @@ -102,9 +102,329 @@ const optionsDemo1 = [ }, ], }, + { + value: '北京', + text: '北京', + wordCode: 'B', + children: [ + { + value: '朝阳区', + text: '朝阳区', + wordCode: 'C', + }, + { + value: '昌平区', + text: '昌平区', + wordCode: 'C', + }, + { + value: '大兴区', + text: '大兴区', + wordCode: 'D', + }, + { + value: '东城区', + text: '东城区', + wordCode: 'D', + }, + { + value: '房山区', + text: '房山区', + wordCode: 'F', + }, + { + value: '丰台区', + text: '丰台区', + wordCode: 'F', + }, + ], + }, +] + +const hotList = [ + { name: '北京' }, + { name: '上海' }, + { name: '广州' }, + { name: '深圳' }, + { name: '杭州' }, + { name: '南京' }, + { name: '苏州' }, + { name: '天津' }, + { name: '武汉' }, + { name: '长沙' }, ] -test('Address: show custom', async () => { +const elevatorList = [ + { + value: '安徽', + text: '安徽', + wordCode: 'A', + children: [ + { + value: '安庆市', + text: '安庆市', + wordCode: 'A', + disabled: true, + children: [ + { + value: '大观区', + text: '大观区', + disabled: true, + wordCode: 'D', + }, + { value: '怀宁县', text: '怀宁县', wordCode: 'H' }, + { value: '岳西县', text: '岳西县', wordCode: 'Y' }, + { value: '迎江区', text: '迎江区', wordCode: 'Y' }, + { value: '宜秀区', text: '宜秀区', wordCode: 'Y' }, + ], + }, + { + value: '合肥市', + text: '合肥市', + wordCode: 'H', + children: [ + { value: '合肥高新', text: '合肥高新', wordCode: 'H' }, + { value: '合肥经济', text: '合肥经济', wordCode: 'H' }, + ], + }, + { + value: '淮北市', + text: '淮北市', + wordCode: 'H', + children: [ + { value: '杜集区', text: '杜集区', wordCode: 'D' }, + { value: '烈山区', text: '杜集区', wordCode: 'L' }, + ], + }, + { + value: '淮南市', + text: '淮南市', + wordCode: 'H', + children: [{ value: '八公山区', text: '八公山区', wordCode: 'B' }], + }, + { + value: '黄山市', + text: '黄山市', + wordCode: 'H', + children: [ + { value: '黄山区', text: '黄山区', wordCode: 'H' }, + { value: '徽州区', text: '徽州区', wordCode: 'H' }, + ], + }, + ], + }, + { + value: '北京', + text: '北京', + wordCode: 'B', + children: [ + { + value: '朝阳区', + text: '朝阳区', + wordCode: 'C', + }, + { + value: '昌平区', + text: '昌平区', + wordCode: 'C', + }, + { + value: '大兴区', + text: '大兴区', + wordCode: 'D', + }, + { + value: '东城区', + text: '东城区', + wordCode: 'D', + }, + { + value: '房山区', + text: '房山区', + wordCode: 'F', + }, + { + value: '丰台区', + text: '丰台区', + wordCode: 'F', + }, + ], + }, + { + value: '重庆', + text: '重庆', + wordCode: 'C', + }, + { + value: '福建', + text: '福建', + wordCode: 'F', + }, + { + value: '贵州', + text: '贵州', + wordCode: 'G', + }, + { + value: '广东', + text: '广东', + wordCode: 'G', + children: [ + { + value: '广州市', + text: '广州市', + wordCode: 'G', + children: [ + { + value: '白云区', + text: '白云区', + wordCode: 'B', + }, + { + value: '黄埔区', + text: '黄埔区', + wordCode: 'H', + }, + { + value: '花都区', + text: '花都区', + wordCode: 'H', + }, + { + value: '海珠区', + text: '海珠区', + wordCode: 'H', + }, + ], + }, + { + value: '深圳市', + text: '深圳市', + wordCode: 'S', + children: [ + { + value: '宝安区', + text: '宝安区', + wordCode: 'B', + }, + { + value: '罗湖区', + text: '罗湖区', + wordCode: 'L', + }, + { + value: '龙岗区', + text: '龙岗区', + wordCode: 'L', + }, + { + value: '龙华区', + text: '龙华区', + wordCode: 'L', + }, + ], + }, + ], + }, + { + value: '广西', + text: '广西', + wordCode: 'G', + }, + { + value: '甘肃', + text: '甘肃', + wordCode: 'G', + }, + { + value: '河北', + text: '河北', + wordCode: 'H', + disabled: true, + }, + { + value: '河南', + text: '河南', + wordCode: 'H', + disabled: true, + }, + { + value: '湖南', + text: '湖南', + wordCode: 'H', + disabled: true, + }, + { + value: '湖北', + text: '湖北', + wordCode: 'H', + disabled: true, + }, + { + value: '山东', + text: '山东', + wordCode: 'S', + }, + { + value: '山西', + text: '山西', + wordCode: 'S', + }, + { + value: '上海', + text: '上海', + wordCode: 'S', + children: [ + { + value: '宝山区', + text: '宝山区', + wordCode: 'B', + }, + { + value: '黄埔区', + text: '黄埔区', + wordCode: 'H', + }, + { + value: '虹口区', + text: '虹口区', + wordCode: 'H', + }, + { + value: '嘉定区', + text: '嘉定区', + wordCode: 'J', + }, + { + value: '静安区', + text: '静安区', + wordCode: 'J', + }, + { + value: '金山区', + text: '金山区', + wordCode: 'J', + }, + ], + }, + { + value: '陕西', + text: '陕西', + wordCode: 'S', + }, + { + value: '四川', + text: '四川', + wordCode: 'S', + }, + { + value: '浙江', + text: '浙江', + wordCode: 'Z', + }, +] + +test('Address: show custom false', async () => { const { container } = render(
) @@ -118,13 +438,51 @@ test('Address: show custom', async () => { expect(container.innerHTML).toMatchSnapshot() }) -test('Address: show custom', async () => { +test('Address: show custom true', async () => { const { container } = render(
) expect(container.innerHTML).toMatchSnapshot() }) +test('Address: show elevator', async () => { + const { container } = render( +
+ ) + expect(container.innerHTML).toMatchSnapshot() + + const elevatorContainer = container.querySelectorAll( + '.nut-elevator-list-item-name' + ) + fireEvent.click(elevatorContainer[8]) + await waitFor(() => { + const selected = container.querySelector('.nut-address-selected-item') + expect(selected?.innerHTML).toBe('河北') + }) +}) + +test('Address: show elevator hotlist', async () => { + const { container } = render( +
+ ) + const hotitems = container.querySelectorAll('.nut-address-hotlist-item') + expect(hotitems.length).toBe(10) + expect(hotitems[0]).toHaveTextContent('北京') + fireEvent.click(hotitems[0]) + await waitFor(() => { + const hotitems = container.querySelectorAll('.nut-address-hotlist-item') + expect(hotitems.length).toBe(0) + const selected = container.querySelectorAll('.nut-address-selected-item') + expect(selected?.length).toBe(1) + }) +}) + test('Address: show custom icon', async () => { const { container } = render(
{ - onChange(val, params) + onChange?.(val, params) }} /> ) diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index d9cf0ae89c..1644e49c8b 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -139,7 +139,7 @@ export const InternalAddress: ForwardRefRenderFunction< height={height} onClose={handleClose} onChange={(val: CascaderValue, params?: any) => { - onChange(val, params) + onChange?.(val, params) }} /> ) From 3b8669f29e2471bc8d0af3a970ad324b20d0305b Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Sun, 27 Apr 2025 22:40:32 +0800 Subject: [PATCH 15/22] fix: build error --- scripts/build-taro.mjs | 7 ------- src/packages/address/elevatorRender.taro.tsx | 2 +- src/packages/cascader/cascader.taro.tsx | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/scripts/build-taro.mjs b/scripts/build-taro.mjs index 17489af0d4..2c8856f089 100644 --- a/scripts/build-taro.mjs +++ b/scripts/build-taro.mjs @@ -428,13 +428,6 @@ async function buildCSS(themeName = '') { join(`${dist}/cjs`, cssPath, `${themeDir}/css.js`), cssContent.join('\n'), ) - - // copy harmonycss - if (file.indexOf('countup') === -1) { - const harmonyCss = join(__dirname, '../', file.replace('scss', 'harmony.css')) - await copy(harmonyCss, join(`${dist}/cjs`, cssPath, 'style/style.harmony.css')) - await copy(harmonyCss, join(`${dist}/es`, cssPath, 'style/style.harmony.css')) - } } } diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index 075e55ab6c..b7a586f6bc 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -19,7 +19,7 @@ import { ComponentDefaults } from '@/utils/typings' import { mergeProps } from '@/utils/merge-props' import { usePropsValue } from '@/hooks/use-props-value' import { isEmpty } from '@/utils/is-empty' -import { useConfig } from '@/packages/configprovider' +import { useConfig } from '@/packages/configprovider/index.taro' export interface AddressProps extends WebCascaderProps { visible: boolean // popup visible diff --git a/src/packages/cascader/cascader.taro.tsx b/src/packages/cascader/cascader.taro.tsx index fec6ebcef9..5267433cc1 100644 --- a/src/packages/cascader/cascader.taro.tsx +++ b/src/packages/cascader/cascader.taro.tsx @@ -22,7 +22,7 @@ import { mergeProps } from '@/utils/merge-props' import { usePropsValue } from '@/hooks/use-props-value' import { isEmpty } from '@/utils/is-empty' import { getRefValue, useRefState } from '@/hooks/use-ref-state' -import { useConfig } from '@/packages/configprovider' +import { useConfig } from '@/packages/configprovider/index.taro' const defaultProps: TaroCascaderProps = { ...ComponentDefaults, From 529b0d4f412b00da2b6f82176eadd63fe230590c Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Mon, 28 Apr 2025 20:10:03 +0800 Subject: [PATCH 16/22] fix: spell error --- src/locales/base.ts | 2 +- src/locales/en-US.ts | 2 +- src/locales/id-ID.ts | 2 +- src/locales/tr-TR.ts | 2 +- src/locales/zh-CN.ts | 2 +- src/locales/zh-TW.ts | 2 +- src/locales/zh-UG.ts | 2 +- src/packages/address/elevatorRender.taro.tsx | 6 +++--- src/packages/address/elevatorRender.tsx | 6 +++--- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/locales/base.ts b/src/locales/base.ts index a79f62c2bf..7e59cf6ca2 100644 --- a/src/locales/base.ts +++ b/src/locales/base.ts @@ -66,7 +66,7 @@ export interface BaseLang { deliveryTo: string chooseAnotherAddress: string hotCity: string - selectProvice: string + selectProvince: string } signature: { reSign: string diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index 126e98b687..a6f74b483b 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -66,7 +66,7 @@ const enUS: BaseLang = { deliveryTo: 'Delivery To', chooseAnotherAddress: 'Choose Another Address', hotCity: 'Hot City', - selectProvice: 'Choose Provice or City', + selectProvince: 'Choose Province or City', }, signature: { reSign: 'Re Sign', diff --git a/src/locales/id-ID.ts b/src/locales/id-ID.ts index 222bad6805..61e56eeef0 100644 --- a/src/locales/id-ID.ts +++ b/src/locales/id-ID.ts @@ -67,7 +67,7 @@ const idID: BaseLang = { deliveryTo: 'Kirim Ke', chooseAnotherAddress: 'Pilih alamat lain', hotCity: 'Kota-kota populer', - selectProvice: 'Pilih provinsi/wilayah', + selectProvince: 'Pilih provinsi/wilayah', }, signature: { reSign: 'Masuk Kembali', diff --git a/src/locales/tr-TR.ts b/src/locales/tr-TR.ts index 5fecdf82c2..6083b18acb 100644 --- a/src/locales/tr-TR.ts +++ b/src/locales/tr-TR.ts @@ -75,7 +75,7 @@ const trTR: BaseLang = { deliveryTo: 'Teslimat yeri', chooseAnotherAddress: 'Başka bir adres seçin', hotCity: 'Popüler şehirler', - selectProvice: 'İl/bölge seçin', + selectProvince: 'İl/bölge seçin', }, signature: { reSign: 'Yeniden imzala', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 635d664884..0c23f5fd6c 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -68,7 +68,7 @@ const zhCN: BaseLang = { deliveryTo: '配送至', chooseAnotherAddress: '选择其他地址', hotCity: '热门城市', - selectProvice: '选择省份/地区', + selectProvince: '选择省份/地区', }, signature: { reSign: '重签', diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index ced63b0587..2beddaa696 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -68,7 +68,7 @@ const zhCN: BaseLang = { deliveryTo: '配送至', chooseAnotherAddress: '選擇其他地址', hotCity: '熱門城市', - selectProvice: '選擇省份/地區', + selectProvince: '選擇省份/地區', }, signature: { reSign: '重簽', diff --git a/src/locales/zh-UG.ts b/src/locales/zh-UG.ts index c8122f9334..f604791f32 100644 --- a/src/locales/zh-UG.ts +++ b/src/locales/zh-UG.ts @@ -66,7 +66,7 @@ const zhUG: BaseLang = { deliveryTo: 'قەيەرگە', chooseAnotherAddress: 'باشقىنى تاللاش', hotCity: 'ئاۋات شەھەرلەر', - selectProvice: 'ئۆلكە / شەھەرنى تاللاڭ', + selectProvince: 'ئۆلكە / شەھەرنى تاللاڭ', }, signature: { reSign: 'قايتا', diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index b7a586f6bc..5186cdedf2 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -82,7 +82,7 @@ export const ElevatorRender: FunctionComponent< const { locale: { select, - address: { hotCity, selectProvice }, + address: { hotCity, selectProvince }, }, } = useConfig() const classPrefix = 'nut-address' @@ -101,7 +101,7 @@ export const ElevatorRender: FunctionComponent< const [innerOptions, setInnerOptions] = useState(outerOptions) const [innerValue, setInnerValue] = useState(value) const [elevatorOptions, setElevatorOptions] = useState([]) - const [addressTip, setAddressTip] = useState(selectProvice) + const [addressTip, setAddressTip] = useState(selectProvince) const [levelIndex, setLevelIndex] = useState(0) const [tabActiveIndex, setTabActiveIndex] = useState(0) @@ -170,7 +170,7 @@ export const ElevatorRender: FunctionComponent< useEffect(() => { setTabActiveIndex(levels.length - 1) - setAddressTip(innerValue.length ? select : selectProvice) + setAddressTip(innerValue.length ? select : selectProvince) }, [innerValue]) const handleElevatorItemClick = ( diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index 3284fc8664..7aaccbbba2 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -81,7 +81,7 @@ export const ElevatorRender: FunctionComponent< const { locale: { select, - address: { hotCity, selectProvice }, + address: { hotCity, selectProvince }, }, } = useConfig() const classPrefix = 'nut-address' @@ -100,7 +100,7 @@ export const ElevatorRender: FunctionComponent< const [innerOptions, setInnerOptions] = useState(outerOptions) const [innerValue, setInnerValue] = useState(value) const [elevatorOptions, setElevatorOptions] = useState([]) - const [addressTip, setAddressTip] = useState(selectProvice) + const [addressTip, setAddressTip] = useState(selectProvince) const [levelIndex, setLevelIndex] = useState(0) const [tabActiveIndex, setTabActiveIndex] = useState(0) @@ -169,7 +169,7 @@ export const ElevatorRender: FunctionComponent< useEffect(() => { setTabActiveIndex(levels.length - 1) - setAddressTip(innerValue.length ? select : selectProvice) + setAddressTip(innerValue.length ? select : selectProvince) }, [innerValue]) const handleElevatorItemClick = ( From 2b92cfd6590f35cc8c677c15eaf47d235758dc0b Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Tue, 29 Apr 2025 10:34:31 +0800 Subject: [PATCH 17/22] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=8F=8A=E7=9B=B8=E5=85=B3=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/address.spec.tsx.snap | 2 +- src/packages/address/__test__/address.spec.tsx | 2 +- src/packages/address/address.taro.tsx | 16 ++++++++-------- src/packages/address/address.tsx | 16 ++++++++-------- ...Render.taro.tsx => cascaderRender.taro.tsx} | 6 +++--- .../{customRender.tsx => cascaderRender.tsx} | 6 +++--- src/packages/address/demo.taro.tsx | 10 +++++----- src/packages/address/demo.tsx | 12 ++++++------ src/packages/address/demos/h5/demo5.tsx | 2 +- src/packages/address/doc.en-US.md | 2 +- src/packages/address/doc.md | 2 +- src/packages/address/doc.taro.md | 2 +- src/packages/address/doc.zh-TW.md | 2 +- src/packages/address/existRender.taro.tsx | 4 ++-- src/packages/address/existRender.tsx | 4 ++-- .../doc/docs/react/migrate-from-v2.md | 6 +++++- src/types/spec/address/base.ts | 18 +++--------------- 17 files changed, 52 insertions(+), 60 deletions(-) rename src/packages/address/{customRender.taro.tsx => cascaderRender.taro.tsx} (94%) rename src/packages/address/{customRender.tsx => cascaderRender.tsx} (94%) diff --git a/src/packages/address/__test__/__snapshots__/address.spec.tsx.snap b/src/packages/address/__test__/__snapshots__/address.spec.tsx.snap index 530c61b4eb..c788efdf28 100644 --- a/src/packages/address/__test__/__snapshots__/address.spec.tsx.snap +++ b/src/packages/address/__test__/__snapshots__/address.spec.tsx.snap @@ -2,7 +2,7 @@ exports[`Address: exist defaultIcon & selectIcon 1`] = `"
请选择地址
  • 123
    探探鱼
    182****1718
    北京市次渠镇通州区
  • 123
    探探鱼
    182****1718
    钓鱼岛钓鱼岛全区
  • 456
    探探鱼
    182****1718
    北京市大兴区科创十一街18号院京东大厦
"`; -exports[`Address: show custom false 1`] = `"
选择地址
请选择
浙江
湖南
福建
北京
"`; +exports[`Address: show cascader false 1`] = `"
选择地址
请选择
浙江
湖南
福建
北京
"`; exports[`Address: show custom icon 1`] = `"
选择地址
请选择
浙江
湖南
福建
北京
"`; diff --git a/src/packages/address/__test__/address.spec.tsx b/src/packages/address/__test__/address.spec.tsx index c1eb2a5fa7..41a6b1761c 100644 --- a/src/packages/address/__test__/address.spec.tsx +++ b/src/packages/address/__test__/address.spec.tsx @@ -424,7 +424,7 @@ const elevatorList = [ }, ] -test('Address: show custom false', async () => { +test('Address: show cascader false', async () => { const { container } = render(
) diff --git a/src/packages/address/address.taro.tsx b/src/packages/address/address.taro.tsx index 14d5b6f7f1..af2d1ec4ad 100644 --- a/src/packages/address/address.taro.tsx +++ b/src/packages/address/address.taro.tsx @@ -9,7 +9,7 @@ import { ArrowLeft } from '@nutui/icons-react-taro' import Popup from '@/packages/popup/index.taro' import { ExistRender } from './existRender.taro' import { ElevatorRender } from './elevatorRender.taro' -import { CustomRender } from './customRender.taro' +import { CascaderRender } from './CascaderRender.taro' import { useConfig } from '@/packages/configprovider/index.taro' import { ComponentDefaults } from '@/utils/typings' import { usePropsValue } from '@/hooks/use-props-value' @@ -24,7 +24,7 @@ import { mergeProps } from '@/utils/merge-props' const defaultProps = { ...ComponentDefaults, defaultValue: [], - type: 'custom', + type: 'cascader', options: [], optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, format: {}, @@ -97,7 +97,7 @@ const InternalAddress: ForwardRefRenderFunction< onClose && onClose() } - const renderLeftOnCustomSwitch = () => { + const renderLeftOnCascaderSwitch = () => { if (!custom) return null return ( @@ -117,7 +117,7 @@ const InternalAddress: ForwardRefRenderFunction< const onSwitchModule = () => { if (currentType === 'exist') { - setCurrentType('custom') + setCurrentType('cascader') } else { setCurrentType('exist') } @@ -129,7 +129,7 @@ const InternalAddress: ForwardRefRenderFunction< visible={innerVisible} closeable title={title || locale.address.selectRegion} - left={renderLeftOnCustomSwitch()} + left={renderLeftOnCascaderSwitch()} defaultValue={defaultValue} closeIcon={closeIcon} options={options} @@ -147,11 +147,11 @@ const InternalAddress: ForwardRefRenderFunction< } const renderCascator = () => { return ( - {currentType === 'elevator' ? renderElevator() : null} - {currentType === 'custom' ? renderCascator() : null} + {currentType === 'cascader' ? renderCascator() : null} {currentType === 'exist' ? renderExist() : null} ) diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index 1644e49c8b..0cb00a3d32 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -6,7 +6,7 @@ import React, { } from 'react' import { ArrowLeft } from '@nutui/icons-react' import Popup from '@/packages/popup' -import { CustomRender } from './customRender' +import { CascaderRender } from './cascaderRender' import { ElevatorRender } from './elevatorRender' import { ExistRender } from './existRender' import { useConfig } from '@/packages/configprovider' @@ -23,7 +23,7 @@ import { mergeProps } from '@/utils/merge-props' const defaultProps = { ...ComponentDefaults, defaultValue: [], - type: 'custom', + type: 'cascader', options: [], optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, format: {}, @@ -96,7 +96,7 @@ export const InternalAddress: ForwardRefRenderFunction< onClose && onClose() } - const renderLeftOnCustomSwitch = () => { + const renderLeftOnCascaderSwitch = () => { if (!custom) return null return (
@@ -116,7 +116,7 @@ export const InternalAddress: ForwardRefRenderFunction< const onSwitchModule = () => { if (currentType === 'exist') { - setCurrentType('custom') + setCurrentType('cascader') } else { setCurrentType('exist') } @@ -128,7 +128,7 @@ export const InternalAddress: ForwardRefRenderFunction< visible={innerVisible} closeable title={title || locale.address.selectRegion} - left={renderLeftOnCustomSwitch()} + left={renderLeftOnCascaderSwitch()} defaultValue={defaultValue} closeIcon={closeIcon} options={options} @@ -146,11 +146,11 @@ export const InternalAddress: ForwardRefRenderFunction< } const renderCascator = () => { return ( - {currentType === 'elevator' ? renderElevator() : null} - {currentType === 'custom' ? renderCascator() : null} + {currentType === 'cascader' ? renderCascator() : null} {currentType === 'exist' ? renderExist() : null} ) diff --git a/src/packages/address/customRender.taro.tsx b/src/packages/address/cascaderRender.taro.tsx similarity index 94% rename from src/packages/address/customRender.taro.tsx rename to src/packages/address/cascaderRender.taro.tsx index ab2fd80289..797a93932c 100644 --- a/src/packages/address/customRender.taro.tsx +++ b/src/packages/address/cascaderRender.taro.tsx @@ -22,14 +22,14 @@ export interface AddressProps extends TaroCascaderProps { const defaultProps = { ...ComponentDefaults, visible: false, - type: 'custom', + type: 'cascader', options: [], optionKey: { textKey: 'text', valueKey: 'value', childrenKey: 'children' }, format: {}, height: '200px', } as unknown as AddressProps -export const CustomRender: FunctionComponent< +export const CascaderRender: FunctionComponent< Partial & Omit< React.HTMLAttributes, @@ -59,7 +59,7 @@ export const CustomRender: FunctionComponent< return ( <> - {type === 'custom' && ( + {type === 'cascader' && ( & Omit< React.HTMLAttributes, @@ -59,7 +59,7 @@ export const CustomRender: FunctionComponent< return ( <> - {type === 'custom' && ( + {type === 'cascader' && ( { const [translated] = useTranslate({ 'zh-CN': { - elevator: '电梯地址', - customAddress: '选择自定义地址', + elevator: '电梯方式的地址展示', + cascaderAddress: '级联方式的地址展示', selectCity: '选中省市区', existList: '选择已有地址', customIcon: '自定义图标', @@ -23,8 +23,8 @@ const AddressDemo = () => { uncontrolled: '非受控方式', }, 'zh-TW': { - elevator: '电梯地址', - customAddress: '選擇自定義地址', + elevator: '電梯方式的地址展示', + cascaderAddress: '級聯方式的地址展示', selectCity: '選中省市區', existList: '選擇已有地址', customIcon: '自定義圖標', @@ -33,7 +33,7 @@ const AddressDemo = () => { }, 'en-US': { elevator: 'Elevator Address', - customAddress: 'Choose Custom Address', + cascaderAddress: 'Choose Cascader Address', selectCity: 'Choose City', existList: 'Choose Exist Address', customIcon: 'Custom Icon', diff --git a/src/packages/address/demo.tsx b/src/packages/address/demo.tsx index 57209eb510..a775a40e5a 100644 --- a/src/packages/address/demo.tsx +++ b/src/packages/address/demo.tsx @@ -11,8 +11,8 @@ import Demo11 from './demos/h5/demo11' const AddressDemo = () => { const [translated] = useTranslate({ 'zh-CN': { - elevator: '电梯地址', - customAddress: '选择自定义地址', + elevator: '电梯方式的地址展示', + cascaderAddress: '级联方式的地址展示', selectCity: '选中省市区', existList: '选择已有地址', customIcon: '自定义图标', @@ -20,8 +20,8 @@ const AddressDemo = () => { uncontrolled: '非受控方式', }, 'zh-TW': { - elevator: '电梯地址', - customAddress: '選擇自定義地址', + elevator: '電梯方式的地址展示', + cascaderAddress: '級聯方式的地址展示', selectCity: '選中省市區', existList: '選擇已有地址', customIcon: '自定義圖標', @@ -30,7 +30,7 @@ const AddressDemo = () => { }, 'en-US': { elevator: 'Elevator Address', - customAddress: 'Choose Custom Address', + cascaderAddress: 'Choose Cascader Address', selectCity: 'Choose City', existList: 'Choose Exist Address', customIcon: 'Custom Icon', @@ -44,7 +44,7 @@ const AddressDemo = () => {

{translated.elevator}

-

{translated.customAddress}

+

{translated.cascaderAddress}

{translated.selectCity}

diff --git a/src/packages/address/demos/h5/demo5.tsx b/src/packages/address/demos/h5/demo5.tsx index 158b0320b6..1f9b7cad6a 100644 --- a/src/packages/address/demos/h5/demo5.tsx +++ b/src/packages/address/demos/h5/demo5.tsx @@ -93,7 +93,7 @@ const Demo5 = () => { } const onSwitch = (val: { type: string }) => { - if (val.type === 'custom') { + if (val.type === 'cascader') { console.log('点击了“选择其他地址”按钮') } else { console.log('点击了自定义地址左上角的返回按钮') diff --git a/src/packages/address/doc.en-US.md b/src/packages/address/doc.en-US.md index c257e69381..aa76722e52 100644 --- a/src/packages/address/doc.en-US.md +++ b/src/packages/address/doc.en-US.md @@ -74,7 +74,7 @@ If you want to select a province, you need to set the region ID in the order of | --- | --- | --- | --- | | visible | Whether to open address | `boolean` | `-` | | defaultVisible | Initial open/close state of the address selection | `boolean` | - | -| type | Choose type: exist/custom/elevator | `string` | `custom` | +| type | Choose type: exist/cascader/elevator | `AddressModeType` | `cascader` | | existList | Exist address list data | `Array` | `[]` | | defaultIcon | Exist address default icon | `ReactNode` | `-` | | selectIcon | Exist address selected icon | `ReactNode` | `-` | diff --git a/src/packages/address/doc.md b/src/packages/address/doc.md index 924999e9fa..bce194de03 100644 --- a/src/packages/address/doc.md +++ b/src/packages/address/doc.md @@ -76,7 +76,7 @@ import { Address } from '@nutui/nutui-react' | --- | --- | --- | --- | | visible | 是否打开地址选择 | `boolean` | `-` | | defaultVisible | 初始地址选择打开/关闭状态 | `boolean` | `-` | -| type | 地址选择类型 exist/custom/elevator | `string` | `custom` | +| type | 地址选择类型 exist/cascader/elevator | `AddressModeType` | `cascader` | | existList | 已存在地址列表,每个地址对象中,必传值provinceName、cityName、countyName、townName、addressDetail、selectedAddress(字段解释见下) | `Array` | `[]` | | defaultIcon | 已有地址列表默认图标,type='exist' 时生效 | `ReactNode` | `-` | | selectIcon | 已有地址列表选中图标,type='exist' 时生效 | `ReactNode` | `-` | diff --git a/src/packages/address/doc.taro.md b/src/packages/address/doc.taro.md index 64cee8ec08..b7ebe2daa8 100644 --- a/src/packages/address/doc.taro.md +++ b/src/packages/address/doc.taro.md @@ -76,7 +76,7 @@ import { Address } from '@nutui/nutui-react-taro' | --- | --- | --- | --- | | visible | 是否打开地址选择 | `boolean` | `-` | | defaultVisible | 初始地址选择打开/关闭状态 | `boolean` | `-` | -| type | 地址选择类型 exist/custom/elevator | `string` | `custom` | +| type | 地址选择类型 exist/cascader/elevator | `AddressModeType` | `cascader` | | existList | 已存在地址列表,每个地址对象中,必传值provinceName、cityName、countyName、townName、addressDetail、selectedAddress(字段解释见下) | `Array` | `[]` | | defaultIcon | 已有地址列表默认图标,type='exist' 时生效 | `ReactNode` | `-` | | selectIcon | 已有地址列表选中图标,type='exist' 时生效 | `ReactNode` | `-` | diff --git a/src/packages/address/doc.zh-TW.md b/src/packages/address/doc.zh-TW.md index 2e5c216304..0170788942 100644 --- a/src/packages/address/doc.zh-TW.md +++ b/src/packages/address/doc.zh-TW.md @@ -68,7 +68,7 @@ import { Address } from '@nutui/nutui-react' | --- | --- | --- | --- | | visible | 是否打開地址選擇 | `boolean` | `-` | | defaultVisible | 初始地址選擇打開/關閉狀態 | `boolean` | - | -| type | 地址選擇類型 exist/custom/elevator | `string` | `custom` | +| type | 地址選擇類型 exist/cascader/elevator | `AddressModeType` | `cascader` | | existList | 已存在地址列錶,每個地址對象中,必傳值provinceName、cityName、countyName、townName、addressDetail、selectedAddress(字段解釋見下) | `Array` | `[]` | | defaultIcon | 已有地址列錶默認圖標,type='exist' 時生效 | `ReactNode` | `-` | | selectIcon | 已有地址列錶選中圖標,type='exist' 時生效 | `ReactNode` | `-` | diff --git a/src/packages/address/existRender.taro.tsx b/src/packages/address/existRender.taro.tsx index 8440899125..96cad08658 100644 --- a/src/packages/address/existRender.taro.tsx +++ b/src/packages/address/existRender.taro.tsx @@ -15,7 +15,7 @@ export interface ExistRenderProps { } const defaultProps = { - type: 'custom', + type: 'exist', existList: [], defaultIcon: null, selectIcon: null, @@ -53,7 +53,7 @@ export const ExistRender: FunctionComponent< const onClick = (e: ITouchEvent) => { e.stopPropagation() - onSwitch && onSwitch({ type: type === 'exist' ? 'custom' : 'exist' }) + onSwitch && onSwitch({ type: type === 'exist' ? 'cascader' : 'exist' }) } return ( diff --git a/src/packages/address/existRender.tsx b/src/packages/address/existRender.tsx index 4f25e0c945..5ad19f70f1 100644 --- a/src/packages/address/existRender.tsx +++ b/src/packages/address/existRender.tsx @@ -14,7 +14,7 @@ export interface ExistRenderProps { } const defaultProps = { - type: 'custom', + type: 'exsit', existList: [], defaultIcon: null, selectIcon: null, @@ -52,7 +52,7 @@ export const ExistRender: FunctionComponent< const onClick: MouseEventHandler = (e) => { e.stopPropagation() - onSwitch && onSwitch({ type: type === 'exist' ? 'custom' : 'exist' }) + onSwitch && onSwitch({ type: type === 'exist' ? 'cascader' : 'exist' }) } return ( diff --git a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md index cf2fd267e5..95bd385ef1 100644 --- a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md @@ -149,6 +149,11 @@ plugins: [ ### 数据录入 +#### Address + +- 修订原 type 的类型定义范围,改 `custom` 为 `cascader`,语义化更强;增加 `elevator`,便于快速检索地址。如果没有用到过 `exsit` 与 `custom` 切换逻辑的,理论上无需关注该变化。 +- + [//]: # '#### Calendar' #### Cascader @@ -314,7 +319,6 @@ plugins: [ [//]: # '#### VirtualList' [//]: # '#### WaterMark' [//]: # '### 特色组件' - [//]: # '#### Address' [//]: # '#### Barrage' [//]: # '#### Card' [//]: # '#### Signature' diff --git a/src/types/spec/address/base.ts b/src/types/spec/address/base.ts index e3e0432f83..4538f688c0 100644 --- a/src/types/spec/address/base.ts +++ b/src/types/spec/address/base.ts @@ -3,16 +3,9 @@ import { CascaderOption, CascaderOptionKey, CascaderValue } from '@/types' export interface RegionData { name?: string - [key: string]: any } -export interface ChangeData { - next: string - value: string | RegionData - custom: string -} - export interface CloseCallBackData extends Regions { addressIdStr: string addressStr: string @@ -40,13 +33,6 @@ export interface AddressList { phone?: string } -export interface CurrentData { - next: string - value: string | RegionData - custom: string - selectedRegion?: Regions -} - export interface Regions { province: RegionData city: RegionData @@ -54,12 +40,14 @@ export interface Regions { town: RegionData } +export type AddressModeType = 'exist' | 'cascader' | 'elevator' + export interface BaseAddress { visible: boolean defaultVisible: boolean value?: CascaderValue defaultValue?: CascaderValue - type: string + type: AddressModeType options: CascaderOption[] optionKey: CascaderOptionKey format: Record From 39068af0a5d9a2e65e97e49c22d4576afe886144 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Tue, 29 Apr 2025 10:39:08 +0800 Subject: [PATCH 18/22] fix: import path --- src/packages/address/address.taro.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/address/address.taro.tsx b/src/packages/address/address.taro.tsx index af2d1ec4ad..7968579a09 100644 --- a/src/packages/address/address.taro.tsx +++ b/src/packages/address/address.taro.tsx @@ -9,7 +9,7 @@ import { ArrowLeft } from '@nutui/icons-react-taro' import Popup from '@/packages/popup/index.taro' import { ExistRender } from './existRender.taro' import { ElevatorRender } from './elevatorRender.taro' -import { CascaderRender } from './CascaderRender.taro' +import { CascaderRender } from './cascaderRender.taro' import { useConfig } from '@/packages/configprovider/index.taro' import { ComponentDefaults } from '@/utils/typings' import { usePropsValue } from '@/hooks/use-props-value' From bab94df5c974d5e97deda4f97eaeaac49e620e8a Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Tue, 29 Apr 2025 10:44:49 +0800 Subject: [PATCH 19/22] fix: ai cr --- src/packages/address/address.taro.tsx | 11 ++++------- src/packages/address/address.tsx | 11 ++++------- src/packages/address/existRender.tsx | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/packages/address/address.taro.tsx b/src/packages/address/address.taro.tsx index 7968579a09..f932915372 100644 --- a/src/packages/address/address.taro.tsx +++ b/src/packages/address/address.taro.tsx @@ -116,12 +116,9 @@ const InternalAddress: ForwardRefRenderFunction< } const onSwitchModule = () => { - if (currentType === 'exist') { - setCurrentType('cascader') - } else { - setCurrentType('exist') - } - onSwitch && onSwitch({ type: currentType }) + const nextType = currentType === 'exist' ? 'cascader' : 'exist' + setCurrentType(nextType) + onSwitch && onSwitch({ type: nextType }) } const renderElevator = () => { return ( @@ -161,7 +158,7 @@ const InternalAddress: ForwardRefRenderFunction< height={height} onClose={handleClose} onChange={(val: CascaderValue, params?: any) => { - onChange(val, params) + onChange && onChange(val, params) }} /> ) diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index 0cb00a3d32..78b430be80 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -115,12 +115,9 @@ export const InternalAddress: ForwardRefRenderFunction< } const onSwitchModule = () => { - if (currentType === 'exist') { - setCurrentType('cascader') - } else { - setCurrentType('exist') - } - onSwitch && onSwitch({ type: currentType }) + const nextType = currentType === 'exist' ? 'cascader' : 'exist' + setCurrentType(nextType) + onSwitch && onSwitch({ type: nextType }) } const renderElevator = () => { return ( @@ -160,7 +157,7 @@ export const InternalAddress: ForwardRefRenderFunction< height={height} onClose={handleClose} onChange={(val: CascaderValue, params?: any) => { - onChange(val, params) + onChange && onChange(val, params) }} /> ) diff --git a/src/packages/address/existRender.tsx b/src/packages/address/existRender.tsx index 5ad19f70f1..cbb0af5a01 100644 --- a/src/packages/address/existRender.tsx +++ b/src/packages/address/existRender.tsx @@ -14,7 +14,7 @@ export interface ExistRenderProps { } const defaultProps = { - type: 'exsit', + type: 'exist', existList: [], defaultIcon: null, selectIcon: null, From 9002e9448da227ffa921133ce33a3001fe35c67d Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Tue, 29 Apr 2025 10:50:33 +0800 Subject: [PATCH 20/22] =?UTF-8?q?fix:=20=E4=BF=AE=E8=AE=A2left=20=E4=BC=A0?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/address/address.taro.tsx | 2 +- src/packages/address/address.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/address/address.taro.tsx b/src/packages/address/address.taro.tsx index f932915372..c1c33fb22f 100644 --- a/src/packages/address/address.taro.tsx +++ b/src/packages/address/address.taro.tsx @@ -126,7 +126,7 @@ const InternalAddress: ForwardRefRenderFunction< visible={innerVisible} closeable title={title || locale.address.selectRegion} - left={renderLeftOnCascaderSwitch()} + left={backIcon} defaultValue={defaultValue} closeIcon={closeIcon} options={options} diff --git a/src/packages/address/address.tsx b/src/packages/address/address.tsx index 78b430be80..7cac43e1bf 100644 --- a/src/packages/address/address.tsx +++ b/src/packages/address/address.tsx @@ -125,7 +125,7 @@ export const InternalAddress: ForwardRefRenderFunction< visible={innerVisible} closeable title={title || locale.address.selectRegion} - left={renderLeftOnCascaderSwitch()} + left={backIcon} defaultValue={defaultValue} closeIcon={closeIcon} options={options} From ee3de8d6ca735b73b55b1d3efeb374d7c25785bc Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Tue, 29 Apr 2025 10:54:07 +0800 Subject: [PATCH 21/22] docs: add update version --- src/sites/sites-react/doc/docs/react/migrate-from-v2.md | 2 +- src/sites/sites-react/doc/docs/taro/migrate-from-v2.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md index 95bd385ef1..21693e359d 100644 --- a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md @@ -152,7 +152,7 @@ plugins: [ #### Address - 修订原 type 的类型定义范围,改 `custom` 为 `cascader`,语义化更强;增加 `elevator`,便于快速检索地址。如果没有用到过 `exsit` 与 `custom` 切换逻辑的,理论上无需关注该变化。 -- +- 电梯模式,支持热门城市、级联地址按照电梯的方式展示。 [//]: # '#### Calendar' diff --git a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md index 8e5f97ab0c..6da127ec1b 100644 --- a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md @@ -149,6 +149,11 @@ plugins: [ ### 数据录入 +#### Address + +- 修订原 type 的类型定义范围,改 `custom` 为 `cascader`,语义化更强;增加 `elevator`,便于快速检索地址。如果没有用到过 `exsit` 与 `custom` 切换逻辑的,理论上无需关注该变化。 +- 电梯模式,支持热门城市、级联地址按照电梯的方式展示。 + [//]: # '#### Calendar' #### Cascader From 60e8f70cad39b96010f59ad0a0942d8830b7b58f Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Mon, 5 May 2025 13:31:34 +0800 Subject: [PATCH 22/22] fix: types --- src/packages/address/demos/h5/demo1.tsx | 4 ++-- src/packages/address/demos/h5/demo11.tsx | 6 +++--- src/packages/address/demos/taro/demo11.tsx | 6 +++--- src/packages/address/elevatorRender.taro.tsx | 15 ++++++++------- src/packages/address/elevatorRender.tsx | 11 ++++++----- src/packages/address/utils.ts | 2 -- src/types/spec/cascader/base.ts | 1 + 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/packages/address/demos/h5/demo1.tsx b/src/packages/address/demos/h5/demo1.tsx index b646b2c500..bb477a7ee9 100644 --- a/src/packages/address/demos/h5/demo1.tsx +++ b/src/packages/address/demos/h5/demo1.tsx @@ -3,7 +3,7 @@ import { Address, Cell } from '@nutui/nutui-react' const Demo1 = () => { const [text, setText] = useState('请选择地址') - const [optionsDemo1] = useState([ + const [optionsDemo] = useState([ { value: '浙江', text: '浙江', @@ -77,7 +77,7 @@ const Demo1 = () => { />
{ setText(value.join('')) diff --git a/src/packages/address/demos/h5/demo11.tsx b/src/packages/address/demos/h5/demo11.tsx index db8ebdb35a..ec871d4783 100644 --- a/src/packages/address/demos/h5/demo11.tsx +++ b/src/packages/address/demos/h5/demo11.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react' -import { Address, Cell } from '@nutui/nutui-react' +import { Address, Cell, CascaderOption } from '@nutui/nutui-react' const Demo1 = () => { const [text, setText] = useState('选择地址') @@ -15,7 +15,7 @@ const Demo1 = () => { { name: '武汉' }, { name: '长沙' }, ]) - const [options, setOptions] = useState([]) + const [options, setOptions] = useState([]) useEffect(() => { setOptions([ { @@ -56,7 +56,7 @@ const Demo1 = () => { wordCode: 'H', children: [ { value: '杜集区', text: '杜集区', wordCode: 'D' }, - { value: '烈山区', text: '杜集区', wordCode: 'L' }, + { value: '烈山区', text: '烈山区', wordCode: 'L' }, ], }, { diff --git a/src/packages/address/demos/taro/demo11.tsx b/src/packages/address/demos/taro/demo11.tsx index 8b64c6507e..5417c5a1ed 100644 --- a/src/packages/address/demos/taro/demo11.tsx +++ b/src/packages/address/demos/taro/demo11.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react' -import { Address, Cell } from '@nutui/nutui-react-taro' +import { Address, Cell, CascaderOption } from '@nutui/nutui-react-taro' const Demo1 = () => { const [text, setText] = useState('选择地址') @@ -15,7 +15,7 @@ const Demo1 = () => { { name: '武汉' }, { name: '长沙' }, ]) - const [options, setOptions] = useState([]) + const [options, setOptions] = useState([]) useEffect(() => { setOptions([ { @@ -56,7 +56,7 @@ const Demo1 = () => { wordCode: 'H', children: [ { value: '杜集区', text: '杜集区', wordCode: 'D' }, - { value: '烈山区', text: '杜集区', wordCode: 'L' }, + { value: '烈山区', text: '烈山区', wordCode: 'L' }, ], }, { diff --git a/src/packages/address/elevatorRender.taro.tsx b/src/packages/address/elevatorRender.taro.tsx index 5186cdedf2..373c3ac020 100644 --- a/src/packages/address/elevatorRender.taro.tsx +++ b/src/packages/address/elevatorRender.taro.tsx @@ -10,7 +10,7 @@ import { import { transformData, findDataByName } from './utils' import { CascaderOption, - WebCascaderProps, + TaroCascaderProps, CascaderValue, CascaderOptionKey, RegionData, @@ -21,7 +21,7 @@ import { usePropsValue } from '@/hooks/use-props-value' import { isEmpty } from '@/utils/is-empty' import { useConfig } from '@/packages/configprovider/index.taro' -export interface AddressProps extends WebCascaderProps { +export interface AddressProps extends TaroCascaderProps { visible: boolean // popup visible type: string options: CascaderOption[] @@ -48,10 +48,11 @@ const defaultProps = { closeIconPosition: 'top-right', closeIcon: 'close', lazy: false, + hotList: [], onClose: () => {}, onChange: () => {}, onPathChange: () => {}, -} as unknown as AddressProps +} export const ElevatorRender: FunctionComponent< Partial & @@ -196,16 +197,16 @@ export const ElevatorRender: FunctionComponent< const distData = findDataByName(options, hotItem.name) // 热门城市主要是一级城市和二级城市,可以扩展。TODO if (distData) { - const innerValue = [distData.pName, distData.name].filter( + const nextValue = [distData.pName, distData.name].filter( (item) => item !== '' ) - setInnerValue(innerValue) + setInnerValue(nextValue) setElevatorOptions(distData.children) - setLevelIndex(innerValue.length) + setLevelIndex(nextValue.length) } } const renderTabs = () => { - if (!levels[0].name) return null + if (!levels.length || !levels[0].name) return null return ( {levels.map((item, index) => ( diff --git a/src/packages/address/elevatorRender.tsx b/src/packages/address/elevatorRender.tsx index 7aaccbbba2..59ffe17b42 100644 --- a/src/packages/address/elevatorRender.tsx +++ b/src/packages/address/elevatorRender.tsx @@ -47,10 +47,11 @@ const defaultProps = { closeIconPosition: 'top-right', closeIcon: 'close', lazy: false, + hotList: [], onClose: () => {}, onChange: () => {}, onPathChange: () => {}, -} as unknown as AddressProps +} export const ElevatorRender: FunctionComponent< Partial & @@ -195,16 +196,16 @@ export const ElevatorRender: FunctionComponent< const distData = findDataByName(options, hotItem.name) // 热门城市主要是一级城市和二级城市,可以扩展。TODO if (distData) { - const innerValue = [distData.pName, distData.name].filter( + const nextValue = [distData.pName, distData.name].filter( (item) => item !== '' ) - setInnerValue(innerValue) + setInnerValue(nextValue) setElevatorOptions(distData.children) - setLevelIndex(innerValue.length) + setLevelIndex(nextValue.length) } } const renderTabs = () => { - if (!levels[0].name) return null + if (!levels.length || !levels[0].name) return null return (
{levels.map((item, index) => ( diff --git a/src/packages/address/utils.ts b/src/packages/address/utils.ts index 6efba04c78..a890a4a7e1 100644 --- a/src/packages/address/utils.ts +++ b/src/packages/address/utils.ts @@ -1,5 +1,4 @@ const generateId = (name: string) => { - // 简单实现:根据 name 生成一个随机 ID return name.split('').reduce((sum, char) => sum + char.charCodeAt(0), 0) // 使用字符的 Unicode 值作为 ID } @@ -34,7 +33,6 @@ export const transformData = (data: any) => { return Object.keys(obj).map((key) => ({ title: key, list: obj[key].map((item: any) => { - // console.log('item', item) if (item.children) { item.children = extractTitles(item.children) } diff --git a/src/types/spec/cascader/base.ts b/src/types/spec/cascader/base.ts index dd65e66eab..873e78ce2f 100644 --- a/src/types/spec/cascader/base.ts +++ b/src/types/spec/cascader/base.ts @@ -10,6 +10,7 @@ export interface CascaderPane { export interface CascaderOption { text?: string value?: number | string + wordCode?: string paneKey?: string disabled?: boolean children?: CascaderOption[]