Files
ShaFaFanXin/前端/pages/cases/detail.uvue
2026-01-27 18:06:04 +08:00

439 lines
8.4 KiB
Plaintext

<template>
<view class="page">
<scroll-view class="page-scroll" scroll-y>
<!-- 图片画廊 -->
<view class="gallery-section">
<swiper
class="gallery-swiper"
circular
indicator-dots
indicator-color="rgba(255,255,255,0.5)"
indicator-active-color="#ffffff"
>
<swiper-item v-for="(item, index) in caseDetail.afterImages" :key="index">
<image
class="gallery-image"
:src="item"
mode="aspectFill"
@click="previewImages(index)"
></image>
</swiper-item>
</swiper>
<view class="gallery-tag">
<text class="gallery-tag-text">{{ caseDetail.categoryName }}</text>
</view>
</view>
<!-- 基本信息 -->
<view class="info-section">
<text class="case-title">{{ caseDetail.title }}</text>
<view class="case-meta">
<text class="case-price">{{ caseDetail.price }}</text>
<view class="case-stats">
<text class="stat-text">👁 {{ caseDetail.views }}</text>
<text class="stat-text">❤ {{ caseDetail.likes }}</text>
</view>
</view>
</view>
<!-- 翻新前后对比 -->
<view class="compare-section">
<before-after
:beforeImage="caseDetail.beforeImages[0] || ''"
:afterImage="caseDetail.afterImages[0] || ''"
:showTitle="true"
></before-after>
</view>
<!-- 详细信息 -->
<view class="detail-section">
<view class="detail-header">
<text class="detail-title">翻新详情</text>
</view>
<view class="detail-list">
<view class="detail-item">
<text class="detail-label">使用材质</text>
<text class="detail-value">{{ caseDetail.material }}</text>
</view>
<view class="detail-item">
<text class="detail-label">翻新工期</text>
<text class="detail-value">{{ caseDetail.duration }}</text>
</view>
<view class="detail-item">
<text class="detail-label">完成日期</text>
<text class="detail-value">{{ caseDetail.createTime }}</text>
</view>
</view>
<view class="detail-desc">
<text class="desc-title">案例描述</text>
<text class="desc-content">{{ caseDetail.description }}</text>
</view>
</view>
<!-- 底部间距 -->
<view class="bottom-space"></view>
</scroll-view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<view class="bar-left">
<view class="bar-btn" @click="handleFavorite">
<text class="bar-icon">{{ isFavorite ? '❤️' : '🤍' }}</text>
<text class="bar-label">收藏</text>
</view>
<view class="bar-btn" @click="handleShare">
<text class="bar-icon">📤</text>
<text class="bar-label">分享</text>
</view>
</view>
<view class="bar-right">
<view class="contact-btn" @click="handleContact">
<text class="contact-text">在线咨询</text>
</view>
<view class="booking-btn" @click="goToBooking">
<text class="booking-text">立即预约</text>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { getCaseDetail } from '@/api/index.uts'
// 案例详情类型
type CaseDetail = {
id : string
title : string
category : string
categoryName : string
beforeImages : string[]
afterImages : string[]
description : string
material : string
duration : string
price : string
views : number
likes : number
createTime : string
}
// 案例ID
const caseId = ref('')
// 案例详情
const caseDetail = ref<CaseDetail>({
id: '',
title: '',
category: '',
categoryName: '',
beforeImages: [],
afterImages: [],
description: '',
material: '',
duration: '',
price: '',
views: 0,
likes: 0,
createTime: ''
})
// 是否收藏
const isFavorite = ref(false)
// 获取案例详情
const fetchCaseDetail = async () => {
try {
const res = await getCaseDetail(caseId.value)
const data = res.data as UTSJSONObject
caseDetail.value = {
id: data['id'] as string,
title: data['title'] as string,
category: data['category'] as string,
categoryName: data['categoryName'] as string,
beforeImages: data['beforeImages'] as string[],
afterImages: data['afterImages'] as string[],
description: data['description'] as string,
material: data['material'] as string,
duration: data['duration'] as string,
price: data['price'] as string,
views: data['views'] as number,
likes: data['likes'] as number,
createTime: data['createTime'] as string
} as CaseDetail
// 更新标题
uni.setNavigationBarTitle({
title: caseDetail.value.title
})
} catch (e) {
console.error('获取案例详情失败', e)
}
}
// 预览图片
const previewImages = (index : number) => {
uni.previewImage({
current: index,
urls: caseDetail.value.afterImages
})
}
// 收藏
const handleFavorite = () => {
isFavorite.value = !isFavorite.value
uni.showToast({
title: isFavorite.value ? '已收藏' : '已取消收藏',
icon: 'none'
})
}
// 分享
const handleShare = () => {
// #ifdef MP-WEIXIN
// 微信小程序触发分享
// #endif
uni.showToast({
title: '分享功能开发中',
icon: 'none'
})
}
// 在线咨询
const handleContact = () => {
uni.makePhoneCall({
phoneNumber: '400-888-8888',
fail: () => {
uni.showToast({
title: '拨打电话失败',
icon: 'none'
})
}
})
}
// 预约
const goToBooking = () => {
uni.navigateTo({
url: '/pages/booking/index'
})
}
onLoad((options : OnLoadOptions) => {
caseId.value = options['id'] ?? ''
if (caseId.value != '') {
fetchCaseDetail()
}
})
</script>
<style lang="scss">
.page {
flex: 1;
background-color: #f5f5f5;
}
.page-scroll {
flex: 1;
}
/* 图片画廊 */
.gallery-section {
position: relative;
}
.gallery-swiper {
height: 500rpx;
}
.gallery-image {
width: 100%;
height: 100%;
}
.gallery-tag {
position: absolute;
top: 24rpx;
left: 24rpx;
background-color: rgba(212, 165, 116, 0.9);
padding: 8rpx 20rpx;
border-radius: 8rpx;
}
.gallery-tag-text {
font-size: 24rpx;
color: #ffffff;
}
/* 基本信息 */
.info-section {
background-color: #ffffff;
padding: 32rpx;
margin-bottom: 24rpx;
}
.case-title {
font-size: 36rpx;
font-weight: 600;
color: #333333;
margin-bottom: 24rpx;
}
.case-meta {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.case-price {
font-size: 40rpx;
font-weight: 600;
color: #D4A574;
}
.case-stats {
flex-direction: row;
}
.stat-text {
font-size: 26rpx;
color: #909399;
margin-left: 24rpx;
}
/* 对比区域 */
.compare-section {
padding: 0 24rpx;
}
/* 详细信息 */
.detail-section {
background-color: #ffffff;
margin: 24rpx;
border-radius: 16rpx;
padding: 32rpx;
}
.detail-header {
margin-bottom: 24rpx;
}
.detail-title {
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
.detail-list {
margin-bottom: 32rpx;
}
.detail-item {
flex-direction: row;
justify-content: space-between;
padding: 16rpx 0;
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #EBEEF5;
}
.detail-label {
font-size: 28rpx;
color: #909399;
}
.detail-value {
font-size: 28rpx;
color: #333333;
}
.detail-desc {
padding-top: 16rpx;
}
.desc-title {
font-size: 28rpx;
font-weight: 600;
color: #333333;
margin-bottom: 16rpx;
}
.desc-content {
font-size: 28rpx;
color: #606266;
line-height: 48rpx;
}
/* 底部间距 */
.bottom-space {
height: 160rpx;
}
/* 底部操作栏 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
flex-direction: row;
align-items: center;
justify-content: space-between;
background-color: #ffffff;
padding: 16rpx 24rpx;
padding-bottom: 32rpx;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.bar-left {
flex-direction: row;
}
.bar-btn {
align-items: center;
padding: 0 24rpx;
}
.bar-icon {
font-size: 40rpx;
}
.bar-label {
font-size: 22rpx;
color: #606266;
margin-top: 4rpx;
}
.bar-right {
flex-direction: row;
flex: 1;
justify-content: flex-end;
}
.contact-btn {
background-color: #f5f5f5;
padding: 20rpx 40rpx;
border-radius: 999rpx;
margin-right: 16rpx;
}
.contact-text {
font-size: 28rpx;
color: #606266;
}
.booking-btn {
background-color: #D4A574;
padding: 20rpx 48rpx;
border-radius: 999rpx;
}
.booking-text {
font-size: 28rpx;
font-weight: 600;
color: #ffffff;
}
</style>