详情组件

概述

详情组件是一套基于 Element Plus 封装的数据展示解决方案,用于展示表单数据的只读视图。通过 schema 配置即可快速构建数据详情页面,支持多种数据展示组件和灵活的配置方式。

快速开始

1. 引入组件

import { DetailForm, useDetailForm } from '@/components/form'

2. 定义详情结构

const schema = [
  {
    prop: 'name',
    label: '姓名',
    component: 'Input'
  },
  {
    prop: 'email',
    label: '邮箱',
    component: 'Input'
  }
]

const [DetailForm, detailFormApi] = useDetailForm({
  labelPosition: 'right',
  labelWidth: '100px',
  schema: schema
})

3. 在模板中使用

<template>
  <DetailForm :model="detailData" />
</template>

核心概念

DetailForm 配置

属性类型默认值说明
labelPosition'left' | 'right' | 'top''right'标签位置
gutternumber0栅格间隔
labelWidthstring'80px'标签宽度
schemaFormItemSchema[][]详情项配置
borderbooleantrue是否显示边框

FormItemSchema 详情项配置

属性类型必填说明
propstring详情项属性名
labelstring详情项标签
componentstring详情项组件类型
labelWidthstring | number标签宽度
colSpannumber栅格列数(1-24)
componentPropsRecord | Function组件属性配置
ifDetailboolean | Function动态显示控制
helpMessagestring | string[]帮助提示信息

内置详情组件

基础展示组件

  1. Select - 基础数据展示
{
  prop: 'status',
  label: '状态',
  component: 'Select',
  componentProps: {
    options: [
      { label: '启用', value: 1 },
      { label: '禁用', value: 0 }
    ]
  }
}
  1. DatePicker - 日期展示
{
  prop: 'createTime',
  label: '创建时间',
  component: 'DatePicker'
}
  1. RadioGroup - 单选展示
{
  prop: 'gender',
  label: '性别',
  component: 'RadioGroup',
  componentProps: {
    options: [
      { label: '男', value: 1 },
      { label: '女', value: 2 }
    ]
  }
}
  1. CheckboxGroup - 多选展示
{
  prop: 'hobbies',
  label: '爱好',
  component: 'CheckboxGroup',
  componentProps: {
    options: [
      { label: '读书', value: 'reading' },
      { label: '游泳', value: 'swimming' }
    ]
  }
}

远程数据展示组件

  1. ApiSelect - 远程数据展示
{
  prop: 'userId',
  label: '用户',
  component: 'ApiSelect',
  componentProps: {
    api: '/api/user/select'
  }
}
  1. ApiRadioGroup - 远程单选展示
{
  prop: 'categoryId',
  label: '分类',
  component: 'ApiRadioGroup',
  componentProps: {
    api: '/api/category/select'
  }
}
  1. ApiCheckboxGroup - 远程多选展示
{
  prop: 'tagIds',
  label: '标签',
  component: 'ApiCheckboxGroup',
  componentProps: {
    api: '/api/tag/select'
  }
}
  1. ApiTreeSelect - 远程树形数据展示
{
  prop: 'deptId',
  label: '部门',
  component: 'ApiTreeSelect',
  componentProps: {
    api: '/api/dept/tree'
  }
}
  1. ApiCascader - 远程级联数据展示
{
  prop: 'areaCode',
  label: '地区',
  component: 'ApiCascader',
  componentProps: {
    api: '/api/area/tree'
  }
}

字典展示组件

{
  prop: 'sex',
  label: '性别',
  component: 'ApiDict',
  componentProps: {
    code: 'sex'
  }
}

字典组件支持标签样式展示:

{
  prop: 'status',
  label: '状态',
  component: 'ApiDict',
  componentProps: {
    code: 'status',
    typeMap: {
      '1': 'success',
      '0': 'danger'
    },
    colorMap: {
      '1': { textColor: '#52c41a', bgColor: '#f6ffed' },
      '0': { textColor: '#ff4d4f', bgColor: '#fff2f0' }
    }
  }
}

特殊展示组件

  1. Upload - 文件展示
{
  prop: 'attachments',
  label: '附件',
  component: 'Upload',
  componentProps: {
    listType: 'text' // text/picture/picture-card
  }
}
  1. Editor - 富文本展示
{
  prop: 'content',
  label: '内容',
  component: 'Editor'
}
  1. IconPicker - 图标展示
{
  prop: 'icon',
  label: '图标',
  component: 'IconPicker'
}
  1. Avatar - 头像展示
{
  prop: 'avatar',
  label: '头像',
  component: 'Avatar'
}

布局组件

  1. Divider - 分割线
{
  prop: 'divider-basic',
  label: '',
  labelWidth: '0px',
  component: 'Divider',
  colSpan: 24,
  componentProps: {
    title: '基本信息'
  }
}

高级功能

动态显示控制

通过 ifDetail 属性控制详情项的显示:

{
  prop: 'type',
  label: '类型',
  component: 'Select',
  componentProps: {
    options: [
      { label: '类型1', value: 1 },
      { label: '类型2', value: 2 }
    ]
  }
},
{
  prop: 'field1',
  label: '字段1',
  component: 'Input',
  ifDetail: (values) => values.type === 1 // 当type为1时显示
}

动态属性配置

通过函数形式的 componentProps实现动态属性:

{
  prop: 'remark',
  label: '备注',
  component: 'Input',
  componentProps: (values) => {
    return {
      disabled: values.status === 0
    }
  }
}

详情方法

通过 useDetailForm 返回的 detailFormApi 可以调用以下方法:

const [DetailForm, detailFormApi] = useDetailForm(schema)

// 设置详情状态
detailFormApi.setState({ labelPosition: 'top' })

// 获取详情状态
detailFormApi.getState()

完整示例

<template>
  <div>
    <el-radio-group v-model="labelPosition">
      <el-radio-button value="left">左对齐</el-radio-button>
      <el-radio-button value="right">右对齐</el-radio-button>
      <el-radio-button value="top">顶部对齐</el-radio-button>
    </el-radio-group>
    
    <DetailForm 
      :model="detailData" 
      style="margin-top: 12px"
      :border="true"
    />
  </div>
</template>

<script setup lang="ts">
import { useDetailForm } from '@/components/form'

const labelPosition = ref<'left' | 'right' | 'top'>('right')

// 模拟详情数据
const detailData = ref({
  name: '张三',
  email: 'zhangsan@example.com',
  status: 1,
  gender: 1,
  createTime: '2023-01-01 12:00:00',
  avatar: 'https://example.com/avatar.jpg',
  content: '<p>这是富文本内容</p>'
})

const schema = [
  // 分割线
  {
    prop: 'divider-basic',
    label: '',
    labelWidth: '0px',
    component: 'Divider',
    colSpan: 24,
    componentProps: {
      title: '基本信息'
    }
  },
  {
    prop: 'name',
    label: '姓名',
    component: 'Input',
    colSpan: 12
  },
  {
    prop: 'email',
    label: '邮箱',
    component: 'Input',
    colSpan: 12
  },
  {
    prop: 'status',
    label: '状态',
    component: 'Select',
    colSpan: 12,
    componentProps: {
      options: [
        { label: '启用', value: 1 },
        { label: '禁用', value: 0 }
      ]
    }
  },
  {
    prop: 'gender',
    label: '性别',
    component: 'RadioGroup',
    colSpan: 12,
    componentProps: {
      options: [
        { label: '男', value: 1 },
        { label: '女', value: 2 }
      ]
    }
  },
  {
    prop: 'createTime',
    label: '创建时间',
    component: 'DatePicker',
    colSpan: 12
  },
  {
    prop: 'avatar',
    label: '头像',
    component: 'Avatar',
    colSpan: 12
  },
  {
    prop: 'content',
    label: '内容',
    component: 'Editor',
    colSpan: 24
  }
]

const [DetailForm, detailFormApi] = useDetailForm({
  labelPosition: labelPosition.value,
  labelWidth: '100px',
  schema: schema
})

// 监听标签位置变化
watch(() => labelPosition.value, (val) => {
  detailFormApi.setState({ labelPosition: val })
})
</script>

注意事项

  1. 所有详情项必须包含 proplabel属性
  2. 详情组件主要用于数据展示,不支持数据编辑功能
  3. 使用远程数据组件时,确保 API 返回的数据格式符合要求
  4. 字典组件需要预先在系统中配置相应的字典数据
  5. 通过 componentProps 可以传递任何组件支持的属性
  6. 详情组件中的 ifDetail用于控制字段在详情页面的显示
  7. 字典组件支持标签形式展示,typeMapcolorMap 配置样式