Files
zkxw/docs/superpowers/plans/2026-05-26-action-column.md
T
2026-05-26 22:31:48 +08:00

168 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ToolbarAction 组件实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 封装 ToolbarAction 可复用组件,将操作按钮从表格操作列移至工具栏,通过勾选行激活操作。
**Architecture:** 新建 `src/components/common/toolbar-action/` 组件,接收 `selected`(已选行)和 `actions`(操作列表),根据选中数量和操作模式(batch/single)自动控制按钮禁用状态。复用现有 `.btn-ghost` 样式。
**Tech Stack:** Vue 3 + TypeScript + Element Plus
---
## 文件结构
| 操作 | 文件 | 职责 |
|------|------|------|
| 创建 | `src/components/common/toolbar-action/types.ts` | ToolbarActionItem 类型定义 |
| 创建 | `src/components/common/toolbar-action/index.vue` | 组件本体(模板 + 逻辑 + scoped 样式) |
| 删除 | `web-admin/demo-action-column.html` | 之前的演示文件 |
---
### Task 1: 创建类型定义
**Files:**
- Create: `src/components/common/toolbar-action/types.ts`
- [ ] **Step 1: 创建类型文件**
```ts
import type { Component } from 'vue'
export interface ToolbarActionItem {
label: string
icon?: Component
handler: (rows: any[]) => void
mode: 'batch' | 'single'
danger?: boolean
disabled?: boolean
visible?: boolean
}
```
---
### Task 2: 创建 ToolbarAction 组件
**Files:**
- Create: `src/components/common/toolbar-action/index.vue`
- Reference: `src/components/common/amount-input/index.vue`(组件结构参考)
- Reference: `src/views/production/consumable/index.vue:46-72`(工具栏按钮布局参考)
- Reference: `src/assets/styles/core/el-ui.scss:987-995`(`.btn-ghost` 样式)
- [ ] **Step 1: 创建组件文件**
组件关键行为:
- 过滤 `visible !== false` 的 actions
- `selected.length === 0`:所有按钮 disabled
- `selected.length === 1`:所有按钮可用
- `selected.length > 1 && mode === 'single'`:disabled + tooltip「请选择单条记录」
- `danger=true`:`type="danger"` 样式
- `disabled=true`(调用方传入):始终禁用
- 非 danger 按钮:`btn-ghost` class
```vue
<template>
<template v-for="action in visibleActions" :key="action.label">
<el-tooltip
v-if="isSingleDisabled(action)"
content="请选择单条记录"
placement="top"
>
<span class="toolbar-action-disabled-wrap">
<el-button
class="btn-ghost"
:type="action.danger ? 'danger' : undefined"
disabled
>
<el-icon v-if="action.icon"><component :is="action.icon" /></el-icon>
{{ action.label }}
</el-button>
</span>
</el-tooltip>
<el-button
v-else
class="btn-ghost"
:type="action.danger ? 'danger' : undefined"
:disabled="isDisabled(action)"
@click="action.handler(selected)"
>
<el-icon v-if="action.icon"><component :is="action.icon" /></el-icon>
{{ action.label }}
</el-button>
</template>
</template>
<script setup lang="ts">
import type { ToolbarActionItem } from './types'
defineOptions({ name: 'ToolbarAction' })
interface Props {
selected: any[]
actions: ToolbarActionItem[]
}
const props = defineProps<Props>()
const visibleActions = computed(() =>
props.actions.filter((a) => a.visible !== false),
)
const selectedCount = computed(() => props.selected.length)
function isDisabled(action: ToolbarActionItem): boolean {
if (action.disabled) return true
if (selectedCount.value === 0) return true
if (action.mode === 'single' && selectedCount.value > 1) return true
return false
}
function isSingleDisabled(action: ToolbarActionItem): boolean {
return (
!action.disabled &&
action.mode === 'single' &&
selectedCount.value > 1
)
}
</script>
<style scoped>
.toolbar-action-disabled-wrap {
display: inline-flex;
margin-left: 12px;
}
</style>
```
---
### Task 3: 验证构建
**Files:** 无新增修改
- [ ] **Step 1: 运行构建**
Run: `cd web-admin && pnpm build`
Expected: 构建成功
---
### Task 4: 清理演示文件
**Files:**
- Delete: `web-admin/demo-action-column.html`
- [ ] **Step 1: 删除演示文件**
Run: `rm web-admin/demo-action-column.html`
---
## 不在本计划范围
- 改造现有页面的操作列(后续按需逐步替换)
- 全局注册组件(按需 import 即可)
- 修改全局样式(使用 ToolbarAction 的页面移除操作列后,`min-width: 260px` 规则自动失效)