Files
zcglxt/DYNAMIC_FORM_QUICKSTART.md
Claude e48975f9d5 fix: 修复前端登录体验和API调用问题
- 修复路由守卫:未登录时直接跳转,不显示提示信息
- 修复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>
2026-01-25 00:26:33 +08:00

6.8 KiB
Raw Blame History

动态表单组件 - 快速开始

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>

更多资源