vue2server7 7.0.108 → 7.0.110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,275 @@
1
+ # 表格列配置演示页面 Implementation Plan
2
+
3
+ > **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.
4
+
5
+ **Goal:** 在前端项目中新增一个"表格列配置演示"路由页面,提供基础的表格框架和预留列配置扩展点
6
+
7
+ **Architecture:** 遵循现有项目结构,创建新的 Vue 页面组件并添加路由配置,保持与现有页面一致的代码风格
8
+
9
+ **Tech Stack:** Vue 3 + Composition API + TypeScript + Element Plus
10
+
11
+ ---
12
+
13
+ ## 文件结构
14
+
15
+ | 文件 | 操作 | 说明 |
16
+ |------|------|------|
17
+ | `frontEnd/src/pages/ColumnConfigDemoPage.vue` | 创建 | 表格列配置演示页面 |
18
+ | `frontEnd/src/router/routes.js` | 修改 | 添加新路由配置 |
19
+
20
+ ---
21
+
22
+ ### Task 1: 创建列配置演示页面组件
23
+
24
+ **Files:**
25
+ - Create: `frontEnd/src/pages/ColumnConfigDemoPage.vue`
26
+
27
+ - [ ] **Step 1: 创建基础页面模板和脚本**
28
+
29
+ ```vue
30
+ <template>
31
+ <section class="page column-config-demo-page">
32
+ <h1 class="title">表格列配置演示</h1>
33
+
34
+ <div class="toolbar">
35
+ <el-button type="primary">查询</el-button>
36
+ <el-button>重置</el-button>
37
+
38
+ <!-- 列设置按钮 - 预留位置,用户自行实现弹窗逻辑 -->
39
+ <el-popover placement="bottom" trigger="click" width="300">
40
+ <template #reference>
41
+ <el-button>列设置</el-button>
42
+ </template>
43
+ <!-- 列配置内容区域 - 用户自行开发 -->
44
+ <div class="column-settings-panel">
45
+ <p>列配置区域</p>
46
+ <p>请在此处实现列配置功能</p>
47
+ </div>
48
+ </el-popover>
49
+ </div>
50
+
51
+ <el-table
52
+ :key="tableKey"
53
+ :data="tableData"
54
+ border
55
+ stripe
56
+ size="small"
57
+ style="width: 100%"
58
+ >
59
+ <el-table-column type="index" label="序号" width="60" align="center" />
60
+ <el-table-column
61
+ v-for="col in visibleColumns"
62
+ :key="col.key"
63
+ :prop="col.prop"
64
+ :label="col.label"
65
+ :width="col.width"
66
+ :min-width="col.minWidth"
67
+ :align="col.align || 'left'"
68
+ :fixed="col.fixed || false"
69
+ >
70
+ </el-table-column>
71
+ </el-table>
72
+
73
+ <div class="pagination">
74
+ <el-pagination
75
+ layout="total, prev, pager, next"
76
+ :current-page="page"
77
+ :page-size="pageSize"
78
+ :total="total"
79
+ @current-change="onPageChange"
80
+ />
81
+ </div>
82
+ </section>
83
+ </template>
84
+
85
+ <script setup lang="ts">
86
+ import { ref, reactive, computed, onMounted } from 'vue'
87
+
88
+ // 列配置接口
89
+ interface ColumnConfig {
90
+ key: string
91
+ prop: string
92
+ label: string
93
+ width?: number
94
+ minWidth?: number
95
+ align?: 'left' | 'center' | 'right'
96
+ fixed?: boolean | 'left' | 'right'
97
+ visible?: boolean
98
+ }
99
+
100
+ // 表格数据接口
101
+ interface TableRow {
102
+ id: number
103
+ name: string
104
+ department: string
105
+ position: string
106
+ phone: string
107
+ email: string
108
+ joinDate: string
109
+ status: string
110
+ }
111
+
112
+ // 响应式数据
113
+ const tableKey = ref(0)
114
+ const page = ref(1)
115
+ const pageSize = ref(10)
116
+ const total = ref(50)
117
+ const tableData = ref<TableRow[]>([])
118
+
119
+ // 列配置 - 可在此基础上扩展更多属性
120
+ const columns = reactive<ColumnConfig[]>([
121
+ { key: 'name', prop: 'name', label: '姓名', width: 100 },
122
+ { key: 'department', prop: 'department', label: '部门', width: 120 },
123
+ { key: 'position', prop: 'position', label: '职位', width: 120 },
124
+ { key: 'phone', prop: 'phone', label: '电话', width: 140 },
125
+ { key: 'email', prop: 'email', label: '邮箱', minWidth: 180 },
126
+ { key: 'joinDate', prop: 'joinDate', label: '入职日期', width: 120, align: 'center' },
127
+ { key: 'status', prop: 'status', label: '状态', width: 100, align: 'center' }
128
+ ])
129
+
130
+ // 可见列计算 - 预留,用户可自行控制显示/隐藏
131
+ const visibleColumns = computed(() => {
132
+ return columns.filter(col => col.visible !== false)
133
+ })
134
+
135
+ // 分页切换
136
+ const onPageChange = (p: number) => {
137
+ page.value = p
138
+ loadData()
139
+ }
140
+
141
+ // 加载模拟数据
142
+ const loadData = () => {
143
+ const data: TableRow[] = []
144
+ for (let i = 0; i < pageSize.value; i++) {
145
+ const index = (page.value - 1) * pageSize.value + i + 1
146
+ data.push({
147
+ id: index,
148
+ name: `员工${index}`,
149
+ department: ['技术部', '产品部', '运营部', '市场部'][index % 4],
150
+ position: ['开发工程师', '产品经理', '运营专员', '市场专员'][index % 4],
151
+ phone: `138${String(index).padStart(8, '0')}`,
152
+ email: `employee${index}@example.com`,
153
+ joinDate: `2024-${String((index % 12) + 1).padStart(2, '0')}-${String((index % 28) + 1).padStart(2, '0')}`,
154
+ status: ['在职', '离职', '休假'][index % 3]
155
+ })
156
+ }
157
+ tableData.value = data
158
+ }
159
+
160
+ onMounted(() => {
161
+ loadData()
162
+ })
163
+ </script>
164
+
165
+ <style scoped>
166
+ .page.column-config-demo-page {
167
+ padding: 16px;
168
+ }
169
+ .title {
170
+ font-size: 18px;
171
+ margin-bottom: 12px;
172
+ }
173
+ .toolbar {
174
+ margin-bottom: 12px;
175
+ }
176
+ .pagination {
177
+ margin-top: 12px;
178
+ text-align: right;
179
+ }
180
+ .column-settings-panel {
181
+ padding: 8px 0;
182
+ }
183
+ </style>
184
+ ```
185
+
186
+ - [ ] **Step 2: 验证文件创建成功**
187
+
188
+ 检查文件是否存在:
189
+ ```bash
190
+ ls -la frontEnd/src/pages/ColumnConfigDemoPage.vue
191
+ ```
192
+ Expected: 文件存在,大小约 3-4KB
193
+
194
+ - [ ] **Step 3: 提交**
195
+
196
+ ```bash
197
+ git add frontEnd/src/pages/ColumnConfigDemoPage.vue
198
+ git commit -m "feat: add column config demo page skeleton"
199
+ ```
200
+
201
+ ---
202
+
203
+ ### Task 2: 添加路由配置
204
+
205
+ **Files:**
206
+ - Modify: `frontEnd/src/router/routes.js:8-87`
207
+
208
+ - [ ] **Step 1: 修改 routes.js 添加导入和路由配置**
209
+
210
+ 在文件顶部导入语句区域添加(第8行后):
211
+ ```javascript
212
+ import ColumnConfigDemoPage from '../pages/ColumnConfigDemoPage.vue'
213
+ ```
214
+
215
+ 在 routes 数组末尾添加新路由(第86行前):
216
+ ```javascript
217
+ {
218
+ path: '/column-config-demo',
219
+ name: 'ColumnConfigDemo',
220
+ component: ColumnConfigDemoPage,
221
+ meta: {
222
+ title: '表格列配置演示',
223
+ showInMenu: true
224
+ }
225
+ }
226
+ ```
227
+
228
+ - [ ] **Step 2: 验证路由配置**
229
+
230
+ 检查文件内容:
231
+ ```bash
232
+ grep -n "ColumnConfigDemo" frontEnd/src/router/routes.js
233
+ ```
234
+ Expected: 至少两行输出(导入语句和路由配置)
235
+
236
+ - [ ] **Step 3: 提交**
237
+
238
+ ```bash
239
+ git add frontEnd/src/router/routes.js
240
+ git commit -m "feat: add column config demo route"
241
+ ```
242
+
243
+ ---
244
+
245
+ ### Task 3: 验证页面功能
246
+
247
+ **Files:**
248
+ - Test: 手动运行前端项目验证
249
+
250
+ - [ ] **Step 1: 启动前端开发服务器**
251
+
252
+ ```bash
253
+ npm run front-dev
254
+ ```
255
+ Expected: Vite 服务器启动成功,无编译错误
256
+
257
+ - [ ] **Step 2: 手动验证**
258
+ 1. 浏览器访问页面
259
+ 2. 检查侧边栏菜单是否显示"表格列配置演示"
260
+ 3. 点击菜单项,页面是否正常加载
261
+ 4. 检查表格数据是否显示
262
+ 5. 检查分页是否正常工作
263
+ 6. 检查"列设置"按钮是否可点击
264
+
265
+ - [ ] **Step 3: 提交验证完成(无代码变更)**
266
+
267
+ ---
268
+
269
+ ## 计划完成检查清单
270
+
271
+ - [x] 所有文件路径正确
272
+ - [x] 代码示例完整无占位符
273
+ - [x] 命令和预期输出明确
274
+ - [x] 与现有项目风格一致
275
+ - [x] 预留了用户自定义扩展点
@@ -0,0 +1,443 @@
1
+ # 表格列配置组件 Implementation Plan
2
+
3
+ > **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.
4
+
5
+ **Goal:** 集成 TableColumnSettings 列配置组件到项目中,并在演示页面使用
6
+
7
+ **Architecture:** 创建独立组件文件,在演示页面中引入,实现动态列显示/隐藏功能
8
+
9
+ **Tech Stack:** Vue 3 + Composition API + Element Plus
10
+
11
+ ---
12
+
13
+ ## 文件结构
14
+
15
+ | 文件 | 操作 | 说明 |
16
+ |------|------|------|
17
+ | `frontEnd/src/components/TableColumnSettings.vue` | 创建 | 表格列配置组件 |
18
+ | `frontEnd/src/pages/ColumnConfigDemoPage.vue` | 修改/创建 | 演示页面集成组件 |
19
+ | `frontEnd/src/router/routes.js` | 修改 | 添加路由(如未添加) |
20
+
21
+ ---
22
+
23
+ ### Task 1: 创建 TableColumnSettings 组件
24
+
25
+ **Files:**
26
+ - Create: `frontEnd/src/components/TableColumnSettings.vue`
27
+
28
+ - [ ] **Step 1: 创建组件文件**
29
+
30
+ ```vue
31
+ <template>
32
+ <el-button @click="visible = true">
33
+ <el-icon><Setting /></el-icon>
34
+ 列配置
35
+ </el-button>
36
+
37
+ <el-dialog
38
+ v-model="visible"
39
+ title="表格列配置"
40
+ width="760px"
41
+ append-to-body
42
+ >
43
+ <div class="desc">请选择需要在表格中显示的数据列</div>
44
+
45
+ <div class="column-box">
46
+ <div class="check-all-row">
47
+ <el-checkbox
48
+ v-model="checkAll"
49
+ :indeterminate="isIndeterminate"
50
+ @change="handleCheckAllChange"
51
+ >
52
+ 全选
53
+ </el-checkbox>
54
+ </div>
55
+
56
+ <el-checkbox-group
57
+ v-model="checkedKeys"
58
+ class="column-list"
59
+ @change="updateCheckAllStatus"
60
+ >
61
+ <el-checkbox
62
+ v-for="item in columns"
63
+ :key="item.prop"
64
+ :label="item.prop"
65
+ :disabled="item.disabled"
66
+ >
67
+ {{ item.label }}
68
+ </el-checkbox>
69
+ </el-checkbox-group>
70
+ </div>
71
+
72
+ <template #footer>
73
+ <el-button @click="visible = false">取消</el-button>
74
+ <el-button type="primary" @click="handleConfirm">
75
+ 确认
76
+ </el-button>
77
+ </template>
78
+ </el-dialog>
79
+ </template>
80
+
81
+ <script setup>
82
+ import { ref, computed, watch } from 'vue'
83
+ import { Setting } from '@element-plus/icons-vue'
84
+
85
+ const props = defineProps({
86
+ columns: {
87
+ type: Array,
88
+ default: () => []
89
+ },
90
+ selectedKeys: {
91
+ type: Array,
92
+ default: () => []
93
+ },
94
+ buttonText: {
95
+ type: String,
96
+ default: '列配置'
97
+ }
98
+ })
99
+
100
+ const emit = defineEmits(['confirm'])
101
+
102
+ const visible = ref(false)
103
+ const checkedKeys = ref([])
104
+ const checkAll = ref(false)
105
+ const isIndeterminate = ref(false)
106
+
107
+ const enabledKeys = computed(() => {
108
+ return props.columns
109
+ .filter(item => !item.disabled)
110
+ .map(item => item.prop)
111
+ })
112
+
113
+ watch(visible, val => {
114
+ if (val) {
115
+ checkedKeys.value = [...props.selectedKeys]
116
+ updateCheckAllStatus()
117
+ }
118
+ })
119
+
120
+ function handleCheckAllChange(val) {
121
+ const disabledCheckedKeys = props.columns
122
+ .filter(item => item.disabled && checkedKeys.value.includes(item.prop))
123
+ .map(item => item.prop)
124
+
125
+ checkedKeys.value = val
126
+ ? [...new Set([...disabledCheckedKeys, ...enabledKeys.value])]
127
+ : disabledCheckedKeys
128
+
129
+ updateCheckAllStatus()
130
+ }
131
+
132
+ function updateCheckAllStatus() {
133
+ const count = checkedKeys.value.filter(key =>
134
+ enabledKeys.value.includes(key)
135
+ ).length
136
+
137
+ checkAll.value = count === enabledKeys.value.length
138
+ isIndeterminate.value = count > 0 && count < enabledKeys.value.length
139
+ }
140
+
141
+ function handleConfirm() {
142
+ emit('confirm', checkedKeys.value)
143
+ visible.value = false
144
+ }
145
+ </script>
146
+
147
+ <style scoped>
148
+ .desc {
149
+ margin-bottom: 22px;
150
+ color: #666;
151
+ font-size: 16px;
152
+ }
153
+
154
+ .column-box {
155
+ border: 1px solid #dcdfe6;
156
+ }
157
+
158
+ .check-all-row {
159
+ padding: 18px 24px;
160
+ border-bottom: 1px solid #dcdfe6;
161
+ }
162
+
163
+ .column-list {
164
+ padding: 22px 24px;
165
+ display: flex;
166
+ flex-wrap: wrap;
167
+ gap: 22px 28px;
168
+ }
169
+
170
+ :deep(.el-checkbox) {
171
+ margin-right: 0;
172
+ }
173
+ </style>
174
+ ```
175
+
176
+ - [ ] **Step 2: 验证文件创建成功**
177
+
178
+ ```bash
179
+ ls -la frontEnd/src/components/TableColumnSettings.vue
180
+ ```
181
+ Expected: 文件存在
182
+
183
+ - [ ] **Step 3: 提交**
184
+
185
+ ```bash
186
+ git add frontEnd/src/components/TableColumnSettings.vue
187
+ git commit -m "feat: add TableColumnSettings component"
188
+ ```
189
+
190
+ ---
191
+
192
+ ### Task 2: 创建/更新 ColumnConfigDemoPage 页面
193
+
194
+ **Files:**
195
+ - Create/Modify: `frontEnd/src/pages/ColumnConfigDemoPage.vue`
196
+
197
+ - [ ] **Step 1: 创建完整的演示页面(如果文件不存在则创建)**
198
+
199
+ ```vue
200
+ <template>
201
+ <section class="page column-config-demo-page">
202
+ <h1 class="title">表格列配置演示</h1>
203
+
204
+ <div class="toolbar">
205
+ <el-button type="primary">查询</el-button>
206
+ <el-button>重置</el-button>
207
+
208
+ <!-- 列配置组件 -->
209
+ <TableColumnSettings
210
+ :columns="columnSettings"
211
+ :selected-keys="selectedKeys"
212
+ @confirm="onColumnConfirm"
213
+ />
214
+ </div>
215
+
216
+ <el-table
217
+ :key="tableKey"
218
+ :data="tableData"
219
+ border
220
+ stripe
221
+ size="small"
222
+ style="width: 100%"
223
+ >
224
+ <el-table-column type="index" label="序号" width="60" align="center" />
225
+ <el-table-column
226
+ v-for="col in visibleColumns"
227
+ :key="col.prop"
228
+ :prop="col.prop"
229
+ :label="col.label"
230
+ :width="col.width"
231
+ :min-width="col.minWidth"
232
+ :align="col.align || 'left'"
233
+ :fixed="col.fixed || false"
234
+ >
235
+ </el-table-column>
236
+ </el-table>
237
+
238
+ <div class="pagination">
239
+ <el-pagination
240
+ layout="total, prev, pager, next"
241
+ :current-page="page"
242
+ :page-size="pageSize"
243
+ :total="total"
244
+ @current-change="onPageChange"
245
+ />
246
+ </div>
247
+ </section>
248
+ </template>
249
+
250
+ <script setup lang="ts">
251
+ import { ref, reactive, computed, onMounted } from 'vue'
252
+ import TableColumnSettings from '../components/TableColumnSettings.vue'
253
+
254
+ // 表格数据接口
255
+ interface TableRow {
256
+ id: number
257
+ name: string
258
+ department: string
259
+ position: string
260
+ phone: string
261
+ email: string
262
+ joinDate: string
263
+ status: string
264
+ }
265
+
266
+ // 响应式数据
267
+ const tableKey = ref(0)
268
+ const page = ref(1)
269
+ const pageSize = ref(10)
270
+ const total = ref(50)
271
+ const tableData = ref<TableRow[]>([])
272
+
273
+ // 列配置 - 用于表格渲染
274
+ const columns = reactive([
275
+ { key: 'name', prop: 'name', label: '姓名', width: 100 },
276
+ { key: 'department', prop: 'department', label: '部门', width: 120 },
277
+ { key: 'position', prop: 'position', label: '职位', width: 120 },
278
+ { key: 'phone', prop: 'phone', label: '电话', width: 140 },
279
+ { key: 'email', prop: 'email', label: '邮箱', minWidth: 180 },
280
+ { key: 'joinDate', prop: 'joinDate', label: '入职日期', width: 120, align: 'center' },
281
+ { key: 'status', prop: 'status', label: '状态', width: 100, align: 'center' }
282
+ ])
283
+
284
+ // 列配置 - 用于列配置组件
285
+ const columnSettings = computed(() => {
286
+ return columns.map(col => ({
287
+ prop: col.prop,
288
+ label: col.label,
289
+ disabled: col.prop === 'name' // 姓名列强制显示,不可取消
290
+ }))
291
+ })
292
+
293
+ // 当前选中的列
294
+ const selectedKeys = ref<string[]>([])
295
+
296
+ // 可见列
297
+ const visibleColumns = computed(() => {
298
+ return columns.filter(col => selectedKeys.value.includes(col.prop))
299
+ })
300
+
301
+ // 列配置确认
302
+ const onColumnConfirm = (keys: string[]) => {
303
+ selectedKeys.value = keys
304
+ tableKey.value += 1 // 强制刷新表格
305
+ }
306
+
307
+ // 分页切换
308
+ const onPageChange = (p: number) => {
309
+ page.value = p
310
+ loadData()
311
+ }
312
+
313
+ // 加载模拟数据
314
+ const loadData = () => {
315
+ const data: TableRow[] = []
316
+ for (let i = 0; i < pageSize.value; i++) {
317
+ const index = (page.value - 1) * pageSize.value + i + 1
318
+ data.push({
319
+ id: index,
320
+ name: `员工${index}`,
321
+ department: ['技术部', '产品部', '运营部', '市场部'][index % 4],
322
+ position: ['开发工程师', '产品经理', '运营专员', '市场专员'][index % 4],
323
+ phone: `138${String(index).padStart(8, '0')}`,
324
+ email: `employee${index}@example.com`,
325
+ joinDate: `2024-${String((index % 12) + 1).padStart(2, '0')}-${String((index % 28) + 1).padStart(2, '0')}`,
326
+ status: ['在职', '离职', '休假'][index % 3]
327
+ })
328
+ }
329
+ tableData.value = data
330
+ }
331
+
332
+ onMounted(() => {
333
+ // 默认选中所有列
334
+ selectedKeys.value = columns.map(col => col.prop)
335
+ loadData()
336
+ })
337
+ </script>
338
+
339
+ <style scoped>
340
+ .page.column-config-demo-page {
341
+ padding: 16px;
342
+ }
343
+ .title {
344
+ font-size: 18px;
345
+ margin-bottom: 12px;
346
+ }
347
+ .toolbar {
348
+ margin-bottom: 12px;
349
+ }
350
+ .pagination {
351
+ margin-top: 12px;
352
+ text-align: right;
353
+ }
354
+ </style>
355
+ ```
356
+
357
+ - [ ] **Step 2: 验证文件**
358
+
359
+ ```bash
360
+ ls -la frontEnd/src/pages/ColumnConfigDemoPage.vue
361
+ ```
362
+ Expected: 文件存在
363
+
364
+ - [ ] **Step 3: 提交**
365
+
366
+ ```bash
367
+ git add frontEnd/src/pages/ColumnConfigDemoPage.vue
368
+ git commit -m "feat: update ColumnConfigDemoPage with TableColumnSettings"
369
+ ```
370
+
371
+ ---
372
+
373
+ ### Task 3: 添加路由配置(如未添加)
374
+
375
+ **Files:**
376
+ - Modify: `frontEnd/src/router/routes.js`
377
+
378
+ - [ ] **Step 1: 检查并添加路由**
379
+
380
+ 如果 routes.js 中还没有 ColumnConfigDemo 路由,添加:
381
+
382
+ 在导入部分添加:
383
+ ```javascript
384
+ import ColumnConfigDemoPage from '../pages/ColumnConfigDemoPage.vue'
385
+ ```
386
+
387
+ 在 routes 数组中添加:
388
+ ```javascript
389
+ {
390
+ path: '/column-config-demo',
391
+ name: 'ColumnConfigDemo',
392
+ component: ColumnConfigDemoPage,
393
+ meta: {
394
+ title: '表格列配置演示',
395
+ showInMenu: true
396
+ }
397
+ }
398
+ ```
399
+
400
+ - [ ] **Step 2: 验证路由配置**
401
+
402
+ ```bash
403
+ grep -n "ColumnConfigDemo" frontEnd/src/router/routes.js
404
+ ```
405
+
406
+ - [ ] **Step 3: 提交**
407
+
408
+ ```bash
409
+ git add frontEnd/src/router/routes.js
410
+ git commit -m "feat: add column config demo route"
411
+ ```
412
+
413
+ ---
414
+
415
+ ### Task 4: 验证功能
416
+
417
+ **Files:**
418
+ - Test: 手动运行测试
419
+
420
+ - [ ] **Step 1: 启动前端开发服务器**
421
+
422
+ ```bash
423
+ npm run front-dev
424
+ ```
425
+ Expected: 无编译错误,服务器正常启动
426
+
427
+ - [ ] **Step 2: 手动验证功能**
428
+ 1. 访问页面,点击"列配置"按钮
429
+ 2. 确认弹窗显示所有列选项
430
+ 3. 确认"姓名"列是禁用状态(不可取消)
431
+ 4. 测试全选/取消全选
432
+ 5. 测试部分选中,确认半选状态显示
433
+ 6. 点击确认,表格列动态更新
434
+ 7. 再次打开弹窗,确认状态保持
435
+
436
+ ---
437
+
438
+ ## 计划完成检查清单
439
+
440
+ - [x] 组件代码完整
441
+ - [x] 演示页面集成完整
442
+ - [x] 文件路径正确
443
+ - [x] 功能描述清晰