import { ReloadOutlined, SettingOutlined } from '@ant-design/icons-vue' import type { TableColumnType } from 'ant-design-vue' import { Tooltip } from 'ant-design-vue' import type { ListToolBarProps } from '../ListToolBar' import ListToolBar from '../ListToolBar' // import ColumnSetting from '../ColumnSetting' import './index.less' import FullScreenIcon from './FullscreenIcon' import DensityIcon from './DensityIcon' import type { ActionType, ProTableProps, OptionSearchProps, LabelTooltipType } from '../../typing' import { useIntl } from '#/provider' import type { IntlType } from '#/provider' import { VueNodeOrRenderPropType, VueNodePropType } from '#/types' import type { VueKey, VueNode, VueNodeOrRender } from '#/types' import { computed, defineComponent, watchEffect } from 'vue' import type { ExtractPropTypes, PropType, Ref } from 'vue' import type { ChangeEvent } from 'ant-design-vue/es/_util/EventInterface' import omitUndefined from '../../../utils/omitUndefined' import { useContainer } from '#/table/container' import { getRender } from '#/layout/utils' import type { ToolBarRender } from '#/table/renderTypes' import ColumnSetting from '#/table/components/ColumnSetting' export type SettingOptionType = { draggable?: boolean checkable?: boolean checkedReset?: boolean listsHeight?: number extra?: VueNode children?: VueNode } export type OptionConfig = { density?: boolean fullScreen?: OptionsType reload?: OptionsType setting?: boolean | SettingOptionType search?: (OptionSearchProps & { name?: string }) | boolean } export type OptionsFunctionType = (e: MouseEvent, action?: ActionType) => void export type OptionsType = OptionsFunctionType | boolean export const toolBarProps = () => ({ headerTitle: VueNodeOrRenderPropType as PropType, tooltip: [String, Object] as PropType, toolbar: Object as PropType, toolBarRender: Function as PropType, action: { type: Object as PropType>, default: () => ref({}) }, options: { type: [Object, Boolean] as PropType, default: undefined }, selectedRowKeys: { type: Array as PropType, default: () => [] }, selectedRows: { type: Array as PropType }, onSearch: Function as PropType<(keyWords: string) => void>, columns: { type: Array as PropType[]>, default: () => [] } }) export type ToolBarProps = { headerTitle?: VueNode tooltip?: string | LabelTooltipType toolbar?: ListToolBarProps toolBarRender?: ToolBarRender action: Ref options?: OptionConfig | false selectedRowKeys?: (string | number)[] selectedRows?: T[] onSearch?: (keyWords: string) => void columns: TableColumnType[] } function getButtonText({ intl }: OptionConfig & { intl: IntlType }) { return { reload: { text: intl.getMessage('tableToolBar.reload', '刷新'), icon: }, density: { text: intl.getMessage('tableToolBar.density', '表格密度'), icon: }, setting: { text: intl.getMessage('tableToolBar.columnSetting', '列设置'), icon: }, fullScreen: { text: intl.getMessage('tableToolBar.fullScreen', '全屏'), icon: } } } /** * 渲染默认的 工具栏 */ function renderDefaultOption( options: OptionConfig, defaultOptions: OptionConfig & { intl: IntlType }, actions: Ref, columns: TableColumnType[] ) { return Object.keys(options) .filter(item => item) .map(key => { // @ts-ignore const value = options[key] if (!value) { return null } let onClick: OptionsFunctionType = // @ts-ignore value === true ? defaultOptions[key] : event => value?.(event, actions.value) if (typeof onClick !== 'function') { onClick = () => ({}) } if (key === 'setting') { // @ts-ignore return } if (key === 'fullScreen') { return ( ) } // @ts-ignore const optionItem = getButtonText(defaultOptions)[key] if (optionItem) { return ( {optionItem.icon} ) } return null }) .filter(item => item) } // eslint-disable-next-line vue/one-component-per-file const ToolBar = defineComponent({ name: 'ToolBar', props: toolBarProps(), setup(props, { slots }) { const counter = useContainer()! const intl = useIntl() const defaultOptions = computed(() => ({ reload: () => props.action?.value?.reload(), density: true, setting: true, search: false, fullScreen: () => props.action?.value?.fullScreen?.() })) const searchConfig = computed(() => { if (!props.options) { return false } if (!props.options.search) return false /** 受控的value 和 onChange */ const defaultSearchConfig = { value: counter.keyWords.value, onChange: (e: ChangeEvent) => counter.setKeyWords(e.target.value) } if (props.options.search === true) return defaultSearchConfig return { ...defaultSearchConfig, ...props.options.search } }) watchEffect(() => { if (counter.keyWords === undefined) { props.onSearch?.('') } }) const optionDom = computed(() => { if (props.options === false) { return [] } const options = { ...defaultOptions.value, fullScreen: true, ...props.options } return renderDefaultOption( options, { ...defaultOptions.value, intl }, props.action, props.columns ) }) // 操作列表 const actions = computed(() => { const toolBarRender = getRender(props, slots, 'toolBarRender') return toolBarRender ? toolBarRender(props.action.value, { selectedRowKeys: props.selectedRowKeys, selectedRows: props.selectedRows }) : [] }) const titleDom = computed(() => { const headerRender = getRender(props, slots, 'headerTitle') if (typeof headerRender === 'function') { // @ts-ignore return headerRender() } else { return headerRender } }) return () => ( ) } }) const toolbarRenderProps = () => ({ hideToolbar: { type: Boolean, default: false }, onFormSearchSubmit: Function as PropType<(params: any) => void>, searchNode: VueNodePropType as PropType, tableColumn: { type: Array as PropType, default: () => [] }, tooltip: [String, Object] as PropType, selectedRows: Array as PropType, selectedRowKeys: Array as PropType, headerTitle: VueNodeOrRenderPropType as PropType, toolbar: Object as PropType, options: [Object, Boolean] as PropType, toolBarRender: Function as PropType, actionRef: Object as PropType> }) export type ToolbarRenderProps = Partial>> /** 这里负责与table交互,并且减少 render次数 */ // eslint-disable-next-line vue/one-component-per-file const ToolbarRender = defineComponent({ name: 'ToolbarRender', props: toolbarRenderProps(), setup(props, { slots }) { const onSearch = (keyword: string) => { if (!props.options || !props.options.search) { return } const { name = 'keyword' } = props.options.search === true ? {} : props.options.search /** 如果传入的 onSearch 返回值为 false,应该直接拦截请求 */ const success = (props.options.search as OptionSearchProps)?.onSearch?.(keyword) if (success === false) return // 查询的时候的回到第一页 props.actionRef?.value?.setPageInfo?.({ current: 1 }) props.onFormSearchSubmit?.( omitUndefined({ _timestamp: Date.now(), [name]: keyword }) ) } return () => { // 不展示 toolbar if (props.hideToolbar) { return null } return ( {slots} ) } } }) export default ToolbarRender