Appearance
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 | 加载状态 | boolean | false |
| statusInfo | 状态信息配置 | object | 见下方说明 |
| operation | 操作按钮配置函数 | function | () => [] |
statusInfo 配置
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| text | 状态文字 | string | '待查验' |
| color | 状态背景色 | string | '#5C2FD2' |
| icon | 状态图标URL | string | '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 | 是否禁用 | boolean | false |
| loading | 加载状态 | boolean | false |
| 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: () => {},
},
]
}注意事项
- 数据绑定: 使用
v-model:info、v-model:config、v-model:loading进行双向绑定 - 状态管理:
statusInfo对象控制顶部状态区域的显示 - 配置驱动: 通过
config数组控制详情内容的显示和布局 - 插槽使用: 支持分组插槽、内容插槽和字段插槽,提供高度自定义能力
- 条件显示: 通过
show属性控制字段和分组的条件显示 - 图片预览: 图片类型字段自动支持 Element Plus 的图片预览功能
- 锚点导航: 右侧自动生成锚点导航,支持平滑滚动
完整示例
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>如需更详细的用法和进阶示例,请参考源码和实际业务场景。