nicecode-v2/packages/biz/src/treePanel/TreePanel.tsx

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