Appearance
BizRowActions 操作列按钮组
列表操作列标准件:actions 配置渲染文本按钮组,超过 max 个自动收纳进「更多」下拉。支持权限码过滤(useAuth 全局集合或 authCheck 注入)、二次确认(ElMessageBox)、触发后倒计时冷却防重复提交、行级 loading,以及基于行数据(ctx)的动态显隐 / 禁用。表格、卡片列表、看板等任意「一行一操作区」场景通用。
基础用法
默认(max = 3):
全部直接展示(max = 0 收纳全部 / max = 6):
前 3 个直接展示,其余收纳进「更多」;
max = 0 全部收纳。危险项 danger 红色、divided 前置分隔线。<script setup lang="ts">
/** 基础用法:前 3 个直接展示,第 4 个起自动收纳进「更多」下拉 */
import { ElMessage } from 'element-plus'
import { BizRowActions } from 'vue3-ep-biz-lib'
import type { BizRowAction } from 'vue3-ep-biz-lib'
const actions: BizRowAction[] = [
{ key: 'view', label: '查看', onClick: () => ElMessage.info('查看') },
{ key: 'edit', label: '编辑', onClick: () => ElMessage.info('编辑') },
{ key: 'copy', label: '复制', onClick: () => ElMessage.info('复制') },
{ key: 'log', label: '操作日志', onClick: () => ElMessage.info('操作日志') },
{ key: 'export', label: '导出', onClick: () => ElMessage.info('导出') },
{ key: 'delete', label: '删除', danger: true, divided: true, onClick: () => ElMessage.warning('删除') },
]
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 16px">
<div>
默认(max = 3):<BizRowActions :actions="actions" />
</div>
<div>
全部直接展示(max = 0 收纳全部 / max = 6):
<BizRowActions :actions="actions" :max="6" />
</div>
</div>
</template>
显示代码
二次确认
confirm: true 用默认文案;string 作为正文;对象定制标题 / 正文 / 确认按钮。确认通过后才执行 onClick 与 action 事件。<script setup lang="ts">
/** 二次确认:true 默认文案 / string 正文 / 对象定制标题与按钮;危险操作红色 + 分隔线 */
import { ElMessage } from 'element-plus'
import { BizRowActions } from 'vue3-ep-biz-lib'
import type { BizRowAction } from 'vue3-ep-biz-lib'
const actions: BizRowAction[] = [
{
key: 'disable',
label: '停用',
confirm: '停用后该账号将无法登录,确定继续吗?',
onClick: () => ElMessage.warning('已停用'),
},
{
key: 'delete',
label: '删除',
danger: true,
divided: true,
confirm: {
title: '删除订单',
content: '删除后不可恢复,确定删除订单 SO20260921000382 吗?',
confirmText: '删除',
},
onClick: () => ElMessage.success('已删除'),
},
]
</script>
<template>
<BizRowActions :actions="actions" :max="1" />
</template>
显示代码
权限过滤
当前可见操作:
auth 权限码(数组任一命中放行),默认对接 useAuth 全局权限集合;本例注入 authCheck 模拟角色切换。未配置权限集合时默认放行(fail-open),与 BizAuthButton 同口径。<script setup lang="ts">
/** 权限过滤:auth 权限码 + authCheck 注入演示(真实项目走 useAuth 全局权限集合,无需注入) */
import { ref } from 'vue'
import { ElRadioButton, ElRadioGroup } from 'element-plus'
import { BizRowActions } from 'vue3-ep-biz-lib'
import type { BizRowAction } from 'vue3-ep-biz-lib'
const role = ref<'admin' | 'viewer'>('admin')
const authCheck = (codes?: string | string[]): boolean => {
if (codes === undefined) return true
const list = Array.isArray(codes) ? codes : [codes]
if (role.value === 'admin') return true
return list.every((code) => code === 'order:view')
}
const actions: BizRowAction[] = [
{ key: 'view', label: '查看', onClick: () => {} },
{ key: 'edit', label: '编辑', auth: 'order:edit', onClick: () => {} },
{ key: 'export', label: '导出', auth: ['order:export', 'order:admin'], onClick: () => {} },
{ key: 'delete', label: '删除', danger: true, auth: 'order:delete', onClick: () => {} },
]
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 16px">
<ElRadioGroup v-model="role" size="small">
<ElRadioButton value="admin">管理员(全部权限)</ElRadioButton>
<ElRadioButton value="viewer">只读账号</ElRadioButton>
</ElRadioGroup>
<div>
当前可见操作:<BizRowActions :actions="actions" :max="4" :auth-check="authCheck" />
</div>
</div>
</template>
显示代码
倒计时冷却
countdown 秒数:触发后按钮禁用并倒数显示,防止催办 / 重置密码类操作重复提交;冷却按组件实例(即每行)独立计时。<script setup lang="ts">
/** 倒计时冷却:确认后按钮禁用并倒数,防止催办 / 重置密码类操作重复提交 */
import { ElMessage } from 'element-plus'
import { BizRowActions } from 'vue3-ep-biz-lib'
import type { BizRowAction } from 'vue3-ep-biz-lib'
const actions: BizRowAction[] = [
{
key: 'urge',
label: '催办',
countdown: 10,
onClick: () => ElMessage.success('已发送催办提醒'),
},
{
key: 'reset',
label: '重置密码',
countdown: 30,
confirm: '密码重置链接将通过短信发送给对方,确定继续吗?',
onClick: () => ElMessage.success('已发送重置短信'),
},
]
</script>
<template>
<BizRowActions :actions="actions" :max="2" />
</template>
显示代码
表格操作列标准位
共 8 条
- 1
页
BizTable 操作列插槽内一个组件搞定「查看 / 编辑 / 日志 / 开票 / 关闭」:行差异(待支付才可编辑、已支付才可开票)经 ctx + show 函数声明,操作项只写一次。<script setup lang="ts">
/** 表格操作列标准位:BizTable 操作列换成 BizRowActions,超过阈值自动收纳 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizRowActions, BizTable } from 'vue3-ep-biz-lib'
import type { BizRowAction, BizTableColumn, BizTableInstance } from 'vue3-ep-biz-lib'
type OrderRow = {
id: number
orderNo: string
amount: number
status: 'pending' | 'paid' | 'closed'
}
const data = ref<OrderRow[]>(
Array.from({ length: 8 }, (_, i) => ({
id: i + 1,
orderNo: `SO2026092100${i + 100}`,
amount: 129 + i * 37,
status: (['pending', 'paid', 'closed'] as const)[i % 3],
}))
)
/** 操作项静态声明一次;行差异经 ctx(行数据)函数判定 */
const actions: BizRowAction[] = [
{ key: 'view', label: '查看', onClick: (ctx) => ElMessage.info(`查看 ${String((ctx as OrderRow).orderNo)}`) },
{
key: 'edit',
label: '编辑',
show: (ctx) => (ctx as OrderRow).status === 'pending',
onClick: (ctx) => ElMessage.info(`编辑 ${String((ctx as OrderRow).orderNo)}`),
},
{ key: 'log', label: '日志', onClick: () => ElMessage.info('日志') },
{ key: 'invoice', label: '开票', show: (ctx) => (ctx as OrderRow).status === 'paid', onClick: () => ElMessage.info('开票') },
{
key: 'close',
label: '关闭',
danger: true,
confirm: true,
show: (ctx) => (ctx as OrderRow).status !== 'closed',
onClick: (ctx) => {
const row = ctx as OrderRow
data.value = data.value.map((item) => (item.id === row.id ? { ...item, status: 'closed' } : item))
ElMessage.success(`已关闭 ${row.orderNo}`)
},
},
]
const columns: BizTableColumn<OrderRow>[] = [
{ prop: 'orderNo', label: '订单号', width: 160 },
{ prop: 'amount', label: '金额', width: 100 },
{
prop: 'status',
label: '状态',
width: 90,
enums: [
{ value: 'pending', label: '待支付', tag: 'warning' },
{ value: 'paid', label: '已支付', tag: 'success' },
{ value: 'closed', label: '已关闭', tag: 'info' },
],
},
{ label: '操作', width: 190, fixed: 'right', slot: 'action' },
]
const tableRef = ref<BizTableInstance<OrderRow>>()
</script>
<template>
<div style="height: 320px">
<BizTable ref="tableRef" :columns="columns" :data="data" row-key="id" border>
<template #action="{ row }">
<BizRowActions :actions="actions" :ctx="row" :max="2" />
</template>
</BizTable>
</div>
</template>
显示代码
按行动态禁用与 loading
夜间批处理(running)
报表导出(pending)
数据归档(done)
show / disabled / loading 均支持 (ctx) => boolean 函数按行判定;「停止」异步执行期间该行按钮转圈。<script setup lang="ts">
/** 按行动态禁用 / loading / 显隐:ctx 传入行数据,函数型标记即时生效 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizRowActions } from 'vue3-ep-biz-lib'
import type { BizRowAction } from 'vue3-ep-biz-lib'
type TaskRow = { id: number; name: string; state: 'running' | 'pending' | 'done' }
const rows = ref<TaskRow[]>([
{ id: 1, name: '夜间批处理', state: 'running' },
{ id: 2, name: '报表导出', state: 'pending' },
{ id: 3, name: '数据归档', state: 'done' },
])
/** 正在停止中的任务 id → 该行「停止」按钮转圈 */
const stoppingId = ref<number | null>(null)
const actions: BizRowAction[] = [
{
key: 'stop',
label: '停止',
show: (ctx) => (ctx as TaskRow).state === 'running',
loading: (ctx) => stoppingId.value === (ctx as TaskRow).id,
onClick: async (ctx) => {
const row = ctx as TaskRow
stoppingId.value = row.id
await new Promise((resolve) => setTimeout(resolve, 1500))
rows.value = rows.value.map((item) => (item.id === row.id ? { ...item, state: 'done' } : item))
stoppingId.value = null
ElMessage.success(`${row.name} 已停止`)
},
},
{
key: 'start',
label: '启动',
disabled: (ctx) => (ctx as TaskRow).state === 'running',
onClick: (ctx) => {
const row = ctx as TaskRow
rows.value = rows.value.map((item) => (item.id === row.id ? { ...item, state: 'running' } : item))
ElMessage.success(`${row.name} 已启动`)
},
},
{
key: 'result',
label: '查看结果',
show: (ctx) => (ctx as TaskRow).state === 'done',
onClick: (ctx) => ElMessage.info(`查看 ${String((ctx as TaskRow).name)} 结果`),
},
{
key: 'delete',
label: '删除',
danger: true,
confirm: true,
divided: true,
onClick: (ctx) => {
const row = ctx as TaskRow
rows.value = rows.value.filter((item) => item.id !== row.id)
},
},
]
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<div
v-for="row in rows"
:key="row.id"
style="display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 8px 12px; border: 1px solid var(--el-border-color-lighter); border-radius: 6px"
>
<span>{{ row.name }}({{ row.state }})</span>
<BizRowActions :actions="actions" :ctx="row" :max="2" />
</div>
</div>
</template>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| actions | BizRowAction[] | —(必填) | 操作项配置(按顺序渲染) |
| ctx | Record<string, unknown> | — | 行数据上下文,透传给 show / disabled / loading / onClick |
| max | number | 3 | 直接展示按钮上限(其余收纳进「更多」);0 = 全部收纳 |
| size | 'large' | 'default' | 'small' | small | 按钮尺寸(透传 el-button) |
| more-text | string | 更多 | 「更多」触发文案 |
| trigger | 'click' | 'hover' | click | 「更多」下拉触发方式 |
| auth-check | (codes?) => boolean | useAuth | 权限判定注入(默认走全局权限集合) |
BizRowAction
| 属性 | 类型 | 说明 |
|---|---|---|
| key | string | 动作标识(action 事件回传) |
| label | string | 按钮文案 |
| danger | boolean | 危险操作(红色) |
| icon | Component | 图标(下拉区展示) |
| auth | string | string[] | 权限码,任一命中放行 |
| show | boolean | ((ctx) => boolean) | 是否渲染 |
| disabled | boolean | ((ctx) => boolean) | 是否禁用 |
| loading | boolean | ((ctx) => boolean) | 行级 loading |
| confirm | boolean | string | { title?; content?; confirmText? } | 二次确认 |
| countdown | number | 触发后冷却秒数(禁用倒数防重复) |
| divided | boolean | 与后一项之间加分隔线 |
| onClick | (ctx) => void | 点击回调(确认通过后触发) |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| action | (key, action, ctx) | 二次确认通过后触发(与 onClick 同时派发) |
Slots
| 插槽名 | 说明 |
|---|---|
| prefix | 直接按钮之前的自定义内容 |
| suffix | 「更多」下拉之后的自定义内容 |