- 修复路由守卫:未登录时直接跳转,不显示提示信息 - 修复API拦截器:401错误直接跳转,无需确认 - 移除不必要的ElMessageBox确认框 - 优化Token过期处理逻辑 - 修复文件管理API引入路径和URL前缀 - 修复调拨/回收管理API端点不匹配问题 - 修复通知管理API方法不匹配问题 - 统一系统配置API路径为单数形式 影响文件: - src/router/index.ts - src/api/request.ts - src/api/file.ts - src/api/index.ts 测试状态: - 前端构建通过 - 所有API路径已验证 - 登录流程测试通过 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
476 lines
11 KiB
Markdown
476 lines
11 KiB
Markdown
# 动态表单组件组使用文档
|
||
|
||
> **版本**: v1.0.0
|
||
> **作者**: 动态表单组件组
|
||
> **创建时间**: 2025-01-24
|
||
|
||
---
|
||
|
||
## 📋 目录
|
||
|
||
1. [组件概述](#组件概述)
|
||
2. [核心组件](#核心组件)
|
||
3. [字段组件](#字段组件)
|
||
4. [工具函数](#工具函数)
|
||
5. [Composable](#composable)
|
||
6. [使用示例](#使用示例)
|
||
7. [API文档](#api文档)
|
||
8. [最佳实践](#最佳实践)
|
||
|
||
---
|
||
|
||
## 组件概述
|
||
|
||
动态表单组件组是资产管理系统的核心组件库,用于支持不同设备类型的自定义字段渲染和验证。
|
||
|
||
### 主要特性
|
||
|
||
- ✅ 支持多种字段类型(text、number、date、select、multiselect、boolean、textarea、tree等)
|
||
- ✅ 动态验证规则(必填、长度、正则、自定义验证)
|
||
- ✅ 字段联动(显示/隐藏、启用/禁用、值联动)
|
||
- ✅ 栅格布局支持
|
||
- ✅ 响应式设计
|
||
- ✅ TypeScript完整类型支持
|
||
- ✅ 统一的API接口
|
||
|
||
### 组件清单
|
||
|
||
| 组件名称 | 文件路径 | 功能说明 |
|
||
|---------|---------|---------|
|
||
| DynamicFieldRenderer | `@/components/form/DynamicFieldRenderer.vue` | 动态字段渲染器(核心组件) |
|
||
| FieldDesigner | `@/components/form/FieldDesigner.vue` | 字段配置设计器 |
|
||
| TextField | `@/components/form/fields/TextField.vue` | 单行文本输入 |
|
||
| NumberField | `@/components/form/fields/NumberField.vue` | 数字输入 |
|
||
| TextareaField | `@/components/form/fields/TextareaField.vue` | 多行文本输入 |
|
||
| DateField | `@/components/form/fields/DateField.vue` | 日期选择器 |
|
||
| SelectField | `@/components/form/fields/SelectField.vue` | 下拉选择器 |
|
||
| MultiSelectField | `@/components/form/fields/MultiSelectField.vue` | 多选下拉 |
|
||
| BooleanField | `@/components/form/fields/BooleanField.vue` | 开关/复选框 |
|
||
| TreeSelect | `@/components/common/TreeSelect.vue` | 树形选择器 |
|
||
|
||
---
|
||
|
||
## 核心组件
|
||
|
||
### DynamicFieldRenderer 动态字段渲染器
|
||
|
||
最核心的组件,根据字段配置动态渲染表单。
|
||
|
||
#### 基础用法
|
||
|
||
```vue
|
||
<template>
|
||
<DynamicFieldRenderer
|
||
ref="formRef"
|
||
v-model="formData"
|
||
:fields="fields"
|
||
@field-change="handleFieldChange"
|
||
/>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref } from 'vue'
|
||
import DynamicFieldRenderer from '@/components/form/DynamicFieldRenderer.vue'
|
||
import type { FieldConfig } from '@/types/form'
|
||
|
||
const formRef = ref()
|
||
const formData = ref({
|
||
assetName: '',
|
||
cpu: '',
|
||
memory: ''
|
||
})
|
||
|
||
const fields: FieldConfig[] = [
|
||
{
|
||
id: '1',
|
||
name: 'assetName',
|
||
label: '资产名称',
|
||
fieldType: 'text',
|
||
required: true,
|
||
span: 12
|
||
},
|
||
{
|
||
id: '2',
|
||
name: 'cpu',
|
||
label: 'CPU型号',
|
||
fieldType: 'text',
|
||
required: true,
|
||
span: 12
|
||
}
|
||
]
|
||
</script>
|
||
```
|
||
|
||
#### Props
|
||
|
||
| 参数 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| modelValue | `FormData` | - | 表单数据(v-model) |
|
||
| fields | `FieldConfig[]` | [] | 字段配置列表 |
|
||
| readonly | `boolean` | false | 是否只读模式 |
|
||
| labelWidth | `string \| number` | '120px' | 标签宽度 |
|
||
| labelPosition | `'left' \| 'right' \| 'top'` | 'right' | 标签位置 |
|
||
| gutter | `number` | 20 | 栅格间隔 |
|
||
| dependencies | `FieldDependency[]` | [] | 字段联动配置 |
|
||
|
||
#### Emits
|
||
|
||
| 事件名 | 参数 | 说明 |
|
||
|--------|------|------|
|
||
| update:modelValue | `(value: FormData)` | 表单数据更新 |
|
||
| field-change | `(event: FieldChangeEvent)` | 字段值变化 |
|
||
| validation-change | `(state: FormValidationState)` | 验证状态变化 |
|
||
|
||
#### Methods
|
||
|
||
| 方法名 | 参数 | 返回值 | 说明 |
|
||
|--------|------|--------|------|
|
||
| validateField | `(fieldName: string)` | `Promise<boolean>` | 验证单个字段 |
|
||
| validateForm | - | `Promise<boolean>` | 验证整个表单 |
|
||
| resetForm | - | `void` | 重置表单 |
|
||
| clearValidation | - | `void` | 清除验证 |
|
||
| setFieldValue | `(fieldName: string, value: any)` | `void` | 设置字段值 |
|
||
| getFieldValue | `(fieldName: string)` | `any` | 获取字段值 |
|
||
| getFormData | - | `FormData` | 获取表单数据 |
|
||
| setFormData | `(data: FormData)` | `void` | 设置表单数据 |
|
||
|
||
---
|
||
|
||
## 字段组件
|
||
|
||
### FieldConfig 字段配置
|
||
|
||
```typescript
|
||
interface FieldConfig {
|
||
id: string // 字段唯一标识
|
||
name: string // 字段名称(用于提交)
|
||
label: string // 字段标签(显示名称)
|
||
fieldType: FieldType // 字段类型
|
||
required?: boolean // 是否必填
|
||
defaultValue?: any // 默认值
|
||
placeholder?: string // 占位符
|
||
options?: Array<{ // 选项(select/multiselect)
|
||
label: string
|
||
value: any
|
||
disabled?: boolean
|
||
}>
|
||
validationRules?: { // 验证规则
|
||
min?: number
|
||
max?: number
|
||
pattern?: string
|
||
custom?: (value: any, allData: Record<string, any>) => boolean | string
|
||
customMessage?: string
|
||
}
|
||
span?: number // 栅格占列数(1-24)
|
||
visible?: boolean | ((data: Record<string, any>) => boolean) // 是否显示
|
||
disabled?: boolean | ((data: Record<string, any>) => boolean) // 是否禁用
|
||
description?: string // 字段描述
|
||
className?: string // 自定义类名
|
||
treeData?: TreeNode[] // 树形数据(tree类型)
|
||
multiple?: boolean // 是否多选(tree类型)
|
||
}
|
||
```
|
||
|
||
### 字段类型(FieldType)
|
||
|
||
| 类型 | 说明 | 组件 |
|
||
|------|------|------|
|
||
| `text` | 单行文本 | TextField |
|
||
| `textarea` | 多行文本 | TextareaField |
|
||
| `number` | 数字输入 | NumberField |
|
||
| `date` | 日期选择 | DateField |
|
||
| `select` | 下拉选择 | SelectField |
|
||
| `multiselect` | 多选下拉 | MultiSelectField |
|
||
| `boolean` | 开关/复选框 | BooleanField |
|
||
| `tree` | 树形选择 | TreeSelect |
|
||
| `url` | URL链接 | TextField(带验证) |
|
||
| `email` | 邮箱 | TextField(带验证) |
|
||
| `phone` | 手机号 | TextField(带验证) |
|
||
|
||
---
|
||
|
||
## 工具函数
|
||
|
||
### fieldValidator 字段验证器
|
||
|
||
```typescript
|
||
import { validateField, validateFields } from '@/utils/fieldValidator'
|
||
|
||
// 验证单个字段
|
||
const result = validateField(value, field, allFormData)
|
||
// 返回: { isValid: boolean, errors: string[] }
|
||
|
||
// 验证所有字段
|
||
const errors = validateFields(data, fields)
|
||
// 返回: Record<string, string[]>
|
||
```
|
||
|
||
### FieldDependencyManager 字段联动管理器
|
||
|
||
```typescript
|
||
import { FieldDependencyManager, DependencyConditions, DependencyActions } from '@/utils/fieldDependency'
|
||
|
||
const manager = new FieldDependencyManager()
|
||
|
||
// 添加联动配置
|
||
manager.addDependency({
|
||
sourceField: 'deviceType',
|
||
targetField: 'cpu',
|
||
type: 'show',
|
||
condition: DependencyConditions.equals('desktop')
|
||
})
|
||
|
||
// 触发联动
|
||
const results = manager.trigger('deviceType', 'desktop', formData)
|
||
```
|
||
|
||
---
|
||
|
||
## Composable
|
||
|
||
### useDynamicForm
|
||
|
||
动态表单状态管理。
|
||
|
||
```typescript
|
||
import { useDynamicForm } from '@/composables/useDynamicForm'
|
||
|
||
const {
|
||
formData, // 表单数据
|
||
validationErrors, // 验证错误
|
||
isValid, // 是否有效
|
||
isDirty, // 是否已修改
|
||
isSubmitting, // 是否正在提交
|
||
setFieldValue, // 设置字段值
|
||
validateField, // 验证字段
|
||
validateAll, // 验证所有
|
||
resetForm, // 重置表单
|
||
getFormData, // 获取表单数据
|
||
submitForm // 提交表单
|
||
} = useDynamicForm(fields)
|
||
```
|
||
|
||
### useFieldConfig
|
||
|
||
字段配置管理。
|
||
|
||
```typescript
|
||
import { useFieldConfig } from '@/composables/useFieldConfig'
|
||
|
||
const {
|
||
loadFieldConfig, // 加载字段配置
|
||
getCachedFieldConfig, // 获取缓存配置
|
||
clearCache // 清除缓存
|
||
} = useFieldConfig()
|
||
|
||
// 加载设备类型的字段配置
|
||
const fields = await loadFieldConfig(deviceTypeId)
|
||
```
|
||
|
||
---
|
||
|
||
## 使用示例
|
||
|
||
### 示例1:基础表单
|
||
|
||
```vue
|
||
<template>
|
||
<DynamicFieldRenderer
|
||
v-model="formData"
|
||
:fields="fields"
|
||
/>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref } from 'vue'
|
||
import DynamicFieldRenderer from '@/components/form/DynamicFieldRenderer.vue'
|
||
|
||
const formData = ref({})
|
||
|
||
const fields = [
|
||
{
|
||
id: '1',
|
||
name: 'username',
|
||
label: '用户名',
|
||
fieldType: 'text',
|
||
required: true,
|
||
validationRules: {
|
||
min: 3,
|
||
max: 20
|
||
}
|
||
},
|
||
{
|
||
id: '2',
|
||
name: 'email',
|
||
label: '邮箱',
|
||
fieldType: 'email',
|
||
required: true
|
||
}
|
||
]
|
||
</script>
|
||
```
|
||
|
||
### 示例2:带字段联动
|
||
|
||
```vue
|
||
<script setup lang="ts">
|
||
const fields = [
|
||
{
|
||
id: '1',
|
||
name: 'country',
|
||
label: '国家',
|
||
fieldType: 'select',
|
||
options: [
|
||
{ label: '中国', value: 'CN' },
|
||
{ label: '美国', value: 'US' }
|
||
]
|
||
},
|
||
{
|
||
id: '2',
|
||
name: 'province',
|
||
label: '省份',
|
||
fieldType: 'select',
|
||
options: [], // 将通过联动动态加载
|
||
visible: (data) => !!data.country // 选择国家后才显示
|
||
}
|
||
]
|
||
|
||
const dependencies = [
|
||
{
|
||
sourceField: 'country',
|
||
targetField: 'province',
|
||
type: 'setValue',
|
||
condition: () => true,
|
||
action: async (target, source) => {
|
||
// 根据选择的国家加载省份列表
|
||
const provinces = await loadProvinces(source)
|
||
return provinces
|
||
}
|
||
}
|
||
]
|
||
</script>
|
||
```
|
||
|
||
### 示例3:自定义验证
|
||
|
||
```vue
|
||
<script setup lang="ts">
|
||
const fields = [
|
||
{
|
||
id: '1',
|
||
name: 'password',
|
||
label: '密码',
|
||
fieldType: 'text',
|
||
required: true,
|
||
validationRules: {
|
||
custom: (value, allData) => {
|
||
if (value.length < 8) {
|
||
return '密码长度不能少于8位'
|
||
}
|
||
if (!/[A-Z]/.test(value)) {
|
||
return '密码必须包含大写字母'
|
||
}
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
]
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## API文档
|
||
|
||
### 类型定义完整参考
|
||
|
||
详见 `@/types/form.ts`
|
||
|
||
### 常见问题
|
||
|
||
**Q: 如何动态加载选项?**
|
||
|
||
A: 使用字段联动配置的 `setValue` 类型配合异步函数:
|
||
|
||
```typescript
|
||
{
|
||
sourceField: 'category',
|
||
targetField: 'product',
|
||
type: 'setValue',
|
||
condition: () => true,
|
||
action: async () => {
|
||
const products = await api.getProducts()
|
||
return products
|
||
}
|
||
}
|
||
```
|
||
|
||
**Q: 如何实现条件验证?**
|
||
|
||
A: 使用 `custom` 验证函数:
|
||
|
||
```typescript
|
||
validationRules: {
|
||
custom: (value, allData) => {
|
||
if (allData.type === 'special' && !value) {
|
||
return '特殊类型必须填写此字段'
|
||
}
|
||
return true
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 字段命名规范
|
||
|
||
- 使用camelCase命名:`assetName`、`purchaseDate`
|
||
- 避免使用保留字:`name`、`id`、`value`
|
||
- 使用语义化命名:`cpuModel` 而非 `field1`
|
||
|
||
### 2. 验证规则设置
|
||
|
||
- 必填字段始终设置 `required: true`
|
||
- 文本字段设置合理的 `max` 限制
|
||
- 数字字段设置 `min` 和 `max` 范围
|
||
- 使用 `custom` 进行复杂验证
|
||
|
||
### 3. 字段联动设计
|
||
|
||
- 避免循环依赖
|
||
- 条件函数保持简单
|
||
- 联动动作尽可能轻量
|
||
|
||
### 4. 性能优化
|
||
|
||
- 使用字段缓存减少API请求
|
||
- 大表单使用懒加载
|
||
- 合理设置字段span优化布局
|
||
|
||
### 5. 错误处理
|
||
|
||
- 提供清晰的错误提示
|
||
- 使用自定义错误消息
|
||
- 验证失败时高亮显示错误字段
|
||
|
||
---
|
||
|
||
## 更新日志
|
||
|
||
### v1.0.0 (2025-01-24)
|
||
|
||
- ✨ 初始版本发布
|
||
- ✨ 支持基础字段类型
|
||
- ✨ 实现字段验证
|
||
- ✨ 实现字段联动
|
||
- ✨ 实现栅格布局
|
||
- 📝 完善文档和示例
|
||
|
||
---
|
||
|
||
## 支持
|
||
|
||
如有问题或建议,请联系开发团队。
|