| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- <template>
- <view class="dynamic-form-page">
- <view class="debug-info">
- <text>调试信息:{{ JSON.stringify(formData, null, 2) }}</text>
- </view>
-
- <!-- 加载状态 -->
- <view v-if="loading" class="loading">
- <text>正在加载数据...</text>
- </view>
-
- <!-- 动态表单 -->
- <Form v-else :rules="fieldConfigs" v-model="formData" ref="formRef">
- <!-- 动态渲染区域 -->
- <template v-for="area in areaList" :key="area.id">
- <table-title>{{ area.name }}</table-title>
- <up-table>
- <!-- 动态渲染字段 -->
- <up-tr v-for="field in area.fields" :key="field.key">
- <up-th>{{ field.label }}</up-th>
- <Td :field="`${area.id}.${field.key}`">
- <!-- 根据字段类型渲染不同组件 -->
- <SsInput
- v-if="field.type === 'input' || !field.type"
- v-model="formData[area.id][field.key]"
- :placeholder="`请输入${field.label}`"
- />
-
- <!-- 这里可以扩展其他组件类型 -->
- <!--
- <ss-select
- v-else-if="field.type === 'select'"
- v-model="formData[area.id][field.key]"
- :options="field.options"
- :placeholder="`请选择${field.label}`"
- />
- -->
- </Td>
- </up-tr>
- </up-table>
- </template>
-
- <!-- 提交按钮 -->
- <view class="submit-section">
- <up-button @click="handleSubmit" type="primary">提交表单</up-button>
- <up-button @click="handleReset" style="margin-left: 20rpx;">重置</up-button>
- </view>
- </Form>
- </view>
- </template>
- <script setup>
- import { ref, onMounted } from 'vue'
- import Form from '@/components/Form/index.vue'
- import Td from '@/components/Td/index.vue'
- import SsInput from '@/components/SsInput/index.vue'
- import TableTitle from '@/components/SsTableTitle/index.vue'
- // 响应式数据
- const formData = ref({})
- const fieldConfigs = ref({})
- const areaList = ref([])
- const loading = ref(true)
- const formRef = ref(null)
- // 模拟API调用
- const fetchAreaData = async () => {
- // 模拟网络延迟
- await new Promise(resolve => setTimeout(resolve, 1500))
-
- return {
- areas: [
- {
- id: 'campus_activity',
- name: '校园活动区',
- fields: [
- {
- key: 'description',
- label: '情况描述',
- type: 'input',
- required: true,
- defaultValue: '正常运行'
- },
- {
- key: 'handler',
- label: '处理人',
- type: 'input',
- required: true,
- defaultValue: '张三'
- },
- {
- key: 'remark',
- label: '备注',
- type: 'input',
- required: false,
- defaultValue: ''
- }
- ]
- },
- {
- id: 'living_area',
- name: '生活区',
- fields: [
- {
- key: 'description',
- label: '情况描述',
- type: 'input',
- required: true,
- defaultValue: '环境良好'
- },
- {
- key: 'cleaner',
- label: '清洁人员',
- type: 'input',
- required: true,
- defaultValue: '李四'
- }
- ]
- },
- {
- id: 'study_area',
- name: '学习区',
- fields: [
- {
- key: 'description',
- label: '情况描述',
- type: 'input',
- required: true,
- defaultValue: '设备完好'
- },
- {
- key: 'equipment_count',
- label: '设备数量',
- type: 'input',
- required: false,
- defaultValue: '10'
- }
- ]
- }
- ]
- }
- }
- // 初始化数据
- const initFormData = async () => {
- try {
- loading.value = true
-
- // 1. 获取区域数据
- const response = await fetchAreaData()
- areaList.value = response.areas
-
- // 2. 动态构建formData和校验规则
- const newFormData = {}
- const newFieldConfigs = {}
-
- areaList.value.forEach(area => {
- newFormData[area.id] = {}
-
- area.fields.forEach(field => {
- // 初始化字段值
- newFormData[area.id][field.key] = field.defaultValue || ''
-
- // 构建校验规则 - 使用嵌套字段名
- const fieldName = `${area.id}.${field.key}`
- newFieldConfigs[fieldName] = {
- rules: field.required ? [
- { required: true, message: `${field.label}不能为空` }
- ] : []
- }
- })
- })
-
- // 3. 更新响应式数据
- formData.value = newFormData
- fieldConfigs.value = newFieldConfigs
-
- console.log('初始化完成:', {
- formData: formData.value,
- fieldConfigs: fieldConfigs.value
- })
-
- } catch (error) {
- console.error('初始化失败:', error)
- uni.showToast({
- title: '数据加载失败',
- icon: 'error'
- })
- } finally {
- loading.value = false
- }
- }
- // 提交表单
- const handleSubmit = async () => {
- if (formRef.value) {
- try {
- const isValid = formRef.value.validateForm(formData.value, fieldConfigs.value)
- console.log('校验结果:', isValid)
-
- if (isValid) {
- console.log('提交数据:', formData.value)
- uni.showToast({
- title: '提交成功',
- icon: 'success'
- })
- // 这里可以调用API提交数据
- } else {
- uni.showToast({
- title: '请检查表单信息',
- icon: 'none'
- })
- }
- } catch (error) {
- console.error('提交失败:', error)
- uni.showToast({
- title: '提交失败',
- icon: 'error'
- })
- }
- }
- }
- // 重置表单
- const handleReset = () => {
- initFormData()
- }
- // 组件挂载时初始化
- onMounted(() => {
- initFormData()
- })
- </script>
- <style lang="scss" scoped>
- .dynamic-form-page {
- padding: 20rpx;
- }
- .debug-info {
- background: #f5f5f5;
- padding: 20rpx;
- margin-bottom: 20rpx;
- border-radius: 10rpx;
-
- text {
- font-size: 24rpx;
- color: #666;
- white-space: pre-wrap;
- }
- }
- .loading {
- text-align: center;
- padding: 100rpx 0;
-
- text {
- color: #999;
- }
- }
- .submit-section {
- margin-top: 40rpx;
- padding: 20rpx;
- text-align: center;
- }
- </style>
|