Skip to content

Detail 详情展示组件

一个功能丰富的详情页面布局组件,提供状态展示、详情内容、锚点导航和操作按钮等功能,特别适合用于订单详情、用户信息详情等场景。

基本用法

代码示例

html
<template>
  <g-detail
    v-model:info="info"
    v-model:config="config"
    v-model:loading="loading"
    :status-info="statusInfo"
    :operation="operation"
  >
    <template #return_address>
      <div>
        <span class="mr-2">{{ info.return_name }}</span>
        <span>{{ info.return_mobile }}</span>
      </div>
      <div>
        <span>{{ info.return_province }}</span>
        <span>{{ info.return_city }}</span>
        <span>{{ info.return_address }}</span>
      </div>
    </template>
  </g-detail>
</template>
javascript
<script setup>
import { ref } from 'vue'

const info = ref({
  orderNo: 'ORD202401001',
  status: 1,
  return_name: '张三',
  return_mobile: '13800138000',
  return_province: '广东省',
  return_city: '深圳市',
  return_address: '南山区科技园'
})

const config = ref([
  {
    label: '基本信息',
    children: [
      { label: '订单号', prop: 'orderNo' },
      { label: '状态', prop: 'status', format: (data) => data.status === 1 ? '已完成' : '进行中' }
    ]
  },
  {
    label: '收货信息',
    children: [
      { label: '收货地址', prop: 'return_address', slot: 'return_address' }
    ]
  }
])

const statusInfo = ref({
  text: '已完成',
  color: '#5C2FD2',
  icon: 'https://webappstorage.gecahobby.com/biu-card-backstage/success-icon.webp',
  type: 'success',
  tag: '订单已完成'
})

const loading = ref(false)

const operation = () => {
  return [
    {
      label: '下载合同',
      type: 'primary',
      action: () => {
        console.log('下载合同')
      }
    }
  ]
}
</script>

属性说明

属性说明类型默认值
info详情数据对象object{}
config详情配置数组array[]
loading加载状态booleanfalse
statusInfo状态信息配置object见下方说明
operation操作按钮配置函数function() => []

statusInfo 配置

属性说明类型默认值
text状态文字string'待查验'
color状态背景色string'#5C2FD2'
icon状态图标URLstring'https://webappstorage.gecahobby.com/biu-card-backstage/time-icon.webp'
type标签类型string'primary'
tag标签文字string'包裹等待查验'

配置说明(config)

分组配置

属性说明类型默认值
label分组标题string-
labelSlot标题插槽名string-
slot内容插槽名string-
children子字段配置数组array[]
show显示条件状态码数组array-

字段配置(children)

属性说明类型默认值
label字段标签string-
prop数据属性名string-
type显示类型'normal'/'single'/'image''normal'
format格式化函数function-
slot自定义插槽名string-
show显示条件状态码数组array-

字段类型说明

  • normal: 普通字段,3列网格布局
  • single: 单行字段,占满整行
  • image: 图片字段,支持预览和轮播

操作按钮配置(operation)

操作函数返回按钮配置数组,每个按钮支持以下配置:

属性说明类型默认值
label按钮文字string-
type按钮类型string'primary'
disabled是否禁用booleanfalse
loading加载状态booleanfalse
class自定义类名string-
icon图标组件component-
action点击事件处理函数function-
show显示条件函数function() => true

插槽

插槽名说明作用域参数
[labelSlot]分组标题自定义插槽-
[slot]分组内容自定义插槽-
[fieldSlot]字段内容自定义插槽{ info }

高级用法

条件显示字段

javascript
const config = ref([
  {
    label: '基本信息',
    show: [1, 2, 3], // 只在状态为1、2、3时显示
    children: [
      {
        label: '订单号',
        prop: 'orderNo',
        show: [1, 2], // 只在状态为1、2时显示
      },
    ],
  },
])

自定义格式化

javascript
const config = ref([
  {
    label: '订单信息',
    children: [
      {
        label: '创建时间',
        prop: 'createTime',
        format: (data) => {
          return new Date(data.createTime).toLocaleString()
        },
      },
      {
        label: '订单状态',
        prop: 'status',
        format: (data) => {
          const statusMap = {
            1: '待支付',
            2: '已支付',
            3: '已完成',
          }
          return statusMap[data.status] || '未知'
        },
      },
    ],
  },
])

图片字段配置

javascript
const config = ref([
  {
    label: '商品图片',
    children: [
      {
        label: '商品图片',
        prop: 'images',
        type: 'image', // 图片类型,支持预览
      },
    ],
  },
])

动态操作按钮

javascript
const operation = () => {
  return [
    {
      label: '下载合同',
      type: 'primary',
      show: (data) => data.status === 2, // 只在状态为2时显示
      action: (data) => {
        downloadContract(data.id)
      },
    },
    {
      label: '取消订单',
      type: 'danger',
      show: (data) => data.status === 1, // 只在状态为1时显示
      action: (data) => {
        cancelOrder(data.id)
      },
    },
  ]
}

使用插槽自定义内容

html
<template>
  <g-detail
    v-model:info="info"
    v-model:config="config"
    v-model:loading="loading"
    :status-info="statusInfo"
  >
    <!-- 自定义标题插槽 -->
    <template #title>
      <div class="flex items-center">
        <span>自定义标题</span>
        <el-tag type="warning">特殊标记</el-tag>
      </div>
    </template>

    <!-- 自定义内容插槽 -->
    <template #custom_content>
      <div class="p-4 bg-gray-50 rounded">
        <h3>自定义内容区域</h3>
        <p>这里可以放置任何自定义内容</p>
      </div>
    </template>

    <!-- 自定义字段插槽 -->
    <template #order_status="{ info }">
      <el-tag :type="info.status === 1 ? 'success' : 'warning'">
        {{ info.status === 1 ? '已完成' : '进行中' }}
      </el-tag>
    </template>
  </g-detail>
</template>
javascript
const config = ref([
  {
    label: '订单信息',
    labelSlot: 'title', // 使用标题插槽
    children: [
      {
        label: '订单状态',
        prop: 'status',
        slot: 'order_status', // 使用字段插槽
      },
    ],
  },
  {
    label: '自定义内容',
    slot: 'custom_content', // 使用内容插槽
  },
])

样式定制

组件使用 Tailwind CSS 构建,支持通过以下方式定制样式:

自定义状态区域样式

html
<template>
  <g-detail
    v-model:info="info"
    v-model:config="config"
    :status-info="{
      ...statusInfo,
      color: '#FF6B6B' // 自定义状态背景色
    }"
  />
</template>

自定义操作按钮样式

javascript
const operation = () => {
  return [
    {
      label: '自定义按钮',
      type: 'primary',
      class: 'custom-button-class', // 自定义类名
      action: () => {},
    },
  ]
}

注意事项

  1. 数据绑定: 使用 v-model:infov-model:configv-model:loading 进行双向绑定
  2. 状态管理: statusInfo 对象控制顶部状态区域的显示
  3. 配置驱动: 通过 config 数组控制详情内容的显示和布局
  4. 插槽使用: 支持分组插槽、内容插槽和字段插槽,提供高度自定义能力
  5. 条件显示: 通过 show 属性控制字段和分组的条件显示
  6. 图片预览: 图片类型字段自动支持 Element Plus 的图片预览功能
  7. 锚点导航: 右侧自动生成锚点导航,支持平滑滚动

完整示例

html
<template>
  <div class="h-full">
    <g-detail
      v-model:info="orderInfo"
      v-model:config="detailConfig"
      v-model:loading="loading"
      :status-info="statusInfo"
      :operation="getOperations"
    >
      <!-- 自定义收货地址显示 -->
      <template #return_address>
        <div class="space-y-1">
          <div class="flex items-center">
            <span class="font-medium">{{ orderInfo.return_name }}</span>
            <span class="ml-2 text-gray-500">{{ orderInfo.return_mobile }}</span>
          </div>
          <div class="text-sm text-gray-600">
            {{ orderInfo.return_province }} {{ orderInfo.return_city }} {{ orderInfo.return_address
            }}
          </div>
        </div>
      </template>

      <!-- 自定义物流信息 -->
      <template #logistics_info>
        <div class="p-4 bg-blue-50 rounded-lg">
          <h4 class="font-medium mb-2">物流跟踪</h4>
          <div class="space-y-2">
            <div class="flex justify-between">
              <span>快递公司:</span>
              <span>{{ orderInfo.shipped_company }}</span>
            </div>
            <div class="flex justify-between">
              <span>快递单号:</span>
              <span>{{ orderInfo.shipped_no }}</span>
            </div>
          </div>
        </div>
      </template>
    </g-detail>
  </div>
</template>
javascript
<script setup>
import { ref, computed, onMounted } from 'vue'

const loading = ref(false)
const orderInfo = ref({})

const statusInfo = computed(() => {
  const statusMap = {
    1: { text: '待支付', color: '#F59E0B', type: 'warning' },
    2: { text: '已支付', color: '#10B981', type: 'success' },
    3: { text: '已完成', color: '#5C2FD2', type: 'primary' }
  }

  const status = statusMap[orderInfo.value.status] || statusMap[1]

  return {
    ...status,
    icon: 'https://webappstorage.gecahobby.com/biu-card-backstage/time-icon.webp',
    tag: '订单状态'
  }
})

const detailConfig = ref([
  {
    label: '基本信息',
    children: [
      { label: '订单号', prop: 'orderNo' },
      { label: '创建时间', prop: 'createTime', format: (data) => new Date(data.createTime).toLocaleString() },
      { label: '订单状态', prop: 'status', format: (data) => statusInfo.value.text }
    ]
  },
  {
    label: '收货信息',
    children: [
      { label: '收货地址', prop: 'return_address', slot: 'return_address' }
    ]
  },
  {
    label: '物流信息',
    children: [
      { label: '物流详情', prop: 'logistics_info', slot: 'logistics_info' }
    ],
    show: [2, 3] // 只在已支付和已完成状态显示
  }
])

const getOperations = () => {
  return [
    {
      label: '下载合同',
      type: 'primary',
      show: (data) => data.status === 2,
      action: (data) => {
        downloadContract(data.id)
      }
    },
    {
      label: '联系客服',
      type: 'default',
      show: () => true,
      action: () => {
        contactCustomerService()
      }
    }
  ]
}

const downloadContract = (orderId) => {
  console.log('下载合同:', orderId)
}

const contactCustomerService = () => {
  console.log('联系客服')
}

onMounted(() => {
  // 模拟加载数据
  loading.value = true
  setTimeout(() => {
    orderInfo.value = {
      orderNo: 'ORD202401001',
      status: 2,
      createTime: '2024-01-15 10:30:00',
      return_name: '张三',
      return_mobile: '13800138000',
      return_province: '广东省',
      return_city: '深圳市',
      return_address: '南山区科技园',
      shipped_company: '顺丰快递',
      shipped_no: 'SF1234567890'
    }
    loading.value = false
  }, 1000)
})
</script>

如需更详细的用法和进阶示例,请参考源码和实际业务场景。