Files
admin-web/src/shared/components/RowActions.vue
T
2026-09-18 16:48:40 +08:00

89 lines
2.6 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue'
import { MoreHorizontal } from '@lucide/vue'
export type RowActionTone = 'neutral' | 'warning' | 'purple' | 'primary' | 'success' | 'danger'
export interface RowActionItem {
key: string
label: string
ariaLabel?: string
visible?: boolean
disabled?: boolean
loading?: boolean
tone?: RowActionTone
priority?: number
divided?: boolean
}
const props = withDefaults(defineProps<{
actions: RowActionItem[]
maxVisible?: number
moreLabel?: string
}>(), {
maxVisible: 3,
moreLabel: '更多操作',
})
const emit = defineEmits<{
action: [key: string]
}>()
const availableActions = computed(() => props.actions.filter(action => action.visible !== false))
const directKeys = computed(() => new Set(
availableActions.value
.map((action, index) => ({ action, index }))
.sort((left, right) => (right.action.priority ?? 0) - (left.action.priority ?? 0) || left.index - right.index)
.slice(0, Math.max(0, props.maxVisible))
.map(({ action }) => action.key),
))
const directActions = computed(() => availableActions.value.filter(action => directKeys.value.has(action.key)))
const overflowActions = computed(() => availableActions.value.filter(action => !directKeys.value.has(action.key)))
function select(action: RowActionItem) {
if (action.disabled || action.loading) return
emit('action', action.key)
}
</script>
<template>
<div class="density-actions row-actions">
<el-button
v-for="action in directActions"
:key="action.key"
class="density-action"
:data-tone="action.tone || 'neutral'"
size="small"
:disabled="action.disabled"
:loading="action.loading"
:aria-label="action.ariaLabel"
:title="action.ariaLabel"
@click.stop="select(action)"
>{{ action.label }}</el-button>
<el-dropdown v-if="overflowActions.length" trigger="click">
<el-button
class="density-action"
data-tone="neutral"
size="small"
:aria-label="moreLabel"
:title="moreLabel"
@click.stop
><MoreHorizontal :size="15" aria-hidden="true" /></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-for="action in overflowActions"
:key="action.key"
:class="{ 'danger-menu-item': action.tone === 'danger' }"
:disabled="action.disabled || action.loading"
:divided="action.divided"
@click="select(action)"
>{{ action.label }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>