Files
xdd-uniapp-new/pkg_product/views/groupBuyDetails.vue
T
2025-10-19 23:15:06 +08:00

418 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="group-detail">
<scroll-view scroll-y class="page-scroll">
<!-- 顶部大图/轮播 -->
<swiper class="hero-swiper" indicator-dots autoplay interval="3000">
<swiper-item v-for="(img, idx) in detail.carouselImages" :key="idx">
<image :src="img" class="hero-img" mode="aspectFill" />
</swiper-item>
</swiper>
<!-- 价格与标题 -->
<view class="price-title">
<view class="price v12-primary-text">
<text class="v12-font-34">¥</text>
<text class="v12-font-bold v12-font-40">{{ detail.price }}</text>
</view>
<view class="title v12-font-bold v12-font-36 more-t">{{ detail.name }}</view>
</view>
<!-- 礼物 -->
<view class="v12-px-3">
<view
@click="toGift"
class=" v12-white-text v12-px-2 v12-py-1 v12-mt-2 v12-radius-20 v12-font-bold v12-justify-between v12-align-center gift-wrap"
:style="giftBg ? 'background: url(' + giftBg + ') no-repeat center/cover' : ''"
:class="giftBg ? '' : 'v12-primary'"
>
<!-- <text v-if="storeInfo.discount > 0" class="v12-font-28 v12-yellow-text ll-text">平台限时补贴{{ storeInfo.discount }}</text> -->
<view class="v12-font-28 v12-align-center" style="height: 74rpx; opacity: 0;">
<image class="gift-img" :src="webUrl + '/orderIcon/gift.png'" mode="widthFix" ></image>
支持礼包赠送
</view>
<view @click="toGift" class="v12-white v12-dark-text v12-radius-20 v12-font-28 gift-btn" v-if="!giftBg">
送给朋友
</view>
</view>
</view>
<!-- 档期 -->
<view class="v12-mt-3 v12-px-3">
<view class="section v12-radius-60 v12-white">
<view class="intro-text">
{{ detail.intro }}
</view>
<view class="intro-text v12-mt-2">* 下单后与商家确认入住时间</view>
<view class="v12-justify-between v12-align-center v12-mt-2">
<view class="v12-primary v12-white-text v12-font-30 date-item v12-px-1" style="height: 160rpx;">
<view></view>
<view></view>
</view>
<view v-for="(d) in currentWeek" :key="d.date" class="date-item">
<view>{{ d.week }}</view>
<view class="v12-my-1 v12-primary-text">{{ d.monthDay }}</view>
<view>不可预约</view>
</view>
<view class="v12-primary-text v12-font-24 date-item v12-white v12-px-1">
<view></view>
<view></view>
<view></view>
<view></view>
</view>
</view>
</view>
</view>
<!-- 套餐详情模拟 -->
<view class="v12-px-3 v12-mt-3">
<view class="section v12-radius-60 v12-white v12-px-3 v12-pt-3">
<view class="v12-font-bold v12-font-36">套餐详情</view>
<view class="v12-mt-3">
<view v-for="(c, i) in detail.packageDetails" :key="i" class="package-item v12-mb-2">
<view class="grid-txt v12-justify-between v12-align-center">
<view class="v12-px-2 v12-py-1"><u-icon name="home"></u-icon></view>
<view class="v12-px-2 v12-py-1 v12-white v12-radius-100">{{ c.title }}</view>
</view>
<view v-for="(img, idx) in c.images" :key="idx" class="v12-justify-start v12-align-center">
<image :src="img" class="grid-img" mode="aspectFill" />
</view>
<view v-if="c.description" class="v12-font-26 v12-mt-2">{{ c.description }}</view>
</view>
</view>
</view>
</view>
<view class="v12-px-3 v12-mt-3">
<view class="section v12-radius-60 v12-white v12-px-3 v12-pt-3">
<view class="v12-font-bold v12-font-36">套餐亮点</view>
<view class="v12-mt-3 v12-font-26">
<rich-text :nodes="rules"></rich-text>
</view>
<!-- 表格 -->
<view class="simple-table">
<view class="table-row">
<view class="table-cell">申请退款时间</view>
<view class="table-cell">费用</view>
</view>
<view class="table-row">
<view class="table-cell">下单未预约</view>
<view class="table-cell">免费</view>
</view>
<view class="table-row">
<view class="table-cell">入住前x天</view>
<view class="table-cell"></view>
</view>
<view class="table-row">
<view class="table-cell">入住前x天</view>
<view class="table-cell"></view>
</view>
</view>
</view>
</view>
<view class="v12-px-3 v12-mt-3">
<u-divider text="图片详情"></u-divider>
</view>
<!-- 图片 -->
<view class="v12-mt-3 v12-px-3">
<view v-for="(img, idx) in detail.detailImages" :key="idx" >
<image :src="img" class="v12-radius-40" style="width: 100%;" mode="aspectFill" />
</view>
</view>
<view class="bottom-space"></view>
</scroll-view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<view class="total " >
<text>合计</text>
<text class="v12-primary-text">
<text class="v12-font-20">¥ </text>
{{ detail.price }}</text>
</view>
<view class="bar-actions">
<view class="mini-btn" @click="contactService">联系商家</view>
<view class="buy-btn" @click="bookNow">立即购买</view>
</view>
</view>
</view>
</template>
<script>
import { getJiaLouProductDetail, getJiaLouCalendar,getJiaLouBookingRules } from '@/api/qianxian'
import {getGiftCardSendBackground} from "@/api/gift"
export default {
name: 'GroupBuyDetails',
data() {
return {
webUrl: this.$VUE_APP_RESOURCES_URL,
giftBg: '',
id: '',
activePeriod: 0,
detail: {
title: '【正牌爆售】30天29晚臻享特色小院/庵食套餐',
price: 3888,
images: [
'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/hotel-1.jpg',
'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/hotel-2.jpg',
'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/hotel-3.jpg'
],
periods: [
{ batch: 1, range: '6/13-6/15' },
{ batch: 2, range: '6/16-6/18' },
{ batch: 3, range: '6/19-6/21' },
{ batch: 4, range: '6/22-6/24' }
],
combos: [
{ img: 'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/room-1.jpg', text: '温泉泡汤·双人早餐' },
{ img: 'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/room-2.jpg', text: '茶室体验·手作禅食' },
{ img: 'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/room-3.jpg', text: '山景露台·下午茶' },
{ img: 'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/room-4.jpg', text: '夜间电影·星空灯' },
{ img: 'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/room-5.jpg', text: '精品床品·加湿香氛' },
{ img: 'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/room-6.jpg', text: '小院烧烤·庭院篝火' }
],
highlights: [
'小院临海风光,步行可达观景台',
'馆内私厨,提供本地特色庵食',
'房间带露台,景观视野绝佳',
'每期限定名额,错峰享受更安静'
],
rules: [
'需至少提前3日预订,节假日价格略有浮动',
'不可与其他优惠同享;支持改期一次',
'如遇不可抗因素,支持无损退款',
'入住需持有效身份证件,遵守园区规定'
],
fees: [
{ name: '下单即赠惊喜', value: '免费' },
{ name: '入住加床', value: 'x' },
{ name: '儿童入园', value: 'x' }
],
gallery: [
'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/courtyard-1.jpg',
'https://cdn.jsdelivr.net/gh/trae-ai/assets-placeholder/courtyard-2.jpg'
]
},
calendar: [],
currentWeek: [],
rules: ""
}
},
onShow() {
getGiftCardSendBackground().then(res => {
if (res.status === 200) {
this.giftBg = res.data || ''
}
})
},
onLoad(query) {
this.id = (query && query.id) || ''
this.getDetail()
this.getCalendar()
getJiaLouBookingRules(this.id).then(res => {
if (res.status === 200) {
this.rules = res.data || ''
}
})
},
methods: {
/**
* 获取产品可预约日期
*/
getCalendar() {
const currentMonth = new Date().toISOString().slice(0, 7)
getJiaLouCalendar({
travelGroupProductId: this.id,
month: currentMonth
}).then(res => {
if (res.status === 200) {
this.calendar = res.data || []
// 计算当前日及后面4天
this.currentWeek = this.computeCurrentWeekFromCalendar()
}
})
},
/**
* 根据 calendar 数据计算:今天 + 接下来4天(共5天)
* 返回 YYYY-MM-DD 字符串数组
*/
computeCurrentWeekFromCalendar() {
const result = []
const base = new Date()
for (let i = 0; i < 5; i++) {
const d = new Date(base)
d.setDate(base.getDate() + i)
const dateStr = this.formatYMD(d)
result.push({
date: dateStr,
week: this.getWeekLabel(dateStr),
monthDay: i === 0 ? '今日' : this.getMonthDay(dateStr)
})
}
return result
},
formatYMD(d) {
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
},
getWeekLabel(dateStr) {
const [y, m, d] = dateStr.split('-').map(Number)
const date = new Date(y, m - 1, d)
const map = ['周日','周一','周二','周三','周四','周五','周六']
return map[date.getDay()]
},
getMonthDay(dateStr) {
const [y, m, d] = dateStr.split('-').map(Number)
return `${m}/${d}`
},
/**
* 获取产品详情
*/
async getDetail() {
if (!this.id) {
uni.showToast({ title: '参数错误', icon: 'none' })
return
}
const res = await getJiaLouProductDetail(this.id)
if (res.status === 200) {
this.detail = res.data
}
},
contactService() {
uni.showToast({ title: '已为您接入管家', icon: 'none' })
},
bookNow() {
uni.navigateTo({ url: '/pkg_product/views/submitOrder?id=' + this.id + '&orderStartDate=' + this.currentWeek[0].date + '&orderEndDate=' + this.currentWeek[4].date })
}
}
}
</script>
<style lang="less" scoped>
.group-detail {
min-height: 100vh;
}
.gift-img{
width: 34rpx;
height: 34rpx;
margin-right: 10rpx;
}
.page-scroll { height: calc(100vh - 120rpx); }
.hero-swiper {
width: 100%;
height: 700rpx;
}
.hero-img { width: 100%; height: 100%; }
.price-title {
padding: 24rpx 24rpx;
background: #fff;
}
.price { color: #E53935; font-size: 40rpx; font-weight: 700; }
.title { margin-top: 8rpx; color: #333; font-size: 28rpx; line-height: 40rpx; }
.action-row { margin-top: 16rpx; display: flex; gap: 16rpx; }
.btn { padding: 14rpx 24rpx; border-radius: 30rpx; font-size: 26rpx; }
.btn.ghost { border: 1rpx solid #ccc; color: #333; }
.btn.primary { background: #E53935; color: #fff; }
.section { padding: 20rpx 24rpx; }
.section-hd { display: flex; align-items: center; font-size: 28rpx; color: #111; font-weight: 600; margin-bottom: 12rpx; }
.dot { width: 14rpx; height: 14rpx; border-radius: 50%; background: #E53935; margin-right: 12rpx; }
.schedule { white-space: nowrap; }
.schedule-inner { display: flex; }
.period { padding: 14rpx 20rpx; border: 1rpx solid #eee; border-radius: 12rpx; margin-right: 12rpx; }
.period.active { border-color: #E53935; color: #E53935; }
.p1 { font-size: 26rpx; font-weight: 600; }
.p2 { font-size: 22rpx; color: #666; }
.grid { display: flex; flex-wrap: wrap; gap: 16rpx; }
.grid-img {
width: 204rpx;
height: 204rpx;
border-radius: 16rpx;
}
.grid-txt {
width: fit-content;
font-size: 24rpx;
color: #333;
border: 1px solid #F9E49D;
background: #F9E49D;
border-radius: 100rpx;
margin-bottom: 12rpx;
}
.bullets { }
.bullet { display: flex; align-items: flex-start; margin-bottom: 12rpx; }
.bullet-icon { width: 28rpx; text-align: center; color: #E53935; font-size: 28rpx; line-height: 32rpx; }
.bullet-txt { flex: 1; font-size: 26rpx; color: #333; }
.fee-table { margin-top: 12rpx; border: 1rpx solid #eee; border-radius: 12rpx; overflow: hidden; }
.fee-row { display: flex; }
.fee-row + .fee-row { border-top: 1rpx solid #f2f2f2; }
.fee-col { flex: 1; padding: 16rpx; font-size: 26rpx; }
.fee-head { background: #f8f8f8; font-weight: 600; }
.name { color: #333; }
.val { color: #666; text-align: right; }
.gallery-img { width: 100%; margin-bottom: 16rpx; border-radius: 12rpx; overflow: hidden; }
.bottom-space { height: 140rpx; }
.bottom-bar { position: fixed; left: 0; right: 0; bottom: 0; background: #fff; border-top: 1rpx solid #eee; display: flex; align-items: center; justify-content: space-between; padding: 16rpx 24rpx; }
.total { font-size: 28rpx; color: #111; font-weight: 700; }
.bar-actions { display: flex; gap: 16rpx; }
.mini-btn { padding: 16rpx 22rpx; border: 1rpx solid #ccc; border-radius: 32rpx; font-size: 26rpx; color: #333; }
.buy-btn { padding: 16rpx 28rpx; border-radius: 32rpx; background: #C52733; color: #fff; font-size: 26rpx; }
.gift-wrap{
position: relative;
}
.intro-text{
font-weight: 400;
font-size: 26rpx;
color: #666666;
line-height: 44rpx;
letter-spacing: 4rpx;
}
.package-item{
margin-bottom: 24rpx;
}
.date-item{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(240,240,240,0.69);
border-radius: 40rpx;
font-size: 24rpx;
color: #333;
height: 160rpx;
padding: 0 4rpx;
}
.simple-table {
margin-top: 12rpx;
border: 1rpx solid #FADE9F;
border-radius: 12rpx;
overflow: hidden;
border-radius: 60rpx 60rpx 0 0;
}
.table-row {
display: flex;
background: #fff;
&:first-child {
background: #FADE9F;
color: #333;
}
}
.table-row + .table-row {
border-top: 1rpx solid #FADE9F;
}
.table-cell {
flex: 1;
padding: 16rpx;
font-size: 26rpx;
color: #333;
border-right: 1rpx solid #FADE9F;
text-align: center;
font-weight: 500;
}
.table-cell:last-child {
border-right: 0;
}
</style>