|
|
|
@ -1,5 +1,5 @@ |
|
|
|
|
<template> |
|
|
|
|
<div :class="[prefixCls, getAlign]" @click="onCellClick"> |
|
|
|
|
<div :class="[prefixCls, getAlign]" @click="onCellClick" class="setting"> |
|
|
|
|
<template v-for="(action, index) in getActions" :key="`${index}-${action.label}`"> |
|
|
|
|
<template v-if="action.slot"> |
|
|
|
|
<slot name="customButton"></slot> |
|
|
|
@ -19,183 +19,198 @@ |
|
|
|
|
|
|
|
|
|
<Divider type="vertical" class="action-divider" v-if="divider && index < getActions.length - 1" /> |
|
|
|
|
</template> |
|
|
|
|
<Dropdown :trigger="['hover']" :dropMenuList="getDropdownList" popconfirm v-if="dropDownActions && getDropdownList.length > 0"> |
|
|
|
|
<Dropdown :trigger="['hover']" :dropMenuList="getDropdownList" popconfirm |
|
|
|
|
v-if="dropDownActions && getDropdownList.length > 0"> |
|
|
|
|
<slot name="more"></slot> |
|
|
|
|
<a-button type="link" size="small" v-if="!$slots.more"> 更多 <Icon icon="mdi-light:chevron-down"></Icon> </a-button> |
|
|
|
|
</Dropdown> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
<script lang="ts"> |
|
|
|
|
import { defineComponent, PropType, computed, toRaw, unref } from 'vue'; |
|
|
|
|
import { MoreOutlined } from '@ant-design/icons-vue'; |
|
|
|
|
import { Divider, Tooltip, TooltipProps } from 'ant-design-vue'; |
|
|
|
|
import Icon from '/@/components/Icon/index'; |
|
|
|
|
import { ActionItem, TableActionType } from '/@/components/Table'; |
|
|
|
|
import { PopConfirmButton } from '/@/components/Button'; |
|
|
|
|
import { Dropdown } from '/@/components/Dropdown'; |
|
|
|
|
import { useDesign } from '/@/hooks/web/useDesign'; |
|
|
|
|
import { useTableContext } from '../hooks/useTableContext'; |
|
|
|
|
import { usePermission } from '/@/hooks/web/usePermission'; |
|
|
|
|
import { isBoolean, isFunction, isString } from '/@/utils/is'; |
|
|
|
|
import { propTypes } from '/@/utils/propTypes'; |
|
|
|
|
import { ACTION_COLUMN_FLAG } from '../const'; |
|
|
|
|
|
|
|
|
|
export default defineComponent({ |
|
|
|
|
name: 'TableAction', |
|
|
|
|
components: { Icon, PopConfirmButton, Divider, Dropdown, MoreOutlined, Tooltip }, |
|
|
|
|
props: { |
|
|
|
|
actions: { |
|
|
|
|
type: Array as PropType<ActionItem[]>, |
|
|
|
|
default: null, |
|
|
|
|
}, |
|
|
|
|
dropDownActions: { |
|
|
|
|
type: Array as PropType<ActionItem[]>, |
|
|
|
|
default: null, |
|
|
|
|
}, |
|
|
|
|
divider: propTypes.bool.def(true), |
|
|
|
|
outside: propTypes.bool, |
|
|
|
|
stopButtonPropagation: propTypes.bool.def(false), |
|
|
|
|
import { defineComponent, PropType, computed, toRaw, unref } from 'vue'; |
|
|
|
|
import { MoreOutlined } from '@ant-design/icons-vue'; |
|
|
|
|
import { Divider, Tooltip, TooltipProps } from 'ant-design-vue'; |
|
|
|
|
import Icon from '/@/components/Icon/index'; |
|
|
|
|
import { ActionItem, TableActionType } from '/@/components/Table'; |
|
|
|
|
import { PopConfirmButton } from '/@/components/Button'; |
|
|
|
|
import { Dropdown } from '/@/components/Dropdown'; |
|
|
|
|
import { useDesign } from '/@/hooks/web/useDesign'; |
|
|
|
|
import { useTableContext } from '../hooks/useTableContext'; |
|
|
|
|
import { usePermission } from '/@/hooks/web/usePermission'; |
|
|
|
|
import { isBoolean, isFunction, isString } from '/@/utils/is'; |
|
|
|
|
import { propTypes } from '/@/utils/propTypes'; |
|
|
|
|
import { ACTION_COLUMN_FLAG } from '../const'; |
|
|
|
|
|
|
|
|
|
export default defineComponent({ |
|
|
|
|
name: 'TableAction', |
|
|
|
|
components: { Icon, PopConfirmButton, Divider, Dropdown, MoreOutlined, Tooltip }, |
|
|
|
|
props: { |
|
|
|
|
actions: { |
|
|
|
|
type: Array as PropType<ActionItem[]>, |
|
|
|
|
default: null, |
|
|
|
|
}, |
|
|
|
|
setup(props) { |
|
|
|
|
const { prefixCls } = useDesign('basic-table-action'); |
|
|
|
|
let table: Partial<TableActionType> = {}; |
|
|
|
|
if (!props.outside) { |
|
|
|
|
table = useTableContext(); |
|
|
|
|
} |
|
|
|
|
dropDownActions: { |
|
|
|
|
type: Array as PropType<ActionItem[]>, |
|
|
|
|
default: null, |
|
|
|
|
}, |
|
|
|
|
divider: propTypes.bool.def(true), |
|
|
|
|
outside: propTypes.bool, |
|
|
|
|
stopButtonPropagation: propTypes.bool.def(false), |
|
|
|
|
}, |
|
|
|
|
setup(props) { |
|
|
|
|
const { prefixCls } = useDesign('basic-table-action'); |
|
|
|
|
let table: Partial<TableActionType> = {}; |
|
|
|
|
if (!props.outside) { |
|
|
|
|
table = useTableContext(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const { hasPermission } = usePermission(); |
|
|
|
|
function isIfShow(action: ActionItem): boolean { |
|
|
|
|
const ifShow = action.ifShow; |
|
|
|
|
const { hasPermission } = usePermission(); |
|
|
|
|
function isIfShow(action: ActionItem): boolean { |
|
|
|
|
const ifShow = action.ifShow; |
|
|
|
|
|
|
|
|
|
let isIfShow = true; |
|
|
|
|
let isIfShow = true; |
|
|
|
|
|
|
|
|
|
if (isBoolean(ifShow)) { |
|
|
|
|
isIfShow = ifShow; |
|
|
|
|
} |
|
|
|
|
if (isFunction(ifShow)) { |
|
|
|
|
isIfShow = ifShow(action); |
|
|
|
|
} |
|
|
|
|
return isIfShow; |
|
|
|
|
if (isBoolean(ifShow)) { |
|
|
|
|
isIfShow = ifShow; |
|
|
|
|
} |
|
|
|
|
if (isFunction(ifShow)) { |
|
|
|
|
isIfShow = ifShow(action); |
|
|
|
|
} |
|
|
|
|
return isIfShow; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const getActions = computed(() => { |
|
|
|
|
return (toRaw(props.actions) || []) |
|
|
|
|
.filter((action) => { |
|
|
|
|
return hasPermission(action.auth) && isIfShow(action); |
|
|
|
|
}) |
|
|
|
|
.map((action) => { |
|
|
|
|
const { popConfirm } = action; |
|
|
|
|
return { |
|
|
|
|
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body, |
|
|
|
|
type: 'link', |
|
|
|
|
size: 'small', |
|
|
|
|
...action, |
|
|
|
|
...(popConfirm || {}), |
|
|
|
|
onConfirm: popConfirm?.confirm, |
|
|
|
|
onCancel: popConfirm?.cancel, |
|
|
|
|
enable: !!popConfirm, |
|
|
|
|
}; |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const getDropdownList = computed((): any[] => { |
|
|
|
|
//过滤掉隐藏的dropdown,避免出现多余的分割线 |
|
|
|
|
const list = (toRaw(props.dropDownActions) || []).filter((action) => { |
|
|
|
|
const getActions = computed(() => { |
|
|
|
|
return (toRaw(props.actions) || []) |
|
|
|
|
.filter((action) => { |
|
|
|
|
return hasPermission(action.auth) && isIfShow(action); |
|
|
|
|
}); |
|
|
|
|
return list.map((action, index) => { |
|
|
|
|
const { label, popConfirm } = action; |
|
|
|
|
}) |
|
|
|
|
.map((action) => { |
|
|
|
|
const { popConfirm } = action; |
|
|
|
|
return { |
|
|
|
|
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body, |
|
|
|
|
type: 'link', |
|
|
|
|
size: 'small', |
|
|
|
|
...action, |
|
|
|
|
...popConfirm, |
|
|
|
|
...(popConfirm || {}), |
|
|
|
|
onConfirm: popConfirm?.confirm, |
|
|
|
|
onCancel: popConfirm?.cancel, |
|
|
|
|
text: label, |
|
|
|
|
divider: index < list.length - 1 ? props.divider : false, |
|
|
|
|
enable: !!popConfirm, |
|
|
|
|
}; |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const getAlign = computed(() => { |
|
|
|
|
const columns = (table as TableActionType)?.getColumns?.() || []; |
|
|
|
|
const actionColumn = columns.find((item) => item.flag === ACTION_COLUMN_FLAG); |
|
|
|
|
return actionColumn?.align ?? 'left'; |
|
|
|
|
const getDropdownList = computed((): any[] => { |
|
|
|
|
//过滤掉隐藏的dropdown,避免出现多余的分割线 |
|
|
|
|
const list = (toRaw(props.dropDownActions) || []).filter((action) => { |
|
|
|
|
return hasPermission(action.auth) && isIfShow(action); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
function getTooltip(data: string | TooltipProps): TooltipProps { |
|
|
|
|
return list.map((action, index) => { |
|
|
|
|
const { label, popConfirm } = action; |
|
|
|
|
return { |
|
|
|
|
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body, |
|
|
|
|
placement: 'bottom', |
|
|
|
|
...(isString(data) ? { title: data } : data), |
|
|
|
|
...action, |
|
|
|
|
...popConfirm, |
|
|
|
|
onConfirm: popConfirm?.confirm, |
|
|
|
|
onCancel: popConfirm?.cancel, |
|
|
|
|
text: label, |
|
|
|
|
divider: index < list.length - 1 ? props.divider : false, |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const getAlign = computed(() => { |
|
|
|
|
const columns = (table as TableActionType)?.getColumns?.() || []; |
|
|
|
|
const actionColumn = columns.find((item) => item.flag === ACTION_COLUMN_FLAG); |
|
|
|
|
return actionColumn?.align ?? 'left'; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
function getTooltip(data: string | TooltipProps): TooltipProps { |
|
|
|
|
return { |
|
|
|
|
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body, |
|
|
|
|
placement: 'bottom', |
|
|
|
|
...(isString(data) ? { title: data } : data), |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function onCellClick(e: MouseEvent) { |
|
|
|
|
if (!props.stopButtonPropagation) return; |
|
|
|
|
const path = e.composedPath() as HTMLElement[]; |
|
|
|
|
const isInButton = path.find((ele) => { |
|
|
|
|
return ele.tagName?.toUpperCase() === 'BUTTON'; |
|
|
|
|
}); |
|
|
|
|
isInButton && e.stopPropagation(); |
|
|
|
|
} |
|
|
|
|
function onCellClick(e: MouseEvent) { |
|
|
|
|
if (!props.stopButtonPropagation) return; |
|
|
|
|
const path = e.composedPath() as HTMLElement[]; |
|
|
|
|
const isInButton = path.find((ele) => { |
|
|
|
|
return ele.tagName?.toUpperCase() === 'BUTTON'; |
|
|
|
|
}); |
|
|
|
|
isInButton && e.stopPropagation(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return { prefixCls, getActions, getDropdownList, getAlign, onCellClick, getTooltip }; |
|
|
|
|
}, |
|
|
|
|
}); |
|
|
|
|
return { prefixCls, getActions, getDropdownList, getAlign, onCellClick, getTooltip }; |
|
|
|
|
}, |
|
|
|
|
}); |
|
|
|
|
</script> |
|
|
|
|
<style lang="less"> |
|
|
|
|
@prefix-cls: ~'@{namespace}-basic-table-action'; |
|
|
|
|
@prefix-cls: ~'@{namespace}-basic-table-action'; |
|
|
|
|
|
|
|
|
|
.@{prefix-cls} { |
|
|
|
|
display: flex; |
|
|
|
|
align-items: center; |
|
|
|
|
/* update-begin-author:taoyan date:2022-11-18 for: 表格默认行高比官方示例多出2px*/ |
|
|
|
|
height: 22px; |
|
|
|
|
/* update-end-author:taoyan date:2022-11-18 for: 表格默认行高比官方示例多出2px*/ |
|
|
|
|
|
|
|
|
|
.action-divider { |
|
|
|
|
display: table; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.@{prefix-cls} { |
|
|
|
|
&.left { |
|
|
|
|
justify-content: flex-start; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&.center { |
|
|
|
|
justify-content: center; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&.right { |
|
|
|
|
justify-content: flex-end; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
button { |
|
|
|
|
display: flex; |
|
|
|
|
align-items: center; |
|
|
|
|
/* update-begin-author:taoyan date:2022-11-18 for: 表格默认行高比官方示例多出2px*/ |
|
|
|
|
height: 22px; |
|
|
|
|
/* update-end-author:taoyan date:2022-11-18 for: 表格默认行高比官方示例多出2px*/ |
|
|
|
|
|
|
|
|
|
.action-divider { |
|
|
|
|
display: table; |
|
|
|
|
span { |
|
|
|
|
margin-left: 0 !important; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&.left { |
|
|
|
|
justify-content: flex-start; |
|
|
|
|
button.ant-btn-circle { |
|
|
|
|
span { |
|
|
|
|
margin: auto !important; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&.center { |
|
|
|
|
justify-content: center; |
|
|
|
|
} |
|
|
|
|
.ant-divider, |
|
|
|
|
.ant-divider-vertical { |
|
|
|
|
margin: 0 2px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.icon-more { |
|
|
|
|
transform: rotate(90deg); |
|
|
|
|
|
|
|
|
|
&.right { |
|
|
|
|
justify-content: flex-end; |
|
|
|
|
svg { |
|
|
|
|
font-size: 1.1em; |
|
|
|
|
font-weight: 700; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
button { |
|
|
|
|
display: flex; |
|
|
|
|
align-items: center; |
|
|
|
|
.setting { |
|
|
|
|
|
|
|
|
|
span { |
|
|
|
|
margin-left: 0 !important; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
width: 100%; |
|
|
|
|
|
|
|
|
|
button.ant-btn-circle { |
|
|
|
|
span { |
|
|
|
|
margin: auto !important; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
height: 100%; |
|
|
|
|
|
|
|
|
|
.ant-divider, |
|
|
|
|
.ant-divider-vertical { |
|
|
|
|
margin: 0 2px; |
|
|
|
|
} |
|
|
|
|
display: flex; |
|
|
|
|
|
|
|
|
|
.icon-more { |
|
|
|
|
transform: rotate(90deg); |
|
|
|
|
flex-wrap: wrap; |
|
|
|
|
|
|
|
|
|
svg { |
|
|
|
|
font-size: 1.1em; |
|
|
|
|
font-weight: 700; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
align-items: center; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
</style> |
|
|
|
|