@agile-team/wl-skills-kit 2.9.2 → 2.9.4
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.
- package/CHANGELOG.md +23 -0
- package/README.md +1 -1
- package/bin/wl-skills.js +19 -11
- package/files/.github/copilot-instructions.md +9 -14
- package/files/.github/guides/architecture.md +1 -1
- package/files/.github/guides/usage.md +1 -1
- package/files/.github/skills/_best-practices.md +2 -2
- package/files/.github/skills/core/convention-audit/SKILL.md +9 -7
- package/files/.github/skills/core/page-codegen/SKILL.md +1 -0
- package/files/.github/skills/core/page-codegen/USAGE.md +1 -1
- package/files/.github/skills/core/prototype-scan/SKILL.md +3 -3
- package/files/.github/standards/14-layout-containers.md +159 -159
- package/files/demo/sale/demo/add-demo/index.scss +207 -207
- package/files/demo/sale/demo/add-demo/index.vue +171 -171
- package/files/demo/sale/demo/metallurgical-spec/index.scss +264 -264
- package/files/demo/sale/demo/metallurgical-spec/index.vue +313 -313
- package/files/src/components/global/C_Splitter/index.vue +149 -149
- package/files/src/components/local/c_formSections/README.md +496 -496
- package/package.json +2 -2
|
@@ -1,496 +1,496 @@
|
|
|
1
|
-
# c_formSections - 表单区块组件
|
|
2
|
-
|
|
3
|
-
> 基于配置的表单折叠面板组件,集成楼层导航、工具栏、布局切换等功能
|
|
4
|
-
|
|
5
|
-
## 📦 功能特性
|
|
6
|
-
|
|
7
|
-
### 核心功能
|
|
8
|
-
|
|
9
|
-
- ✅ **配置驱动** - 基于 JSON 配置自动渲染表单区块
|
|
10
|
-
- ✅ **类型丰富** - 支持 input、select、textarea、date、datetime、number 等多种类型
|
|
11
|
-
- ✅ **动态显示** - 支持根据条件动态显示/隐藏区块
|
|
12
|
-
- ✅ **插槽扩展** - 支持特殊区块和自定义字段插槽
|
|
13
|
-
- ✅ **TypeScript** - 完整的类型定义支持
|
|
14
|
-
|
|
15
|
-
### 🆕 增强功能
|
|
16
|
-
|
|
17
|
-
- ✅ **楼层导航** - 左侧/右侧导航,支持锚点跳转
|
|
18
|
-
- ✅ **工具栏** - 内置必填字段过滤开关,可扩展自定义工具
|
|
19
|
-
- ✅ **布局切换** - 支持 2/3/4/5 列布局快速切换
|
|
20
|
-
- ✅ **顶部操作栏** - 可配置标题和操作按钮
|
|
21
|
-
- ✅ **自动过滤** - 组件内部自动处理必填字段过滤逻辑
|
|
22
|
-
|
|
23
|
-
## 📖 基础用法
|
|
24
|
-
|
|
25
|
-
```vue
|
|
26
|
-
<template>
|
|
27
|
-
<c_formSections
|
|
28
|
-
:sections="sectionsConfig"
|
|
29
|
-
:form="form"
|
|
30
|
-
v-model:activeNames="activeNames"
|
|
31
|
-
/>
|
|
32
|
-
</template>
|
|
33
|
-
|
|
34
|
-
<script setup lang="ts">
|
|
35
|
-
import { ref } from "vue";
|
|
36
|
-
import c_formSections from "@/components/local/c_formSections/index.vue";
|
|
37
|
-
|
|
38
|
-
const form = ref({
|
|
39
|
-
name: "",
|
|
40
|
-
type: "",
|
|
41
|
-
description: ""
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const activeNames = ref(["1", "2"]);
|
|
45
|
-
|
|
46
|
-
const sectionsConfig = [
|
|
47
|
-
{
|
|
48
|
-
name: "1",
|
|
49
|
-
id: "section-1",
|
|
50
|
-
title: "基本信息",
|
|
51
|
-
fieldsConfig: [
|
|
52
|
-
{ prop: "name", label: "名称", type: "input", required: true },
|
|
53
|
-
{
|
|
54
|
-
prop: "type",
|
|
55
|
-
label: "类型",
|
|
56
|
-
type: "select",
|
|
57
|
-
required: true,
|
|
58
|
-
options: [
|
|
59
|
-
{ label: "类型A", value: "A" },
|
|
60
|
-
{ label: "类型B", value: "B" }
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
]
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
name: "2",
|
|
67
|
-
id: "section-2",
|
|
68
|
-
title: "详细信息",
|
|
69
|
-
fieldsConfig: [
|
|
70
|
-
{ prop: "description", label: "描述", type: "textarea", rows: 4 }
|
|
71
|
-
]
|
|
72
|
-
}
|
|
73
|
-
];
|
|
74
|
-
</script>
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## 🆕 完整功能用法
|
|
78
|
-
|
|
79
|
-
```vue
|
|
80
|
-
<template>
|
|
81
|
-
<c_formSections
|
|
82
|
-
:sections="sectionsConfig"
|
|
83
|
-
:form="form"
|
|
84
|
-
v-model:activeNames="activeNames"
|
|
85
|
-
show-header
|
|
86
|
-
header-title="主档维护"
|
|
87
|
-
:header-actions="headerActions"
|
|
88
|
-
show-toolbar
|
|
89
|
-
show-required-filter
|
|
90
|
-
show-layout-switch
|
|
91
|
-
:default-layout="5"
|
|
92
|
-
:layout-options="[2, 3, 4, 5]"
|
|
93
|
-
show-nav-tabs
|
|
94
|
-
nav-tabs-position="left"
|
|
95
|
-
:nav-tabs="navTabsConfig"
|
|
96
|
-
label-width="100px"
|
|
97
|
-
label-position="right"
|
|
98
|
-
:gutter="20"
|
|
99
|
-
>
|
|
100
|
-
<!-- 特殊区块插槽 -->
|
|
101
|
-
<template #special-3>
|
|
102
|
-
<el-button>自定义内容</el-button>
|
|
103
|
-
</template>
|
|
104
|
-
</c_formSections>
|
|
105
|
-
</template>
|
|
106
|
-
|
|
107
|
-
<script setup lang="ts">
|
|
108
|
-
import { Check, Document } from "@element-plus/icons-vue";
|
|
109
|
-
|
|
110
|
-
const headerActions = [
|
|
111
|
-
{
|
|
112
|
-
label: "保存",
|
|
113
|
-
type: "primary",
|
|
114
|
-
icon: Check,
|
|
115
|
-
onClick: () => console.log("保存")
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
label: "取消",
|
|
119
|
-
onClick: () => console.log("取消")
|
|
120
|
-
}
|
|
121
|
-
];
|
|
122
|
-
|
|
123
|
-
const navTabsConfig = [
|
|
124
|
-
{ label: "基本信息", name: "basic", sectionName: "1" },
|
|
125
|
-
{ label: "详细信息", name: "detail", sectionName: "2" }
|
|
126
|
-
];
|
|
127
|
-
</script>
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## 🔧 Props
|
|
131
|
-
|
|
132
|
-
### 基础属性
|
|
133
|
-
|
|
134
|
-
| 参数 | 说明 | 类型 | 默认值 |
|
|
135
|
-
| ------------- | ---------------------------------------- | ---------------------------- | --------- |
|
|
136
|
-
| sections | 表单区块配置数组 | `SectionConfig[]` | `[]` |
|
|
137
|
-
| form | 表单数据对象 | `FormDataType` | `{}` |
|
|
138
|
-
| activeNames | 激活的折叠面板 name 数组(支持 v-model) | `string[]` | `[]` |
|
|
139
|
-
| rules | 表单验证规则 | `any` | - |
|
|
140
|
-
| labelWidth | 表单标签宽度 | `string` | `'100px'` |
|
|
141
|
-
| labelPosition | 表单标签位置 | `'left' \| 'right' \| 'top'` | `'right'` |
|
|
142
|
-
| gutter | 栅格间距 | `number` | `20` |
|
|
143
|
-
| fieldSpan | 每个字段占据的栅格数(手动控制时使用) | `number` | - |
|
|
144
|
-
|
|
145
|
-
### 🆕 增强属性
|
|
146
|
-
|
|
147
|
-
| 参数 | 说明 | 类型 | 默认值 |
|
|
148
|
-
| ------------------ | ------------------------------------------ | ------------------------- | ------------ |
|
|
149
|
-
| showHeader | 是否显示顶部标题栏 | `boolean` | `false` |
|
|
150
|
-
| headerTitle | 标题栏标题文本 | `string` | `'主档维护'` |
|
|
151
|
-
| headerActions | 顶部操作按钮 | `HeaderAction[]` | `[]` |
|
|
152
|
-
| showToolbar | 是否显示工具栏 | `boolean` | `false` |
|
|
153
|
-
| showRequiredFilter | 是否显示必填字段过滤开关 | `boolean` | `false` |
|
|
154
|
-
| showLayoutSwitch | 是否显示布局切换器 | `boolean` | `false` |
|
|
155
|
-
| defaultLayout | 默认布局列数 | `2 \| 3 \| 4 \| 5` | `5` |
|
|
156
|
-
| layoutOptions | 可选布局列数 | `Array<2 \| 3 \| 4 \| 5>` | `[2,3,4,5]` |
|
|
157
|
-
| showNavTabs | 是否显示楼层导航 | `boolean` | `false` |
|
|
158
|
-
| navTabsPosition | 楼层导航位置 | `'left' \| 'right'` | `'left'` |
|
|
159
|
-
| navTabs | 楼层导航配置(不传则自动从 sections 生成) | `NavTabConfig[]` | `[]` |
|
|
160
|
-
|
|
161
|
-
## 📊 配置接口
|
|
162
|
-
|
|
163
|
-
### SectionConfig
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
interface SectionConfig {
|
|
167
|
-
/** 折叠面板的 name 值(唯一标识) */
|
|
168
|
-
name: string;
|
|
169
|
-
/** 折叠面板 ID(用于锚点跳转) */
|
|
170
|
-
id: string;
|
|
171
|
-
/** 显示的标题 */
|
|
172
|
-
title: string;
|
|
173
|
-
/** 字段配置数组 */
|
|
174
|
-
fieldsConfig: FieldConfig[];
|
|
175
|
-
/** 显示条件函数(可选) */
|
|
176
|
-
visible?: () => boolean;
|
|
177
|
-
/** 是否为特殊处理的区块 */
|
|
178
|
-
isSpecial?: boolean;
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### FieldConfig
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
interface FieldConfig {
|
|
186
|
-
/** 字段属性名 */
|
|
187
|
-
prop: string;
|
|
188
|
-
/** 字段标签 */
|
|
189
|
-
label: string;
|
|
190
|
-
/** 字段类型 */
|
|
191
|
-
type?:
|
|
192
|
-
| "input"
|
|
193
|
-
| "select"
|
|
194
|
-
| "textarea"
|
|
195
|
-
| "date"
|
|
196
|
-
| "datetime"
|
|
197
|
-
| "number"
|
|
198
|
-
| "custom";
|
|
199
|
-
/** 栅格占据列数 */
|
|
200
|
-
span?: number;
|
|
201
|
-
/** 是否必填 */
|
|
202
|
-
required?: boolean;
|
|
203
|
-
/** 占位符文本 */
|
|
204
|
-
placeholder?: string;
|
|
205
|
-
/** 是否可清空(select) */
|
|
206
|
-
clearable?: boolean;
|
|
207
|
-
/** 下拉选项(select) */
|
|
208
|
-
options?: Array<{ label: string; value: string | number }>;
|
|
209
|
-
/** 文本域行数(textarea) */
|
|
210
|
-
rows?: number;
|
|
211
|
-
/** 最小值(number) */
|
|
212
|
-
min?: number;
|
|
213
|
-
/** 最大值(number) */
|
|
214
|
-
max?: number;
|
|
215
|
-
/** 数字精度(number) */
|
|
216
|
-
precision?: number;
|
|
217
|
-
/** 步长(number) */
|
|
218
|
-
step?: number;
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### 🆕 HeaderAction
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
interface HeaderAction {
|
|
226
|
-
/** 按钮文本 */
|
|
227
|
-
label: string;
|
|
228
|
-
/** 按钮类型 */
|
|
229
|
-
type?: "primary" | "success" | "warning" | "danger" | "info" | "text" | "";
|
|
230
|
-
/** 图标(Element Plus Icon 组件) */
|
|
231
|
-
icon?: Component;
|
|
232
|
-
/** 点击事件回调 */
|
|
233
|
-
onClick: () => void;
|
|
234
|
-
/** 是否禁用 */
|
|
235
|
-
disabled?: boolean;
|
|
236
|
-
}
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### 🆕 NavTabConfig
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
interface NavTabConfig {
|
|
243
|
-
/** 标签名称(唯一标识) */
|
|
244
|
-
name: string;
|
|
245
|
-
/** 显示文本 */
|
|
246
|
-
label: string;
|
|
247
|
-
/** 关联的 section name(用于锚点跳转) */
|
|
248
|
-
sectionName?: string | null;
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
## 🎨 插槽
|
|
253
|
-
|
|
254
|
-
### 🆕 工具栏插槽
|
|
255
|
-
|
|
256
|
-
**toolbar-left** - 工具栏左侧自定义内容:
|
|
257
|
-
|
|
258
|
-
```vue
|
|
259
|
-
<c_formSections>
|
|
260
|
-
<template #toolbar-left>
|
|
261
|
-
<el-button size="small">自定义按钮</el-button>
|
|
262
|
-
</template>
|
|
263
|
-
</c_formSections>
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
**toolbar-right** - 工具栏右侧自定义内容:
|
|
267
|
-
|
|
268
|
-
```vue
|
|
269
|
-
<c_formSections>
|
|
270
|
-
<template #toolbar-right>
|
|
271
|
-
<span>自定义文本</span>
|
|
272
|
-
</template>
|
|
273
|
-
</c_formSections>
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
### 特殊区块插槽
|
|
277
|
-
|
|
278
|
-
用于渲染 `isSpecial: true` 的区块自定义内容:
|
|
279
|
-
|
|
280
|
-
```vue
|
|
281
|
-
<c_formSections :sections="sections" :form="form">
|
|
282
|
-
<template #special-3="{ section }">
|
|
283
|
-
<el-row :gutter="20">
|
|
284
|
-
<el-col :span="24">
|
|
285
|
-
<el-button type="primary" @click="addItem">+ 添加项</el-button>
|
|
286
|
-
</el-col>
|
|
287
|
-
</el-row>
|
|
288
|
-
</template>
|
|
289
|
-
</c_formSections>
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### 自定义字段插槽
|
|
293
|
-
|
|
294
|
-
用于渲染 `type: 'custom'` 的字段自定义内容:
|
|
295
|
-
|
|
296
|
-
```vue
|
|
297
|
-
<c_formSections :sections="sections" :form="form">
|
|
298
|
-
<template #field-customField="{ field, form }">
|
|
299
|
-
<custom-input v-model="form[field.prop]" />
|
|
300
|
-
</template>
|
|
301
|
-
</c_formSections>
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
## 📝 完整示例
|
|
305
|
-
|
|
306
|
-
```vue
|
|
307
|
-
<template>
|
|
308
|
-
<div class="form-container">
|
|
309
|
-
<!-- 必填字段过滤开关 -->
|
|
310
|
-
<el-switch v-model="showRequiredOnly" />
|
|
311
|
-
|
|
312
|
-
<!-- 表单区块组件 -->
|
|
313
|
-
<c-form-sections
|
|
314
|
-
:sections="visibleSections"
|
|
315
|
-
:form="form"
|
|
316
|
-
v-model:activeNames="activeNames"
|
|
317
|
-
:rules="formRules"
|
|
318
|
-
:fieldSpan="layoutColumns === 2 ? 12 : 6"
|
|
319
|
-
>
|
|
320
|
-
<!-- 特殊需求区块 -->
|
|
321
|
-
<template #special-3>
|
|
322
|
-
<el-row :gutter="20">
|
|
323
|
-
<el-col :span="24">
|
|
324
|
-
<el-button type="primary" plain @click="addRequirement">
|
|
325
|
-
+ 添加需求
|
|
326
|
-
</el-button>
|
|
327
|
-
</el-col>
|
|
328
|
-
</el-row>
|
|
329
|
-
</template>
|
|
330
|
-
</c-form-sections>
|
|
331
|
-
</div>
|
|
332
|
-
</template>
|
|
333
|
-
|
|
334
|
-
<script setup lang="ts">
|
|
335
|
-
import { ref, computed } from "vue";
|
|
336
|
-
import CFormSections from "@/components/local/c_formSections/index.vue";
|
|
337
|
-
import { filterFieldsByRequired } from "@/components/local/c_formSections/data";
|
|
338
|
-
|
|
339
|
-
const showRequiredOnly = ref(false);
|
|
340
|
-
const layoutColumns = ref(5);
|
|
341
|
-
const activeNames = ref(["1", "2", "3"]);
|
|
342
|
-
|
|
343
|
-
const form = ref({
|
|
344
|
-
name: "",
|
|
345
|
-
code: "",
|
|
346
|
-
type: "",
|
|
347
|
-
count: 0,
|
|
348
|
-
date: null
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
const sectionsConfigRaw = [
|
|
352
|
-
{
|
|
353
|
-
name: "1",
|
|
354
|
-
id: "section-1",
|
|
355
|
-
title: "基本信息",
|
|
356
|
-
fieldsConfig: [
|
|
357
|
-
{ prop: "name", label: "名称", required: true },
|
|
358
|
-
{ prop: "code", label: "编码", required: true },
|
|
359
|
-
{
|
|
360
|
-
prop: "type",
|
|
361
|
-
label: "类型",
|
|
362
|
-
type: "select",
|
|
363
|
-
options: [
|
|
364
|
-
{ label: "类型A", value: "A" },
|
|
365
|
-
{ label: "类型B", value: "B" }
|
|
366
|
-
]
|
|
367
|
-
}
|
|
368
|
-
]
|
|
369
|
-
},
|
|
370
|
-
{
|
|
371
|
-
name: "2",
|
|
372
|
-
id: "section-2",
|
|
373
|
-
title: "详细信息",
|
|
374
|
-
fieldsConfig: [
|
|
375
|
-
{ prop: "count", label: "数量", type: "number", min: 0 },
|
|
376
|
-
{ prop: "date", label: "日期", type: "date" }
|
|
377
|
-
]
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
name: "3",
|
|
381
|
-
id: "section-3",
|
|
382
|
-
title: "特殊需求",
|
|
383
|
-
fieldsConfig: [],
|
|
384
|
-
isSpecial: true,
|
|
385
|
-
visible: () => !showRequiredOnly.value
|
|
386
|
-
}
|
|
387
|
-
];
|
|
388
|
-
|
|
389
|
-
// 动态过滤字段
|
|
390
|
-
const visibleSections = computed(() => {
|
|
391
|
-
return sectionsConfigRaw.map((section) => ({
|
|
392
|
-
...section,
|
|
393
|
-
fieldsConfig: filterFieldsByRequired(
|
|
394
|
-
section.fieldsConfig,
|
|
395
|
-
showRequiredOnly.value
|
|
396
|
-
)
|
|
397
|
-
}));
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
const formRules = {
|
|
401
|
-
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
|
|
402
|
-
code: [{ required: true, message: "请输入编码", trigger: "blur" }]
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
const addRequirement = () => {
|
|
406
|
-
console.log("添加特殊需求");
|
|
407
|
-
};
|
|
408
|
-
</script>
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
## 🛠️ 工具函数
|
|
412
|
-
|
|
413
|
-
### filterFieldsByRequired
|
|
414
|
-
|
|
415
|
-
根据必填条件过滤字段配置:
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
import { filterFieldsByRequired } from "@/components/local/c_formSections/data";
|
|
419
|
-
|
|
420
|
-
const filteredFields = filterFieldsByRequired(fieldsConfig, true);
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### hasSectionFields
|
|
424
|
-
|
|
425
|
-
判断区块是否有可显示的字段:
|
|
426
|
-
|
|
427
|
-
```typescript
|
|
428
|
-
import { hasSectionFields } from "@/components/local/c_formSections/data";
|
|
429
|
-
|
|
430
|
-
const hasFields = hasSectionFields(section.fieldsConfig);
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
### generateDefaultFormData
|
|
434
|
-
|
|
435
|
-
生成默认表单数据:
|
|
436
|
-
|
|
437
|
-
```typescript
|
|
438
|
-
import { generateDefaultFormData } from "@/components/local/c_formSections/data";
|
|
439
|
-
|
|
440
|
-
const defaultForm = generateDefaultFormData(sectionsConfig);
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
## 💡 最佳实践
|
|
444
|
-
|
|
445
|
-
1. **配置管理** - 将 sections 配置放在独立的 data.ts 文件中
|
|
446
|
-
2. **类型安全** - 使用 TypeScript 定义表单数据接口
|
|
447
|
-
3. **动态过滤** - 使用 computed 实现响应式字段过滤
|
|
448
|
-
4. **插槽使用** - 对于复杂的自定义字段,使用插槽扩展
|
|
449
|
-
5. **验证规则** - 配合 Element Plus 的 rules 实现表单验证
|
|
450
|
-
|
|
451
|
-
## 🎯 应用场景
|
|
452
|
-
|
|
453
|
-
- ✅ 订单新增/编辑页面
|
|
454
|
-
- ✅ 配置管理表单
|
|
455
|
-
- ✅ 多区块复杂表单
|
|
456
|
-
- ✅ 需要动态显示/隐藏字段的表单
|
|
457
|
-
- ✅ 企业级业务系统表单页面
|
|
458
|
-
|
|
459
|
-
## 📚 真实项目示例
|
|
460
|
-
|
|
461
|
-
项目中已有完整可用的示例页面,可作为开发模板:
|
|
462
|
-
|
|
463
|
-
### 新增编辑页示例
|
|
464
|
-
|
|
465
|
-
**路径**: `src/views/sale/demo/add-demo/`
|
|
466
|
-
|
|
467
|
-
**特性**:
|
|
468
|
-
|
|
469
|
-
- ✅ 使用 c_formSections 组件展示所有功能
|
|
470
|
-
- ✅ 集成楼层导航、布局切换、必填过滤
|
|
471
|
-
- ✅ 配置驱动的表单字段(50+ 字段)
|
|
472
|
-
- ✅ 真实的保存/草稿/取消逻辑(使用 request + Mock)
|
|
473
|
-
- ✅ 项次信息管理(带分页,使用 jh-pagination)
|
|
474
|
-
- ✅ 全屏模式支持
|
|
475
|
-
- ✅ jh-drag-row 拖拽调整布局
|
|
476
|
-
|
|
477
|
-
**使用方式**:
|
|
478
|
-
|
|
479
|
-
1. 复制 `add-demo` 目录作为模板
|
|
480
|
-
2. 修改 `data.ts` 中的 API_CONFIG 为实际接口地址
|
|
481
|
-
3. 修改 `formFieldsData` 配置为业务字段
|
|
482
|
-
4. 修改 `modalConfig` 为业务需求
|
|
483
|
-
5. 创建对应的 Mock 文件(开发阶段)
|
|
484
|
-
|
|
485
|
-
**关键代码结构**:
|
|
486
|
-
|
|
487
|
-
```
|
|
488
|
-
add-demo/
|
|
489
|
-
├── index.vue # 视图层(176行)- 组件使用和布局
|
|
490
|
-
├── data.ts # 逻辑层(400+行)- 配置和业务逻辑
|
|
491
|
-
├── index.scss # 样式层(207行)- 页面样式
|
|
492
|
-
└── mock/
|
|
493
|
-
└── add-demo.ts # Mock 数据(50条项次数据)
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
**推荐作为团队内部的标准模板使用!**
|
|
1
|
+
# c_formSections - 表单区块组件
|
|
2
|
+
|
|
3
|
+
> 基于配置的表单折叠面板组件,集成楼层导航、工具栏、布局切换等功能
|
|
4
|
+
|
|
5
|
+
## 📦 功能特性
|
|
6
|
+
|
|
7
|
+
### 核心功能
|
|
8
|
+
|
|
9
|
+
- ✅ **配置驱动** - 基于 JSON 配置自动渲染表单区块
|
|
10
|
+
- ✅ **类型丰富** - 支持 input、select、textarea、date、datetime、number 等多种类型
|
|
11
|
+
- ✅ **动态显示** - 支持根据条件动态显示/隐藏区块
|
|
12
|
+
- ✅ **插槽扩展** - 支持特殊区块和自定义字段插槽
|
|
13
|
+
- ✅ **TypeScript** - 完整的类型定义支持
|
|
14
|
+
|
|
15
|
+
### 🆕 增强功能
|
|
16
|
+
|
|
17
|
+
- ✅ **楼层导航** - 左侧/右侧导航,支持锚点跳转
|
|
18
|
+
- ✅ **工具栏** - 内置必填字段过滤开关,可扩展自定义工具
|
|
19
|
+
- ✅ **布局切换** - 支持 2/3/4/5 列布局快速切换
|
|
20
|
+
- ✅ **顶部操作栏** - 可配置标题和操作按钮
|
|
21
|
+
- ✅ **自动过滤** - 组件内部自动处理必填字段过滤逻辑
|
|
22
|
+
|
|
23
|
+
## 📖 基础用法
|
|
24
|
+
|
|
25
|
+
```vue
|
|
26
|
+
<template>
|
|
27
|
+
<c_formSections
|
|
28
|
+
:sections="sectionsConfig"
|
|
29
|
+
:form="form"
|
|
30
|
+
v-model:activeNames="activeNames"
|
|
31
|
+
/>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup lang="ts">
|
|
35
|
+
import { ref } from "vue";
|
|
36
|
+
import c_formSections from "@/components/local/c_formSections/index.vue";
|
|
37
|
+
|
|
38
|
+
const form = ref({
|
|
39
|
+
name: "",
|
|
40
|
+
type: "",
|
|
41
|
+
description: ""
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const activeNames = ref(["1", "2"]);
|
|
45
|
+
|
|
46
|
+
const sectionsConfig = [
|
|
47
|
+
{
|
|
48
|
+
name: "1",
|
|
49
|
+
id: "section-1",
|
|
50
|
+
title: "基本信息",
|
|
51
|
+
fieldsConfig: [
|
|
52
|
+
{ prop: "name", label: "名称", type: "input", required: true },
|
|
53
|
+
{
|
|
54
|
+
prop: "type",
|
|
55
|
+
label: "类型",
|
|
56
|
+
type: "select",
|
|
57
|
+
required: true,
|
|
58
|
+
options: [
|
|
59
|
+
{ label: "类型A", value: "A" },
|
|
60
|
+
{ label: "类型B", value: "B" }
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "2",
|
|
67
|
+
id: "section-2",
|
|
68
|
+
title: "详细信息",
|
|
69
|
+
fieldsConfig: [
|
|
70
|
+
{ prop: "description", label: "描述", type: "textarea", rows: 4 }
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
</script>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 🆕 完整功能用法
|
|
78
|
+
|
|
79
|
+
```vue
|
|
80
|
+
<template>
|
|
81
|
+
<c_formSections
|
|
82
|
+
:sections="sectionsConfig"
|
|
83
|
+
:form="form"
|
|
84
|
+
v-model:activeNames="activeNames"
|
|
85
|
+
show-header
|
|
86
|
+
header-title="主档维护"
|
|
87
|
+
:header-actions="headerActions"
|
|
88
|
+
show-toolbar
|
|
89
|
+
show-required-filter
|
|
90
|
+
show-layout-switch
|
|
91
|
+
:default-layout="5"
|
|
92
|
+
:layout-options="[2, 3, 4, 5]"
|
|
93
|
+
show-nav-tabs
|
|
94
|
+
nav-tabs-position="left"
|
|
95
|
+
:nav-tabs="navTabsConfig"
|
|
96
|
+
label-width="100px"
|
|
97
|
+
label-position="right"
|
|
98
|
+
:gutter="20"
|
|
99
|
+
>
|
|
100
|
+
<!-- 特殊区块插槽 -->
|
|
101
|
+
<template #special-3>
|
|
102
|
+
<el-button>自定义内容</el-button>
|
|
103
|
+
</template>
|
|
104
|
+
</c_formSections>
|
|
105
|
+
</template>
|
|
106
|
+
|
|
107
|
+
<script setup lang="ts">
|
|
108
|
+
import { Check, Document } from "@element-plus/icons-vue";
|
|
109
|
+
|
|
110
|
+
const headerActions = [
|
|
111
|
+
{
|
|
112
|
+
label: "保存",
|
|
113
|
+
type: "primary",
|
|
114
|
+
icon: Check,
|
|
115
|
+
onClick: () => console.log("保存")
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: "取消",
|
|
119
|
+
onClick: () => console.log("取消")
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const navTabsConfig = [
|
|
124
|
+
{ label: "基本信息", name: "basic", sectionName: "1" },
|
|
125
|
+
{ label: "详细信息", name: "detail", sectionName: "2" }
|
|
126
|
+
];
|
|
127
|
+
</script>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 🔧 Props
|
|
131
|
+
|
|
132
|
+
### 基础属性
|
|
133
|
+
|
|
134
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
135
|
+
| ------------- | ---------------------------------------- | ---------------------------- | --------- |
|
|
136
|
+
| sections | 表单区块配置数组 | `SectionConfig[]` | `[]` |
|
|
137
|
+
| form | 表单数据对象 | `FormDataType` | `{}` |
|
|
138
|
+
| activeNames | 激活的折叠面板 name 数组(支持 v-model) | `string[]` | `[]` |
|
|
139
|
+
| rules | 表单验证规则 | `any` | - |
|
|
140
|
+
| labelWidth | 表单标签宽度 | `string` | `'100px'` |
|
|
141
|
+
| labelPosition | 表单标签位置 | `'left' \| 'right' \| 'top'` | `'right'` |
|
|
142
|
+
| gutter | 栅格间距 | `number` | `20` |
|
|
143
|
+
| fieldSpan | 每个字段占据的栅格数(手动控制时使用) | `number` | - |
|
|
144
|
+
|
|
145
|
+
### 🆕 增强属性
|
|
146
|
+
|
|
147
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
148
|
+
| ------------------ | ------------------------------------------ | ------------------------- | ------------ |
|
|
149
|
+
| showHeader | 是否显示顶部标题栏 | `boolean` | `false` |
|
|
150
|
+
| headerTitle | 标题栏标题文本 | `string` | `'主档维护'` |
|
|
151
|
+
| headerActions | 顶部操作按钮 | `HeaderAction[]` | `[]` |
|
|
152
|
+
| showToolbar | 是否显示工具栏 | `boolean` | `false` |
|
|
153
|
+
| showRequiredFilter | 是否显示必填字段过滤开关 | `boolean` | `false` |
|
|
154
|
+
| showLayoutSwitch | 是否显示布局切换器 | `boolean` | `false` |
|
|
155
|
+
| defaultLayout | 默认布局列数 | `2 \| 3 \| 4 \| 5` | `5` |
|
|
156
|
+
| layoutOptions | 可选布局列数 | `Array<2 \| 3 \| 4 \| 5>` | `[2,3,4,5]` |
|
|
157
|
+
| showNavTabs | 是否显示楼层导航 | `boolean` | `false` |
|
|
158
|
+
| navTabsPosition | 楼层导航位置 | `'left' \| 'right'` | `'left'` |
|
|
159
|
+
| navTabs | 楼层导航配置(不传则自动从 sections 生成) | `NavTabConfig[]` | `[]` |
|
|
160
|
+
|
|
161
|
+
## 📊 配置接口
|
|
162
|
+
|
|
163
|
+
### SectionConfig
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
interface SectionConfig {
|
|
167
|
+
/** 折叠面板的 name 值(唯一标识) */
|
|
168
|
+
name: string;
|
|
169
|
+
/** 折叠面板 ID(用于锚点跳转) */
|
|
170
|
+
id: string;
|
|
171
|
+
/** 显示的标题 */
|
|
172
|
+
title: string;
|
|
173
|
+
/** 字段配置数组 */
|
|
174
|
+
fieldsConfig: FieldConfig[];
|
|
175
|
+
/** 显示条件函数(可选) */
|
|
176
|
+
visible?: () => boolean;
|
|
177
|
+
/** 是否为特殊处理的区块 */
|
|
178
|
+
isSpecial?: boolean;
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### FieldConfig
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
interface FieldConfig {
|
|
186
|
+
/** 字段属性名 */
|
|
187
|
+
prop: string;
|
|
188
|
+
/** 字段标签 */
|
|
189
|
+
label: string;
|
|
190
|
+
/** 字段类型 */
|
|
191
|
+
type?:
|
|
192
|
+
| "input"
|
|
193
|
+
| "select"
|
|
194
|
+
| "textarea"
|
|
195
|
+
| "date"
|
|
196
|
+
| "datetime"
|
|
197
|
+
| "number"
|
|
198
|
+
| "custom";
|
|
199
|
+
/** 栅格占据列数 */
|
|
200
|
+
span?: number;
|
|
201
|
+
/** 是否必填 */
|
|
202
|
+
required?: boolean;
|
|
203
|
+
/** 占位符文本 */
|
|
204
|
+
placeholder?: string;
|
|
205
|
+
/** 是否可清空(select) */
|
|
206
|
+
clearable?: boolean;
|
|
207
|
+
/** 下拉选项(select) */
|
|
208
|
+
options?: Array<{ label: string; value: string | number }>;
|
|
209
|
+
/** 文本域行数(textarea) */
|
|
210
|
+
rows?: number;
|
|
211
|
+
/** 最小值(number) */
|
|
212
|
+
min?: number;
|
|
213
|
+
/** 最大值(number) */
|
|
214
|
+
max?: number;
|
|
215
|
+
/** 数字精度(number) */
|
|
216
|
+
precision?: number;
|
|
217
|
+
/** 步长(number) */
|
|
218
|
+
step?: number;
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### 🆕 HeaderAction
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
interface HeaderAction {
|
|
226
|
+
/** 按钮文本 */
|
|
227
|
+
label: string;
|
|
228
|
+
/** 按钮类型 */
|
|
229
|
+
type?: "primary" | "success" | "warning" | "danger" | "info" | "text" | "";
|
|
230
|
+
/** 图标(Element Plus Icon 组件) */
|
|
231
|
+
icon?: Component;
|
|
232
|
+
/** 点击事件回调 */
|
|
233
|
+
onClick: () => void;
|
|
234
|
+
/** 是否禁用 */
|
|
235
|
+
disabled?: boolean;
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 🆕 NavTabConfig
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
interface NavTabConfig {
|
|
243
|
+
/** 标签名称(唯一标识) */
|
|
244
|
+
name: string;
|
|
245
|
+
/** 显示文本 */
|
|
246
|
+
label: string;
|
|
247
|
+
/** 关联的 section name(用于锚点跳转) */
|
|
248
|
+
sectionName?: string | null;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## 🎨 插槽
|
|
253
|
+
|
|
254
|
+
### 🆕 工具栏插槽
|
|
255
|
+
|
|
256
|
+
**toolbar-left** - 工具栏左侧自定义内容:
|
|
257
|
+
|
|
258
|
+
```vue
|
|
259
|
+
<c_formSections>
|
|
260
|
+
<template #toolbar-left>
|
|
261
|
+
<el-button size="small">自定义按钮</el-button>
|
|
262
|
+
</template>
|
|
263
|
+
</c_formSections>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**toolbar-right** - 工具栏右侧自定义内容:
|
|
267
|
+
|
|
268
|
+
```vue
|
|
269
|
+
<c_formSections>
|
|
270
|
+
<template #toolbar-right>
|
|
271
|
+
<span>自定义文本</span>
|
|
272
|
+
</template>
|
|
273
|
+
</c_formSections>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 特殊区块插槽
|
|
277
|
+
|
|
278
|
+
用于渲染 `isSpecial: true` 的区块自定义内容:
|
|
279
|
+
|
|
280
|
+
```vue
|
|
281
|
+
<c_formSections :sections="sections" :form="form">
|
|
282
|
+
<template #special-3="{ section }">
|
|
283
|
+
<el-row :gutter="20">
|
|
284
|
+
<el-col :span="24">
|
|
285
|
+
<el-button type="primary" @click="addItem">+ 添加项</el-button>
|
|
286
|
+
</el-col>
|
|
287
|
+
</el-row>
|
|
288
|
+
</template>
|
|
289
|
+
</c_formSections>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### 自定义字段插槽
|
|
293
|
+
|
|
294
|
+
用于渲染 `type: 'custom'` 的字段自定义内容:
|
|
295
|
+
|
|
296
|
+
```vue
|
|
297
|
+
<c_formSections :sections="sections" :form="form">
|
|
298
|
+
<template #field-customField="{ field, form }">
|
|
299
|
+
<custom-input v-model="form[field.prop]" />
|
|
300
|
+
</template>
|
|
301
|
+
</c_formSections>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## 📝 完整示例
|
|
305
|
+
|
|
306
|
+
```vue
|
|
307
|
+
<template>
|
|
308
|
+
<div class="form-container">
|
|
309
|
+
<!-- 必填字段过滤开关 -->
|
|
310
|
+
<el-switch v-model="showRequiredOnly" />
|
|
311
|
+
|
|
312
|
+
<!-- 表单区块组件 -->
|
|
313
|
+
<c-form-sections
|
|
314
|
+
:sections="visibleSections"
|
|
315
|
+
:form="form"
|
|
316
|
+
v-model:activeNames="activeNames"
|
|
317
|
+
:rules="formRules"
|
|
318
|
+
:fieldSpan="layoutColumns === 2 ? 12 : 6"
|
|
319
|
+
>
|
|
320
|
+
<!-- 特殊需求区块 -->
|
|
321
|
+
<template #special-3>
|
|
322
|
+
<el-row :gutter="20">
|
|
323
|
+
<el-col :span="24">
|
|
324
|
+
<el-button type="primary" plain @click="addRequirement">
|
|
325
|
+
+ 添加需求
|
|
326
|
+
</el-button>
|
|
327
|
+
</el-col>
|
|
328
|
+
</el-row>
|
|
329
|
+
</template>
|
|
330
|
+
</c-form-sections>
|
|
331
|
+
</div>
|
|
332
|
+
</template>
|
|
333
|
+
|
|
334
|
+
<script setup lang="ts">
|
|
335
|
+
import { ref, computed } from "vue";
|
|
336
|
+
import CFormSections from "@/components/local/c_formSections/index.vue";
|
|
337
|
+
import { filterFieldsByRequired } from "@/components/local/c_formSections/data";
|
|
338
|
+
|
|
339
|
+
const showRequiredOnly = ref(false);
|
|
340
|
+
const layoutColumns = ref(5);
|
|
341
|
+
const activeNames = ref(["1", "2", "3"]);
|
|
342
|
+
|
|
343
|
+
const form = ref({
|
|
344
|
+
name: "",
|
|
345
|
+
code: "",
|
|
346
|
+
type: "",
|
|
347
|
+
count: 0,
|
|
348
|
+
date: null
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const sectionsConfigRaw = [
|
|
352
|
+
{
|
|
353
|
+
name: "1",
|
|
354
|
+
id: "section-1",
|
|
355
|
+
title: "基本信息",
|
|
356
|
+
fieldsConfig: [
|
|
357
|
+
{ prop: "name", label: "名称", required: true },
|
|
358
|
+
{ prop: "code", label: "编码", required: true },
|
|
359
|
+
{
|
|
360
|
+
prop: "type",
|
|
361
|
+
label: "类型",
|
|
362
|
+
type: "select",
|
|
363
|
+
options: [
|
|
364
|
+
{ label: "类型A", value: "A" },
|
|
365
|
+
{ label: "类型B", value: "B" }
|
|
366
|
+
]
|
|
367
|
+
}
|
|
368
|
+
]
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: "2",
|
|
372
|
+
id: "section-2",
|
|
373
|
+
title: "详细信息",
|
|
374
|
+
fieldsConfig: [
|
|
375
|
+
{ prop: "count", label: "数量", type: "number", min: 0 },
|
|
376
|
+
{ prop: "date", label: "日期", type: "date" }
|
|
377
|
+
]
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
name: "3",
|
|
381
|
+
id: "section-3",
|
|
382
|
+
title: "特殊需求",
|
|
383
|
+
fieldsConfig: [],
|
|
384
|
+
isSpecial: true,
|
|
385
|
+
visible: () => !showRequiredOnly.value
|
|
386
|
+
}
|
|
387
|
+
];
|
|
388
|
+
|
|
389
|
+
// 动态过滤字段
|
|
390
|
+
const visibleSections = computed(() => {
|
|
391
|
+
return sectionsConfigRaw.map((section) => ({
|
|
392
|
+
...section,
|
|
393
|
+
fieldsConfig: filterFieldsByRequired(
|
|
394
|
+
section.fieldsConfig,
|
|
395
|
+
showRequiredOnly.value
|
|
396
|
+
)
|
|
397
|
+
}));
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const formRules = {
|
|
401
|
+
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
|
|
402
|
+
code: [{ required: true, message: "请输入编码", trigger: "blur" }]
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const addRequirement = () => {
|
|
406
|
+
console.log("添加特殊需求");
|
|
407
|
+
};
|
|
408
|
+
</script>
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## 🛠️ 工具函数
|
|
412
|
+
|
|
413
|
+
### filterFieldsByRequired
|
|
414
|
+
|
|
415
|
+
根据必填条件过滤字段配置:
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
import { filterFieldsByRequired } from "@/components/local/c_formSections/data";
|
|
419
|
+
|
|
420
|
+
const filteredFields = filterFieldsByRequired(fieldsConfig, true);
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### hasSectionFields
|
|
424
|
+
|
|
425
|
+
判断区块是否有可显示的字段:
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
import { hasSectionFields } from "@/components/local/c_formSections/data";
|
|
429
|
+
|
|
430
|
+
const hasFields = hasSectionFields(section.fieldsConfig);
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### generateDefaultFormData
|
|
434
|
+
|
|
435
|
+
生成默认表单数据:
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
import { generateDefaultFormData } from "@/components/local/c_formSections/data";
|
|
439
|
+
|
|
440
|
+
const defaultForm = generateDefaultFormData(sectionsConfig);
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## 💡 最佳实践
|
|
444
|
+
|
|
445
|
+
1. **配置管理** - 将 sections 配置放在独立的 data.ts 文件中
|
|
446
|
+
2. **类型安全** - 使用 TypeScript 定义表单数据接口
|
|
447
|
+
3. **动态过滤** - 使用 computed 实现响应式字段过滤
|
|
448
|
+
4. **插槽使用** - 对于复杂的自定义字段,使用插槽扩展
|
|
449
|
+
5. **验证规则** - 配合 Element Plus 的 rules 实现表单验证
|
|
450
|
+
|
|
451
|
+
## 🎯 应用场景
|
|
452
|
+
|
|
453
|
+
- ✅ 订单新增/编辑页面
|
|
454
|
+
- ✅ 配置管理表单
|
|
455
|
+
- ✅ 多区块复杂表单
|
|
456
|
+
- ✅ 需要动态显示/隐藏字段的表单
|
|
457
|
+
- ✅ 企业级业务系统表单页面
|
|
458
|
+
|
|
459
|
+
## 📚 真实项目示例
|
|
460
|
+
|
|
461
|
+
项目中已有完整可用的示例页面,可作为开发模板:
|
|
462
|
+
|
|
463
|
+
### 新增编辑页示例
|
|
464
|
+
|
|
465
|
+
**路径**: `src/views/sale/demo/add-demo/`
|
|
466
|
+
|
|
467
|
+
**特性**:
|
|
468
|
+
|
|
469
|
+
- ✅ 使用 c_formSections 组件展示所有功能
|
|
470
|
+
- ✅ 集成楼层导航、布局切换、必填过滤
|
|
471
|
+
- ✅ 配置驱动的表单字段(50+ 字段)
|
|
472
|
+
- ✅ 真实的保存/草稿/取消逻辑(使用 request + Mock)
|
|
473
|
+
- ✅ 项次信息管理(带分页,使用 jh-pagination)
|
|
474
|
+
- ✅ 全屏模式支持
|
|
475
|
+
- ✅ jh-drag-row 拖拽调整布局
|
|
476
|
+
|
|
477
|
+
**使用方式**:
|
|
478
|
+
|
|
479
|
+
1. 复制 `add-demo` 目录作为模板
|
|
480
|
+
2. 修改 `data.ts` 中的 API_CONFIG 为实际接口地址
|
|
481
|
+
3. 修改 `formFieldsData` 配置为业务字段
|
|
482
|
+
4. 修改 `modalConfig` 为业务需求
|
|
483
|
+
5. 创建对应的 Mock 文件(开发阶段)
|
|
484
|
+
|
|
485
|
+
**关键代码结构**:
|
|
486
|
+
|
|
487
|
+
```
|
|
488
|
+
add-demo/
|
|
489
|
+
├── index.vue # 视图层(176行)- 组件使用和布局
|
|
490
|
+
├── data.ts # 逻辑层(400+行)- 配置和业务逻辑
|
|
491
|
+
├── index.scss # 样式层(207行)- 页面样式
|
|
492
|
+
└── mock/
|
|
493
|
+
└── add-demo.ts # Mock 数据(50条项次数据)
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**推荐作为团队内部的标准模板使用!**
|