|
|
@@ -0,0 +1,177 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import type { ButtonType } from 'ant-design-vue/es/button';
|
|
|
+
|
|
|
+import type { ActionItem, PopConfirm } from './types';
|
|
|
+
|
|
|
+import { computed, type PropType, toRaw } from 'vue';
|
|
|
+
|
|
|
+import { useAccess } from '@vben/access';
|
|
|
+import { isBoolean, isFunction } from '@vben/utils';
|
|
|
+
|
|
|
+import { Button, Dropdown, Menu, Popconfirm, Space } from 'ant-design-vue';
|
|
|
+
|
|
|
+import { Icon } from '#/components/icon';
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ actions: {
|
|
|
+ type: Array as PropType<ActionItem[]>,
|
|
|
+ default() {
|
|
|
+ return [];
|
|
|
+ },
|
|
|
+ },
|
|
|
+ dropDownActions: {
|
|
|
+ type: Array as PropType<ActionItem[]>,
|
|
|
+ default() {
|
|
|
+ return [];
|
|
|
+ },
|
|
|
+ },
|
|
|
+ divider: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const MenuItem = Menu.Item;
|
|
|
+
|
|
|
+const { hasAccessByCodes } = useAccess();
|
|
|
+function isIfShow(action: ActionItem): boolean {
|
|
|
+ const ifShow = action.ifShow;
|
|
|
+
|
|
|
+ let isIfShow = true;
|
|
|
+
|
|
|
+ if (isBoolean(ifShow)) {
|
|
|
+ isIfShow = ifShow;
|
|
|
+ }
|
|
|
+ if (isFunction(ifShow)) {
|
|
|
+ isIfShow = ifShow(action);
|
|
|
+ }
|
|
|
+ return isIfShow;
|
|
|
+}
|
|
|
+
|
|
|
+const getActions = computed(() => {
|
|
|
+ return (toRaw(props.actions) || [])
|
|
|
+ .filter((action) => {
|
|
|
+ return (
|
|
|
+ (hasAccessByCodes(action.auth || []) ||
|
|
|
+ (action.auth || []).length === 0) &&
|
|
|
+ isIfShow(action)
|
|
|
+ );
|
|
|
+ })
|
|
|
+ .map((action) => {
|
|
|
+ const { popConfirm } = action;
|
|
|
+ return {
|
|
|
+ // getPopupContainer: document.body,
|
|
|
+ type: 'link' as ButtonType,
|
|
|
+ ...action,
|
|
|
+ ...popConfirm,
|
|
|
+ onConfirm: popConfirm?.confirm,
|
|
|
+ onCancel: popConfirm?.cancel,
|
|
|
+ enable: !!popConfirm,
|
|
|
+ };
|
|
|
+ });
|
|
|
+});
|
|
|
+const getDropdownList = computed((): any[] => {
|
|
|
+ return (toRaw(props.dropDownActions) || [])
|
|
|
+ .filter((action) => {
|
|
|
+ return (
|
|
|
+ (hasAccessByCodes(action.auth || []) ||
|
|
|
+ (action.auth || []).length === 0) &&
|
|
|
+ isIfShow(action)
|
|
|
+ );
|
|
|
+ })
|
|
|
+ .map((action, index) => {
|
|
|
+ const { label, popConfirm } = action;
|
|
|
+ return {
|
|
|
+ ...action,
|
|
|
+ ...popConfirm,
|
|
|
+ onConfirm: popConfirm?.confirm,
|
|
|
+ onCancel: popConfirm?.cancel,
|
|
|
+ text: label,
|
|
|
+ divider:
|
|
|
+ index < props.dropDownActions.length - 1 ? props.divider : false,
|
|
|
+ };
|
|
|
+ });
|
|
|
+});
|
|
|
+const getPopConfirmProps = (attrs: PopConfirm) => {
|
|
|
+ const originAttrs: any = attrs;
|
|
|
+ delete originAttrs.icon;
|
|
|
+ if (attrs.confirm && isFunction(attrs.confirm)) {
|
|
|
+ originAttrs.onConfirm = attrs.confirm;
|
|
|
+ delete originAttrs.confirm;
|
|
|
+ }
|
|
|
+ if (attrs.cancel && isFunction(attrs.cancel)) {
|
|
|
+ originAttrs.onCancel = attrs.cancel;
|
|
|
+ delete originAttrs.cancel;
|
|
|
+ }
|
|
|
+ return originAttrs;
|
|
|
+};
|
|
|
+const getButtonProps = (action: ActionItem) => {
|
|
|
+ const res = {
|
|
|
+ type: action.type || 'primary',
|
|
|
+ size: action?.size || 'small',
|
|
|
+ ...action,
|
|
|
+ };
|
|
|
+ delete res.icon;
|
|
|
+ return res;
|
|
|
+};
|
|
|
+const handleMenuClick = (e: any) => {
|
|
|
+ const action = getDropdownList.value[e.key];
|
|
|
+ if (action.onClick && isFunction(action.onClick)) {
|
|
|
+ action.onClick();
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="m-table-action flex items-center">
|
|
|
+ <Space :size="2">
|
|
|
+ <template v-for="(action, index) in getActions" :key="index">
|
|
|
+ <Popconfirm
|
|
|
+ v-if="action.popConfirm"
|
|
|
+ v-bind="getPopConfirmProps(action.popConfirm)"
|
|
|
+ >
|
|
|
+ <template v-if="action.popConfirm.icon" #icon>
|
|
|
+ <Icon :icon="action.popConfirm.icon" />
|
|
|
+ </template>
|
|
|
+ <Button v-bind="getButtonProps(action)">
|
|
|
+ <Icon v-if="action.icon" :icon="action.icon" />
|
|
|
+ {{ action.label }}
|
|
|
+ </Button>
|
|
|
+ </Popconfirm>
|
|
|
+ <Button v-else v-bind="getButtonProps(action)" @click="action.onClick">
|
|
|
+ <Icon v-if="action.icon" :icon="action.icon" />
|
|
|
+ {{ action.label }}
|
|
|
+ </Button>
|
|
|
+ </template>
|
|
|
+ </Space>
|
|
|
+
|
|
|
+ <Dropdown v-if="getDropdownList.length > 0" :trigger="['hover']">
|
|
|
+ <slot name="more">
|
|
|
+ <Button size="small" type="text">
|
|
|
+ <Icon class="icon-more size-5" icon="ic:twotone-more-horiz" />
|
|
|
+ </Button>
|
|
|
+ </slot>
|
|
|
+ <template #overlay>
|
|
|
+ <Menu @click="handleMenuClick">
|
|
|
+ <MenuItem v-for="(action, index) in getDropdownList" :key="index">
|
|
|
+ <template v-if="action.popConfirm">
|
|
|
+ <Popconfirm v-bind="getPopConfirmProps(action.popConfirm)">
|
|
|
+ <template v-if="action.popConfirm.icon" #icon>
|
|
|
+ <Icon :icon="action.popConfirm.icon" />
|
|
|
+ </template>
|
|
|
+ <div>
|
|
|
+ <Icon v-if="action.icon" :icon="action.icon" />
|
|
|
+ <span class="ml-1">{{ action.text }}</span>
|
|
|
+ </div>
|
|
|
+ </Popconfirm>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <Icon v-if="action.icon" :icon="action.icon" />
|
|
|
+ {{ action.label }}
|
|
|
+ </template>
|
|
|
+ </MenuItem>
|
|
|
+ </Menu>
|
|
|
+ </template>
|
|
|
+ </Dropdown>
|
|
|
+ </div>
|
|
|
+</template>
|