126 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
| 明白你的实际需求是这样的:
 | ||
| 
 | ||
| ✅ 你有多个类似的表单表格页面
 | ||
| 结构类似,都是用 <el-table> + <el-table-column> 组成。
 | ||
| 
 | ||
| 不想复制粘贴逻辑去控制字段显示与否。
 | ||
| 
 | ||
| ✅ 每个账号登录后,后端会返回字段权限控制数组
 | ||
| 例如:
 | ||
| 
 | ||
| json
 | ||
| 复制
 | ||
| 编辑
 | ||
| ["customerName", "companyAccount", "companyAddress"]
 | ||
| 你希望根据这个字段列表来自动控制每一列是否显示,不再手动加 v-if="showField('xxx')"。
 | ||
| 
 | ||
| ✅ 目标:让字段显示/隐藏逻辑封装好,不影响页面使用结构
 | ||
| 你想要的最终效果是:
 | ||
| 
 | ||
| vue
 | ||
| 复制
 | ||
| 编辑
 | ||
| <!-- 外部写法保持不变,只改 el-table 为 FormTable -->
 | ||
| <FormTable :data="formData" :visible-fields="visibleFields">
 | ||
|   <el-table-column label="序号" type="index" width="100" />
 | ||
| 
 | ||
|   <el-table-column label="单位名称" prop="customerName">
 | ||
|     <!-- 表单结构 -->
 | ||
|   </el-table-column>
 | ||
| 
 | ||
|   <el-table-column label="开户账号" prop="companyAccount">
 | ||
|     <!-- 表单结构 -->
 | ||
|   </el-table-column>
 | ||
| </FormTable>
 | ||
| ✅ 解决方案:封装 FormTable,自动隐藏字段(通过 prop 字段)
 | ||
| 我们只需要在封装组件中 拦截 slot 中的 el-table-column,判断其 prop 是否在权限字段中,不在就不渲染。
 | ||
| 
 | ||
| ✅ 封装组件 FormTable.vue
 | ||
| vue
 | ||
| 复制
 | ||
| 编辑
 | ||
| <template>
 | ||
|   <el-table :data="data" v-bind="$attrs" class="-mt-10px">
 | ||
|     <component
 | ||
|       v-for="(vnode, index) in filteredColumns"
 | ||
|       :is="vnode"
 | ||
|       :key="index"
 | ||
|     />
 | ||
|   </el-table>
 | ||
| </template>
 | ||
| 
 | ||
| <script setup lang="ts">
 | ||
| import { useSlots, computed } from 'vue'
 | ||
| 
 | ||
| const props = defineProps<{
 | ||
|   data: any[]
 | ||
|   visibleFields: string[] // 后端返回的字段权限列表
 | ||
| }>()
 | ||
| 
 | ||
| const slots = useSlots()
 | ||
| 
 | ||
| // 处理 slots 中的 column,仅保留 prop 在 visibleFields 里的
 | ||
| const filteredColumns = computed(() => {
 | ||
|   const defaultSlot = slots.default?.() || []
 | ||
| 
 | ||
|   return defaultSlot.filter((vnode: any) => {
 | ||
|     // 保留不含 prop 的列(如序号/操作列)
 | ||
|     const prop = vnode.props?.prop
 | ||
|     if (!prop) return true
 | ||
|     return props.visibleFields.includes(prop)
 | ||
|   })
 | ||
| })
 | ||
| </script>
 | ||
| ✅ 父组件使用方式(完全一样,只加一个 visibleFields)
 | ||
| vue
 | ||
| 复制
 | ||
| 编辑
 | ||
| <FormTable :data="formData" :visible-fields="visibleFields">
 | ||
|   <el-table-column label="序号" type="index" width="100" />
 | ||
| 
 | ||
|   <el-table-column label="单位名称" prop="customerName">
 | ||
|     <template #default="{ row, $index }">
 | ||
|       <el-form-item :prop="`${$index}.customerName`" :rules="formRules.customerName">
 | ||
|         <el-input v-model="row.customerName" placeholder="请输入单位名称" />
 | ||
|       </el-form-item>
 | ||
|     </template>
 | ||
|   </el-table-column>
 | ||
| 
 | ||
|   <el-table-column label="开户账号" prop="companyAccount">
 | ||
|     <template #default="{ row, $index }">
 | ||
|       <el-form-item :prop="`${$index}.companyAccount`" :rules="formRules.companyAccount">
 | ||
|         <el-input v-model="row.companyAccount" placeholder="请输入开户账号" />
 | ||
|       </el-form-item>
 | ||
|     </template>
 | ||
|   </el-table-column>
 | ||
| 
 | ||
|   <!-- 操作列不写 prop,自动保留 -->
 | ||
|   <el-table-column label="操作" fixed="right" width="60">
 | ||
|     <template #default="{ $index }">
 | ||
|       <el-button @click="handleDelete($index)" link>—</el-button>
 | ||
|     </template>
 | ||
|   </el-table-column>
 | ||
| </FormTable>
 | ||
| ✅ 后端返回字段控制
 | ||
| 你只需要从后端返回一个字段列表,比如:
 | ||
| 
 | ||
| ts
 | ||
| 复制
 | ||
| 编辑
 | ||
| const visibleFields = ['customerName', 'companyAccount']
 | ||
| 然后传给 FormTable 即可:
 | ||
| 
 | ||
| vue
 | ||
| 复制
 | ||
| 编辑
 | ||
| <FormTable :data="formData" :visible-fields="visibleFields">...</FormTable>
 | ||
| ✅ 总结优点
 | ||
| ✅ 只改 <el-table> 为 <FormTable>,其他逻辑不动。
 | ||
| 
 | ||
| ✅ 无需手动每列写 v-if。
 | ||
| 
 | ||
| ✅ 可根据后端返回字段权限自动显示/隐藏。
 | ||
| 
 | ||
| ✅ 支持任意结构(form-item、插槽等)。
 | ||
| 
 | ||
| 需要我帮你做完整的 .vue 文件模板或添加分页/loading 也可以继续说。 |