- 修复路由守卫:未登录时直接跳转,不显示提示信息 - 修复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>
6.8 KiB
6.8 KiB
动态表单组件 - 快速开始
1. 基础使用
最简单的例子
<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
}
]
</script>
2. 添加验证
<script setup lang="ts">
const fields = [
{
id: '1',
name: 'email',
label: '邮箱',
fieldType: 'email',
required: true,
validationRules: {
pattern: '^[^@]+@[^@]+\\\\.[^@]+$',
customMessage: '请输入有效的邮箱地址'
}
},
{
id: '2',
name: 'age',
label: '年龄',
fieldType: 'number',
validationRules: {
min: 18,
max: 65
}
}
]
</script>
3. 字段联动
<template>
<DynamicFieldRenderer
v-model="formData"
:fields="fields"
:dependencies="dependencies"
/>
</template>
<script setup lang="ts">
const fields = [
{
id: '1',
name: 'hasDiscount',
label: '是否有优惠',
fieldType: 'boolean'
},
{
id: '2',
name: 'discountCode',
label: '优惠码',
fieldType: 'text',
// 只有选择有优惠时才显示
visible: (data) => data.hasDiscount === true
}
]
</script>
4. 处理表单提交
<template>
<DynamicFieldRenderer
ref="formRef"
v-model="formData"
:fields="fields"
/>
<el-button @click="handleSubmit">提交</el-button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const formRef = ref()
const formData = ref({})
const handleSubmit = async () => {
const valid = await formRef.value?.validateForm()
if (valid) {
console.log('表单数据:', formData.value)
ElMessage.success('提交成功')
}
}
</script>
5. 使用Composable
<script setup lang="ts">
import { useDynamicForm } from '@/composables/useDynamicForm'
const fields = [
// ... 字段配置
]
const {
formData, // 表单数据
isValid, // 是否验证通过
setFieldValue, // 设置字段值
validateAll, // 验证所有字段
submitForm // 提交表单
} = useDynamicForm(fields)
const handleSubmit = async () => {
await submitForm(async (data) => {
console.log('提交数据:', data)
})
}
</script>
6. 加载设备类型字段
<script setup lang="ts">
import { onMounted } from 'vue'
import { useFieldConfig } from '@/composables/useFieldConfig'
const { loadFieldConfig } = useFieldConfig()
const fields = ref([])
onMounted(async () => {
// 从API加载设备类型的字段配置
fields.value = await loadFieldConfig(1) // 1是设备类型ID
})
</script>
7. 常用字段类型示例
const fields = [
// 单行文本
{
id: '1',
name: 'title',
label: '标题',
fieldType: 'text',
required: true
},
// 多行文本
{
id: '2',
name: 'description',
label: '描述',
fieldType: 'textarea',
rows: 4
},
// 数字
{
id: '3',
name: 'price',
label: '价格',
fieldType: 'number',
validationRules: {
min: 0,
max: 999999
}
},
// 日期
{
id: '4',
name: 'birthday',
label: '生日',
fieldType: 'date'
},
// 下拉选择
{
id: '5',
name: 'gender',
label: '性别',
fieldType: 'select',
options: [
{ label: '男', value: 'male' },
{ label: '女', value: 'female' }
]
},
// 多选
{
id: '6',
name: 'hobbies',
label: '爱好',
fieldType: 'multiselect',
options: [
{ label: '读书', value: 'reading' },
{ label: '运动', value: 'sports' },
{ label: '音乐', value: 'music' }
]
},
// 开关
{
id: '7',
name: 'isActive',
label: '是否激活',
fieldType: 'boolean',
defaultValue: false
}
]
8. 布局控制
const fields = [
// 半行
{
id: '1',
name: 'firstName',
label: '名',
fieldType: 'text',
span: 12 // 占12列(半行)
},
// 半行
{
id: '2',
name: 'lastName',
label: '姓',
fieldType: 'text',
span: 12 // 占12列(半行)
},
// 整行
{
id: '3',
name: 'address',
label: '地址',
fieldType: 'text',
span: 24 // 占24列(整行)
}
]
9. 自定义验证
const fields = [
{
id: '1',
name: 'password',
label: '密码',
fieldType: 'text',
required: true,
validationRules: {
custom: (value) => {
if (value.length < 8) {
return '密码长度不能少于8位'
}
if (!/[A-Z]/.test(value)) {
return '密码必须包含大写字母'
}
if (!/[0-9]/.test(value)) {
return '密码必须包含数字'
}
return true
}
}
}
]
10. 完整示例
<template>
<el-card>
<DynamicFieldRenderer
ref="formRef"
v-model="formData"
:fields="fields"
label-width="100px"
@field-change="handleChange"
/>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button @click="handleReset">重置</el-button>
</el-card>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import DynamicFieldRenderer from '@/components/form/DynamicFieldRenderer.vue'
const formRef = ref()
const formData = ref({
username: '',
email: '',
role: 'user'
})
const fields = [
{
id: '1',
name: 'username',
label: '用户名',
fieldType: 'text',
required: true,
span: 12,
validationRules: {
min: 3,
max: 20
}
},
{
id: '2',
name: 'email',
label: '邮箱',
fieldType: 'email',
required: true,
span: 12
},
{
id: '3',
name: 'role',
label: '角色',
fieldType: 'select',
required: true,
span: 12,
options: [
{ label: '管理员', value: 'admin' },
{ label: '普通用户', value: 'user' }
]
},
{
id: '4',
name: 'isActive',
label: '激活状态',
fieldType: 'boolean',
span: 12,
defaultValue: true
}
]
const handleChange = (event) => {
console.log('字段变化:', event)
}
const handleSubmit = async () => {
const valid = await formRef.value?.validateForm()
if (valid) {
console.log('提交数据:', formData.value)
ElMessage.success('提交成功')
}
}
const handleReset = () => {
formRef.value?.resetForm()
}
</script>