nicecode-v2/packages/biz/src/boxSelectTree/components/boxPanel/index.tsx

333 lines
9.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { FC, useState, useContext, ReactNode } from 'react';
import { ModalFormProps } from '@ant-design/pro-components'
import { Input, Dropdown } from 'antd'
import {
ButtonProps,
ConfigProvider,
Tooltip,
Button,
Divider,
DataNode as TreeDataNode,
Tree as BoxTree,
TreeProps as BoxTreeProps,
TreeProps,
InputProps,
DropDownProps
} from '@zhst/meta';
import { IconFont } from '@zhst/icon';
import { ClockCircleOutlined, CloseCircleOutlined, DiffOutlined, FolderAddOutlined, ImportOutlined, SwitcherOutlined } from '@ant-design/icons'
import classNames from 'classnames';
import './index.less'
interface IOption {
label: string
key: string
icon?: string | ReactNode
type?: ButtonProps['type'] | 'dropdown'
disabled?: boolean;
showTooltip?: boolean;
props?: ButtonProps
onClick?: () => void
dropdownConfig?: DropDownProps
}
interface ITag {
label: string
value: string
icon?: ReactNode
parentNode?: string
children?: ITag[]
}
export interface BoxPanelProps {
searchInputProps?: InputProps
showOptions?: boolean
treeProps?: Partial<BoxTreeProps>
data: TreeDataNode[]
onSearch?: (e: any) => void
onItemCheck?: TreeProps['onCheck']
onItemSelect?: TreeProps['onSelect']
/**
* @deprecated 将于下个版本 0.23.0 以后弃用
*/
onBoxBatchDelete?: (data?: any) => void
/**
* @deprecated 将于下个版本 0.23.0 以后弃用
*/
onCreateSubmit?: ModalFormProps['onFinish']
/**
* @deprecated 将于下个版本 0.23.0 以后弃用
*/
onClockClick?: () => void //
/**
* @deprecated 将于下个版本 0.23.0 以后弃用
*/
onImport?: () => void
/**
* @deprecated 将于下个版本 0.23.0 以后弃用
*/
onBatch?: () => void
/**
* @deprecated 将于下个版本 0.23.0 以后弃用
*/
onCreate?: () => void
customImport?: ReactNode | string // 自定义搜索栏边上的过滤图标
extraBtns?: 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 BoxPanel: FC<BoxPanelProps> = (props) => {
const [isTreeCheckable, setIsTreeCheckable] = useState(false)
const {
searchInputProps,
showOptions = true,
extraBtns,
noFilter,
data = [],
onSearch,
treeProps,
onItemCheck,
onItemSelect,
onBoxBatchDelete,
onClockClick,
onImport,
onBatch,
onCreate,
showSearchBar = true,
optionList = [
{
label: '导入盒子',
key: 'import',
icon: <ImportOutlined />,
onClick: () => onImport?.()
},
{
label: '新建组',
key: 'add',
icon: <FolderAddOutlined />,
onClick: () => onCreate?.()
},
{
label: '删除',
key: 'del',
icon: <CloseCircleOutlined />,
onClick: () => onBoxBatchDelete?.(),
props: {
danger: true
}
}
],
filterList = [
{
label: '多选',
key: 'multi',
icon: isTreeCheckable ? <SwitcherOutlined /> : <DiffOutlined />,
onClick: () => onBatch?.() || handleCheckable()
},
{
label: '时钟',
key: 'clock',
icon: <ClockCircleOutlined />,
onClick: () => onClockClick?.()
}
],
showTagPanel,
tagList,
tagExpandAll,
onTagExpand,
checkedTags = [],
onTagCheck,
onResetTags,
tagFootRender,
prefixCls: customizePrefixCls,
customImport: customFilter
} = props
const { getPrefixCls } = useContext(ConfigContext);
const componentName = getPrefixCls('biz-box-select-tree-panel', customizePrefixCls);
/**
* 修改选择状态
* @param _data
*/
const handleCheckable = () => {
setIsTreeCheckable(pre => !pre)
}
/**
* 初始化拓展 filter
* @param _list
* @returns
*/
const initFilter = (_list?: BoxPanelProps['filterList']) => {
const WithDropdown = (dom: ReactNode, _config?: DropDownProps) => {
return (
<Dropdown placement="bottomLeft" arrow {..._config}>
{dom}
</Dropdown>
)
}
return _list?.map(item => (
<Tooltip
title={item.label}
open={item.showTooltip}
>
{item.type === 'dropdown' ? (
WithDropdown(
<Button className={classNames(componentName + '-search-btns-btn')} type="text" onClick={item.onClick} icon={item.icon} />,
item.dropdownConfig
)
) : (
<Button className={classNames(componentName + '-search-btns-btn')} type="text" onClick={item.onClick} icon={item.icon} />
)}
</Tooltip>
))
}
/**
* 初始化拓展 filter
* @param _list
* @returns
*/
const initOptions = (_list?: BoxPanelProps['optionList']) => {
return _list?.map((item, idx) => (
<>
<Tooltip
title={item.label}
>
{/* @ts-ignore */}
<Button className={classNames(componentName + '-btns-common')} type={item.type || 'text'} onClick={item.onClick} icon={item.icon} {...item?.props}>{item.label}</Button>
</Tooltip>
{idx !== _list.length - 1 && <Divider className={classNames(componentName + '-btns-divider')} type="vertical" />}
</>
))
}
/**
* 初始化标签面板
* @param _tagList
* @param sort 是否分类
* @returns
*/
const initTagPanel = (_tagList: BoxPanelProps['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')}
size='middle'
onChange={(e) => onSearch?.(e)}
placeholder='请输入盒子名称'
{...searchInputProps}
/>
{customFilter || (!noFilter && (
<div
className={classNames(componentName + '-search-btns')}
>
{/* @ts-ignore */}
{initFilter(filterList)}
</div>
))}
</div>
)}
{/* 默认操作按钮 */}
{showOptions && (
<>
<div className={classNames(componentName + '-btns')}>
{initOptions(optionList)}
</div>
<Divider style={{ margin: 0 }} />
</>
)}
{extraBtns}
{showTagPanel && (
<div className={classNames(componentName + '-tags')}>
<span
className={classNames(componentName + '-tags-tag')}
style={tagExpandAll ? {
marginBottom: '12px',
display: tagExpandAll ? 'block' : 'inline-block'
} : {}
}
></span>
{initTagPanel(tagList, tagExpandAll)}
<div
className={classNames(
componentName + '-tags-tag_option',
{ [componentName + '-tags-tag_absolute']: tagExpandAll },
)}
>
{tagExpandAll && (
<span
className={classNames(componentName + '-tags-tag_common', componentName + '-tags-tag_fz12')}
onClick={onResetTags}
></span>
)}
<span
className={classNames(componentName + '-tags-tag_common', componentName + '-tags-tag_fz12')}
onClick={onTagExpand}
>{tagExpandAll ? '收起' : '更多'}<IconFont icon={tagExpandAll ? 'icon-shangjiantou' : 'icon-xiajiantou'} /></span>
</div>
{tagFootRender}
</div>
)}
<BoxTree
className={classNames(componentName + '-tree')}
checkable={isTreeCheckable}
treeData={data}
blockNode
onSelect={onItemSelect}
onCheck={onItemCheck}
{...treeProps}
/>
</div>
)
}
export default BoxPanel