import { SettingOutlined, VerticalAlignMiddleOutlined, VerticalAlignTopOutlined, VerticalAlignBottomOutlined } from '@ant-design/icons-vue' import { Checkbox, Tree, Popover, Tooltip, Space } from 'ant-design-vue' import 'ant-design-vue/es/checkbox/style/index.less' import 'ant-design-vue/es/tree/style/index.less' import 'ant-design-vue/es/popover/style/index.less' import 'ant-design-vue/es/tooltip/style/index.less' import 'ant-design-vue/es/space/style/index.less' import type { TableColumnType } from 'ant-design-vue' import type { DataNode } from 'ant-design-vue/es/tree' import { genColumnKey } from '../../utils' import type { ProColumns } from '../../typing' import './index.less' import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface' import type { FunctionalComponent, PropType } from 'vue' import { useIntl } from '#/provider' import { getPrefixCls } from '#/layout/RouteContext' import type { VueKey, VueNode } from '#/types' import type { ColumnsState } from '#/table/container' import { useContainer } from '#/table/container' import { computed, ref, watchEffect } from 'vue' import omit from 'ant-design-vue/es/_util/omit' type ColumnSettingProps = { columns: TableColumnType[] draggable?: boolean checkable?: boolean extra?: VueNode checkedReset?: boolean listsHeight?: number } const ToolTipIcon: FunctionalComponent<{ title: string columnKey: string | number show: boolean fixed: 'left' | 'right' | undefined }> = ({ title, show, columnKey, fixed }, { slots }) => { const { columnsMap, setColumnsMap } = useContainer()! if (!show) { return null } return ( { e.stopPropagation() e.preventDefault() const config = columnsMap.value[columnKey] || {} const disableIcon = typeof config.disable === 'boolean' && config.disable if (disableIcon) return const columnKeyMap = { ...columnsMap.value, [columnKey]: { ...config, fixed } as ColumnsState } setColumnsMap(columnKeyMap) }} > {slots.default?.()} ) } const CheckboxListItem: FunctionalComponent<{ columnKey: string | number className?: string title?: VueNode fixed?: boolean | 'left' | 'right' hasParent?: boolean // 等于 react 版本的 isLeaf 属性,由于 ant-design-vue 会默认给 isLeaf 属性赋值,这里需要一个额外的属性来处理 }> = ({ columnKey, hasParent, title, className, fixed }) => { const intl = useIntl() const dom = ( ) return (
{title}
{!hasParent ? dom : null}
) } const CheckboxList = defineComponent({ name: 'CheckboxList', props: { list: { type: Array as PropType<(ProColumns & { index?: number })[]>, default: undefined }, className: { type: String, default: undefined }, title: { type: String, default: undefined }, draggable: { type: Boolean, default: undefined }, checkable: { type: Boolean, default: undefined }, showTitle: { type: Boolean, default: true }, listHeight: { type: Number, default: 280 } }, setup(props) { const { columnsMap, setColumnsMap, sortKeyColumns, setSortKeyColumns } = useContainer()! const show = computed(() => props.list && props.list.length > 0) const treeDataConfig = computed(() => { if (!show.value) return {} const checkedKeys: string[] = [] const loopData = (data: any[], parentConfig?: ColumnsState): DataNode[] => data.map(({ key, children, ...rest }) => { const columnKey = genColumnKey(key, rest.index) const config = columnsMap.value[columnKey || 'null'] || { show: true } if (config.show !== false && parentConfig?.show !== false && !children) { checkedKeys.push(columnKey) } const item: DataNode = { key: columnKey, ...omit(rest, ['className']), selectable: false, disabled: config.disable === true, disableCheckbox: typeof config.disable === 'boolean' ? config.disable : config.disable?.checkbox, hasParent: parentConfig ? true : undefined } if (children) { item.children = loopData(children, config) } return item }) return { list: loopData(props.list as any), keys: checkedKeys } }) /** 移动到指定的位置 */ const move = (id: VueKey, targetId: VueKey, dropPosition: number) => { const newMap = { ...columnsMap.value } // @ts-ignore const newColumns = [...sortKeyColumns.value] const findIndex = newColumns.findIndex(columnKey => columnKey === id) const targetIndex = newColumns.findIndex(columnKey => columnKey === targetId) const isDownWord = dropPosition > findIndex if (findIndex < 0) return const targetItem = newColumns[findIndex] newColumns.splice(findIndex, 1) if (dropPosition === 0) { newColumns.unshift(targetItem) } else { newColumns.splice(isDownWord ? targetIndex : targetIndex + 1, 0, targetItem) } // 重新生成排序数组 newColumns.forEach((key, order) => { newMap[key] = { ...(newMap[key] || {}), order } }) // 更新数组 setColumnsMap(newMap) setSortKeyColumns(newColumns) } /** 选中反选功能 */ const onCheckTree = (e: any) => { const columnKey = e.node.key const newSetting = { ...columnsMap.value[columnKey] } newSetting.show = e.checked setColumnsMap({ ...columnsMap.value, [columnKey]: newSetting }) } return () => { if (!show.value) { return null } const listDom = ( 1 } checkable={props.checkable} onDrop={info => { const dropKey = info.node.key const dragKey = info.dragNode.key const { dropPosition, dropToGap } = info const position = dropPosition === -1 || !dropToGap ? dropPosition + 1 : dropPosition move(dragKey, dropKey, position) }} blockNode onCheck={(_, e) => onCheckTree(e)} checkedKeys={treeDataConfig.value.keys} showLine={false} height={props.listHeight} treeData={treeDataConfig.value.list} > {{ title: (_node: DataNode) => { const node = { ..._node, children: undefined } return } }} ) return ( <> {props.showTitle && {props.title}} {listDom} ) } } }) const GroupCheckboxList: FunctionalComponent<{ localColumns: (ProColumns & { index?: number })[] className?: string draggable: boolean checkable: boolean listsHeight?: number }> = ({ localColumns, className, draggable, checkable, listsHeight }) => { const rightList: (ProColumns & { index?: number })[] = [] const leftList: (ProColumns & { index?: number })[] = [] const list: (ProColumns & { index?: number })[] = [] const intl = useIntl() localColumns.forEach(item => { /** 不在 setting 中展示的 */ if (item.hideInSetting) { return } const { fixed } = item if (fixed === 'left') { leftList.push(item) return } if (fixed === 'right') { rightList.push(item) return } list.push(item) }) const showRight = rightList && rightList.length > 0 const showLeft = leftList && leftList.length > 0 return (
{/* 如果没有任何固定,不需要显示title */}
) } const ColumnSetting: FunctionalComponent = ( props: ColumnSettingProps, { slots } ) => { const columnRef = ref({}) const counter = useContainer()! const localColumns: TableColumnType & { index?: number fixed?: any key?: any }[] = props.columns const { checkedReset = true } = props const { columnsMap, setColumnsMap, clearPersistenceStorage } = counter watchEffect(() => { if (counter.propsRef.value?.columnsState?.value) { columnRef.value = JSON.parse( JSON.stringify(counter.propsRef.value?.columnsState?.value || {}) ) } }) /** * 设置全部选中,或全部未选中 * * @param show */ const setAllSelectAction = (show = true) => { const columnKeyMap = {} const loopColumns = (columns: any) => { columns.forEach(({ key, fixed, index, children }: any) => { const columnKey = genColumnKey(key, index) if (columnKey) { // @ts-ignore columnKeyMap[columnKey] = { show, fixed } } if (children) { loopColumns(children) } }) } loopColumns(localColumns) setColumnsMap(columnKeyMap) } /** 全选和反选 */ const checkedAll = (e: CheckboxChangeEvent) => { if (e.target.checked) { setAllSelectAction() } else { setAllSelectAction(false) } } /** 重置项目 */ const clearClick = () => { clearPersistenceStorage?.() setColumnsMap(columnRef.value) } // 未选中的 key 列表 const unCheckedKeys = computed(() => Object.values(columnsMap.value).filter( // @ts-ignore value => !value || value.show === false ) ) // 是否已经选中 const indeterminate = computed( () => unCheckedKeys.value.length > 0 && unCheckedKeys.value.length !== localColumns.length ) const intl = useIntl() const className = getPrefixCls('pro-table-column-setting') return ( checkedAll(e)} > {intl.getMessage('tableToolBar.columnDisplay', '列展示')} {checkedReset ? ( {intl.getMessage('tableToolBar.reset', '重置')} ) : null} {props?.extra ? ( {props.extra} ) : null} } overlayClassName={`${className}-overlay`} trigger="click" placement="bottomRight" content={ } > {slots.default?.() || ( )} ) } export default ColumnSetting