import { FC, useState, useMemo, useEffect } from 'react' import { Input, Button, CheckList } from 'antd-mobile' import { DownOutline, CloseCircleFill, RightOutline } from 'antd-mobile-icons' import styled from 'styled-components' import KMPopup from '../Popup' import { TreeItem, BasicCascaderPropsType } from '@/types' import { findTreeLabelBySelectValue } from '@/utils' const InputWrap = styled.div` position: relative; min-height: 40px; .adm-input-feign { height: auto; /* max-width: 100%; */ .adm-input-element { line-height: 19px; height: auto; padding: 3px 20px 3px 0; } .cancel-icon { position: absolute; right: 12px; top: 50%; color: #dcdcdc; transform: translateY(-50%); } } > .arrow-icon { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); } ` const ButtonWrap = styled.div` padding: 16px; display: flex; .adm-button { &:first-child { margin-right: 8px; } } .adm-button-primary { background: linear-gradient(90deg, #f48930 0%, #f66416 100%); box-shadow: 0px 2px 8px 0px rgba(244, 137, 48, 0.3); } ` const PopupHeader = styled.div` text-align: center; position: relative; padding: 15px 0; font-size: 14px; font-weight: 500; line-height: 22px; text-align: center; letter-spacing: 0px; border-bottom: 0.5px solid #dcdcdc; svg { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); color: #dcdcdc; font-size: 16px; } ` const CascaderViewWrap = styled.div` height: 240px; margin-top: 8px; overflow: auto; .adm-list { --padding-left: 8px; --padding-right: 8px; --active-background-color: transparent; .adm-list-body { border: none; } } .adm-check-list-item-active { .adm-list-item-content-main { background: #ececec; border-radius: 6px; } } .adm-list-item-content { border-top: none; .adm-list-item-content-main { font-size: 12px; padding-left: 8px; padding-right: 8px; } .adm-list-item-content-extra { display: none; } } .cascader-item { height: 100%; display: flex; align-items: center; justify-content: space-between; &-icon { width: 12px; } &-label { flex: 1; } } ` const SelectedWrap = styled.div` background: #f5f6f7; width: 100%; height: 40px; padding: 9px 12px; color: #3c3c3c; line-height: 22px; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; ` const BasicCascaderField: FC = ({ title = '多级选择', propValue = 'value', value = [], options = [], onChange }) => { const choosed = value && value.filter(Boolean).length const [activeIndex, setActiveIndex] = useState(0) const [visible, setVisible] = useState(false) const [values, setValues] = useState(choosed ? value : []) const inputLabels = findTreeLabelBySelectValue(options, value, propValue) const handleComfirm = () => { onChange?.(values) setVisible(false) } const handleReset = () => { setValues([]) } const handleClearChoose = ( e: React.MouseEvent ) => { e.stopPropagation() setValues([]) onChange?.(values) } useEffect(() => { setValues(value || []) }, [value]) useEffect(() => { setActiveIndex(levels.length - 1) return }, [values]) useEffect(() => { if (visible) { setValues(choosed ? value : []) } return }, [visible]) const onItemSelect = (selectValue: string, depth: number) => { const next = values.slice(0, depth) if (selectValue !== undefined) { next[depth] = selectValue } setValues(next) } const levels = useMemo(() => { const ret = [] let currentOptions = options let reachedEnd = false for (const v of values) { const target = currentOptions.find((option: TreeItem) => { return ( propValue && ( option[propValue as keyof TreeItem] as number | string ).toString() === v ) }) ret.push({ selected: target, options: currentOptions }) if (!target || !target.children || !target.children.length) { reachedEnd = true break } currentOptions = target.children } if (!reachedEnd) { ret.push({ selected: undefined, options: currentOptions }) } return ret }, [values, options]) const reachedEnd = useMemo(() => { return levels.filter(level => !level.selected).length === 0 }, [levels]) const labels: string[] = useMemo(() => { const selecteds = levels.filter(item => item.selected) return selecteds.map( (i: { selected: TreeItem | undefined; options: TreeItem[] }) => i.selected!.label ) }, [levels]) return ( <> setVisible(!visible)}> {choosed ? (
{inputLabels && inputLabels.join('/')}
handleClearChoose(e)} className="cancel-icon" />
) : ( <> )}
{title} setVisible(false)} /> {levels.map((level, index) => { return ( { onItemSelect(selectValue[0], index) }} > {level.options.map(option => { return (
{option.label}
{option.children && option?.children?.length !== 0 && ( )}
) })}
) })}
已选:{labels.join('/')}
) } export default BasicCascaderField