270 lines
7.2 KiB
TypeScript
270 lines
7.2 KiB
TypeScript
import React, { FC, useContext, ReactNode } from 'react';
|
|
import {
|
|
ConfigProvider,
|
|
Input,
|
|
Dropdown,
|
|
Tooltip,
|
|
Button,
|
|
DataNode as TreeDataNode,
|
|
Tree as BoxTree,
|
|
TreeProps as BoxTreeProps,
|
|
TreeProps,
|
|
InputProps,
|
|
DropDownProps,
|
|
SelectProps,
|
|
Select
|
|
} from '@zhst/meta';
|
|
import { IconFont } from '@zhst/icon';
|
|
import classNames from 'classnames';
|
|
import './index.less'
|
|
import { ButtonProps } from 'antd';
|
|
|
|
export interface IOption {
|
|
type?: ButtonProps['type'] & 'dropdown';
|
|
label: string
|
|
key: string
|
|
icon?: string | ReactNode
|
|
disabled?: boolean;
|
|
showTooltip?: boolean;
|
|
onClick?: () => void
|
|
className?: string;
|
|
dropdownConfig?: DropDownProps
|
|
}
|
|
|
|
export interface ITag {
|
|
label: string
|
|
value: string
|
|
icon?: ReactNode
|
|
parentNode?: string
|
|
children?: ITag[]
|
|
}
|
|
|
|
export interface TreePanelProps {
|
|
treeType?: 'directory' | 'normal'
|
|
searchInputProps?: InputProps
|
|
showOptions?: boolean
|
|
showSelectBar?: boolean // 显示搜索框
|
|
filterSelectProps?: SelectProps
|
|
onSelect?: SelectProps['onChange']
|
|
treeProps?: Partial<BoxTreeProps>
|
|
data: TreeDataNode[]
|
|
onSearch?: (e: any) => void
|
|
onItemCheck?: TreeProps['onCheck']
|
|
onItemSelect?: TreeProps['onSelect']
|
|
customImport?: ReactNode | string // 自定义搜索栏边上的过滤图标
|
|
extra?: ReactNode | string // 搜索栏下面的插槽
|
|
prefixCls?: string
|
|
showSearchBar?: boolean // 是否显示搜索栏
|
|
noFilter?: boolean // 是否显示搜索拓展 icon
|
|
filterList?: IOption[]
|
|
optionList?: IOption[]
|
|
showTagPanel?: boolean // 标签插槽
|
|
tagList?: ITag[] // 标签列表
|
|
tagExpandAll?: boolean // 展开所有
|
|
onTagCheck?: (value: string, tag: ITag) => void;
|
|
checkedTags?: string[]
|
|
onResetTags?: () => void
|
|
onTagExpand?: (e: any) => void
|
|
tagFootRender?: ReactNode
|
|
}
|
|
|
|
const { ConfigContext } = ConfigProvider
|
|
const { DirectoryTree } = BoxTree
|
|
|
|
const TreePanel: FC<TreePanelProps> = (props) => {
|
|
const {
|
|
treeType = 'directory',
|
|
searchInputProps,
|
|
showOptions = true,
|
|
showSelectBar,
|
|
filterSelectProps,
|
|
extra,
|
|
noFilter,
|
|
data = [],
|
|
treeProps,
|
|
onSelect,
|
|
onSearch,
|
|
onItemCheck,
|
|
onItemSelect,
|
|
showSearchBar = true,
|
|
optionList = [],
|
|
filterList = [],
|
|
showTagPanel,
|
|
tagList,
|
|
tagExpandAll,
|
|
onTagExpand,
|
|
checkedTags = [],
|
|
onTagCheck,
|
|
onResetTags,
|
|
tagFootRender,
|
|
prefixCls: customizePrefixCls,
|
|
customImport: customFilter
|
|
} = props
|
|
|
|
const { getPrefixCls } = useContext(ConfigContext);
|
|
const componentName = getPrefixCls('biz-tree-panel', customizePrefixCls);
|
|
const CurrentTree = treeType === 'directory' ? DirectoryTree : BoxTree
|
|
|
|
/**
|
|
* 初始化拓展 filter
|
|
* @param _list
|
|
* @returns
|
|
*/
|
|
const initFilter = (_list?: TreePanelProps['filterList']) => {
|
|
const WithDropdown = (dom: ReactNode, isShow?: boolean, _config?: DropDownProps) => {
|
|
if (!isShow) {
|
|
return dom
|
|
}
|
|
|
|
return (
|
|
<Dropdown placement="bottomLeft" arrow {..._config}>
|
|
{dom}
|
|
</Dropdown>
|
|
)
|
|
}
|
|
|
|
return _list?.map(item => (
|
|
<Tooltip
|
|
title={item.label}
|
|
open={item.showTooltip}
|
|
>
|
|
{WithDropdown(
|
|
<Button className={classNames(componentName + '-search-btns-btn')} type={item.type} onClick={item.onClick} icon={item.icon} {...item} />,
|
|
item.type === 'dropdown',
|
|
item.dropdownConfig
|
|
)}
|
|
</Tooltip>
|
|
))
|
|
}
|
|
|
|
/**
|
|
* 初始化拓展 filter
|
|
* @param _list
|
|
* @returns
|
|
*/
|
|
const initOptions = (_list?: TreePanelProps['optionList']) => {
|
|
return _list?.map((item, idx) => (
|
|
<>
|
|
{/* @ts-ignore */}
|
|
<div key={idx} className={classNames(componentName + '-btns-btn')}>
|
|
{item.icon}
|
|
<span onClick={item.onClick} className={classNames(componentName + '-btns-btn-label', item.className)}>{item.label}</span>
|
|
</div>
|
|
{idx % 2 !== 0 && (<br/>)}
|
|
</>
|
|
))
|
|
}
|
|
|
|
/**
|
|
* 初始化标签面板
|
|
* @param _tagList
|
|
* @param sort 是否分类
|
|
* @returns
|
|
*/
|
|
const initTagPanel = (_tagList: TreePanelProps['tagList'], sort?: boolean) => {
|
|
// 正常标签渲染
|
|
const commonTag = (_tagProps: ITag) => (
|
|
<span
|
|
className={classNames(
|
|
componentName + '-tags-tag_common',
|
|
{[componentName + '-tags-tag_checked']: checkedTags.includes(_tagProps.value)}
|
|
)}
|
|
key={_tagProps.value}
|
|
onClick={() => onTagCheck?.(_tagProps.value, _tagProps)}
|
|
>{_tagProps.label}</span>
|
|
)
|
|
// 包装父级标签
|
|
const _withFather = (tag: ITag) => (
|
|
<div key={tag.value}>
|
|
<span className={classNames(componentName + '-tags-tag')}>{tag.label}</span>
|
|
{tag.children?.map?.(_tag => commonTag(_tag))}
|
|
</div>
|
|
)
|
|
|
|
return _tagList?.map(tag => {
|
|
if (tag.children?.length && sort) {
|
|
return _withFather(tag)
|
|
} else {
|
|
return commonTag(tag)
|
|
}
|
|
})
|
|
}
|
|
|
|
return (
|
|
<div className={componentName}>
|
|
{/* 搜索栏 */}
|
|
{showSearchBar && (
|
|
<div className={classNames(componentName + '-search')}>
|
|
<Input
|
|
className={classNames(componentName + '-search-input')}
|
|
onChange={(e) => onSearch?.(e)}
|
|
placeholder='请输入盒子名称'
|
|
{...searchInputProps}
|
|
/>
|
|
</div>
|
|
)}
|
|
{/* 搜索栏 */}
|
|
{showSelectBar && (
|
|
<div className={classNames(componentName + '-search')}>
|
|
<Select
|
|
className={classNames(componentName + '-search-input')}
|
|
onChange={onSelect}
|
|
{...filterSelectProps}
|
|
/>
|
|
{customFilter || (!noFilter && (
|
|
<div
|
|
className={classNames(componentName + '-search-btns')}
|
|
>
|
|
{/* @ts-ignore */}
|
|
{initFilter(filterList)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
{showTagPanel && (
|
|
<div className={classNames(componentName + '-tags')}>
|
|
<div className={classNames(componentName + '-tags-title')}>
|
|
标签
|
|
<div
|
|
className={classNames(
|
|
componentName + '-tags-tag_option',
|
|
)}
|
|
>
|
|
{tagExpandAll && (
|
|
<span
|
|
className={classNames(componentName + '-tags-tag_option-btn')}
|
|
onClick={onResetTags}
|
|
>重置</span>
|
|
)}
|
|
<span
|
|
className={classNames(componentName + '-tags-tag_option-btn')}
|
|
onClick={onTagExpand}
|
|
>{tagExpandAll ? '收起' : '展开'}<IconFont icon={tagExpandAll ? 'icon-shangjiantou' : 'icon-xiajiantou'} /></span>
|
|
</div>
|
|
</div>
|
|
{initTagPanel(tagList, tagExpandAll)}
|
|
{tagFootRender}
|
|
</div>
|
|
)}
|
|
{/* 默认操作按钮 */}
|
|
{showOptions && (
|
|
<div className={classNames(componentName + '-btns')}>
|
|
{initOptions(optionList)}
|
|
</div>
|
|
)}
|
|
{extra}
|
|
<CurrentTree
|
|
className={classNames(componentName + '-tree')}
|
|
treeData={data}
|
|
showIcon={false}
|
|
blockNode
|
|
onSelect={onItemSelect}
|
|
onCheck={onItemCheck}
|
|
{...treeProps}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default TreePanel
|