@ -0,0 +1,207 @@ | |||||
<template> | |||||
<view class="page"> | |||||
<!-- 导航栏 --> | |||||
<navbar title="礼包列表" leftClick @leftClick="$utils.navigateBack" bgColor="#E3441A" color="#fff" /> | |||||
<!-- 订单筛选 --> | |||||
<view class="tabs"> | |||||
<uv-tabs :list="tabs" | |||||
:activeStyle="{color : '#fff', fontWeight : 600}" | |||||
lineColor="#fff" | |||||
:inactiveStyle="{color: 'rgba(255,255,255,.8)'}" | |||||
lineHeight="8rpx" | |||||
lineWidth="50rpx" | |||||
:current="current" | |||||
@click="clickTabs"></uv-tabs> | |||||
</view> | |||||
<view class="list"> | |||||
<view class="item" v-for="(item, index) in list" @click="toGiftDetail(item.id)" :key="index"> | |||||
<view class="content"> | |||||
<view class="top"> | |||||
<view class="service"> | |||||
{{ item.title }} | |||||
</view> | |||||
<view class="status"> | |||||
<text>{{ item.state === 0 ? '待领取' : '已领取' }}</text> | |||||
</view> | |||||
</view> | |||||
<view class="main"> | |||||
<view class="left"> | |||||
<image mode="aspectFill" :src="item.image && item.image.split(',')[0]"></image> | |||||
</view> | |||||
<view class="right"> | |||||
<view class="text-hidden-1"> | |||||
赠送人:{{item.senderName}} | |||||
</view> | |||||
<view class="text-hidden-1"> | |||||
赠送时间:{{item.createTime}} | |||||
</view> | |||||
<view class="text-hidden-2"> | |||||
祝福语:{{item.message}} | |||||
</view> | |||||
</view> | |||||
</view> | |||||
</view> | |||||
<view class="bottom"> | |||||
<view class="price"> | |||||
<text class="total-title">礼包价值:</text> | |||||
<text class="unit">¥</text> | |||||
<text class="num">{{item.price}}</text> | |||||
<text class="c-unit">元</text> | |||||
</view> | |||||
<view @click.stop="receiveGift(item)" class="btn" v-if="item.state === 0"> | |||||
立即领取 | |||||
</view> | |||||
</view> | |||||
</view> | |||||
<view style="margin-top: 20rpx; min-width: 700rpx;"> | |||||
<uv-empty mode="list" v-if="list.length === 0"></uv-empty> | |||||
</view> | |||||
</view> | |||||
</view> | |||||
</template> | |||||
<script> | |||||
import mixinsList from '@/mixins/list.js' | |||||
export default { | |||||
mixins: [mixinsList], | |||||
data() { | |||||
return { | |||||
mixinsListApi: 'getGiftList', | |||||
tabs: [ | |||||
{ | |||||
name: '我赠送的' | |||||
}, | |||||
{ | |||||
name: '我收到的' | |||||
} | |||||
], | |||||
current : 0, | |||||
} | |||||
}, | |||||
methods: { | |||||
clickTabs({index}){ | |||||
}, | |||||
// 跳转礼包详情 | |||||
toGiftDetail(id) { | |||||
uni.navigateTo({ | |||||
url: '/pages_order/order/giftDetail?id=' + id | |||||
}) | |||||
}, | |||||
// 领取礼包 | |||||
receiveGift(item) { | |||||
uni.showModal({ | |||||
title: '提示', | |||||
content: '确认领取该礼包吗?', | |||||
success: async (res) => { | |||||
if (res.confirm) { | |||||
await this.$http.post('/gift/receive', { | |||||
id: item.id | |||||
}) | |||||
uni.showToast({ | |||||
title: '领取成功', | |||||
icon: 'success' | |||||
}) | |||||
this.getData() | |||||
} | |||||
} | |||||
}) | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
.list { | |||||
.item { | |||||
width: calc(100% - 40rpx); | |||||
background-color: #fff; | |||||
margin: 20rpx; | |||||
box-sizing: border-box; | |||||
border-radius: 16rpx; | |||||
padding: 30rpx; | |||||
.content { | |||||
.top { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
align-items: center; | |||||
font-size: 34rpx; | |||||
.status { | |||||
font-weight: 600; | |||||
color: #FFAC2F; | |||||
flex-shrink: 0; | |||||
margin-left: 20rpx; | |||||
} | |||||
} | |||||
.main { | |||||
display: flex; | |||||
margin: 20rpx 0rpx; | |||||
.left { | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
width: 180rpx; | |||||
height: 180rpx; | |||||
image { | |||||
width: 95%; | |||||
height: 95%; | |||||
border-radius: 10rpx; | |||||
} | |||||
} | |||||
.right { | |||||
display: flex; | |||||
flex-direction: column; | |||||
justify-content: space-between; | |||||
width: calc(100% - 200rpx); | |||||
color: #777; | |||||
font-size: 26rpx; | |||||
padding: 30rpx 20rpx; | |||||
box-sizing: border-box; | |||||
margin-left: 20rpx; | |||||
border-radius: 10rpx; | |||||
background-color: #F8F8F8; | |||||
} | |||||
} | |||||
} | |||||
.bottom { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
font-size: 25rpx; | |||||
.price { | |||||
.num { | |||||
font-size: 36rpx; | |||||
} | |||||
.num, | |||||
.unit, | |||||
.c-unit { | |||||
color: $uni-color; | |||||
} | |||||
} | |||||
.btn { | |||||
border: 1px solid #C7C7C7; | |||||
padding: 10rpx 20rpx; | |||||
border-radius: 40rpx; | |||||
color: #575757; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
</style> |
@ -0,0 +1,238 @@ | |||||
<template> | |||||
<view class="instant-gift"> | |||||
<navbar title="立即送礼" leftClick @leftClick="$utils.navigateBack" /> | |||||
<!-- 主图片展示区 --> | |||||
<view class="main-image"> | |||||
<image :src="selectedGift.image" mode="aspectFill"></image> | |||||
</view> | |||||
<!-- 礼品选择列表 --> | |||||
<scroll-view scroll-x class="gift-list"> | |||||
<view | |||||
class="gift-item" | |||||
v-for="(item, index) in giftList" | |||||
:key="index" | |||||
:class="{ active: selectedIndex === index }" | |||||
@click="selectGift(index)" | |||||
> | |||||
<image :src="item.image" mode="aspectFill"></image> | |||||
<text class="gift-name">{{item.name}}</text> | |||||
</view> | |||||
</scroll-view> | |||||
<!-- 祝福语区域 --> | |||||
<view class="blessing-area"> | |||||
<view class="blessing-title">送祝福给TA</view> | |||||
<view class="blessing-input"> | |||||
<input type="text" v-model="blessing" placeholder="蛇年到,福气绕。钱包满满当当!" /> | |||||
</view> | |||||
</view> | |||||
<!-- 底部区域 --> | |||||
<view class="bottom-area"> | |||||
<view class="countdown">距离礼包失效:{{countdownText}}</view> | |||||
<button class="send-btn" @click="sendGift">立即送礼</button> | |||||
</view> | |||||
</view> | |||||
</template> | |||||
<script> | |||||
export default { | |||||
data() { | |||||
return { | |||||
selectedIndex: 0, | |||||
blessing: '', | |||||
countdown: 24 * 60 * 60, // 倒计时秒数 | |||||
countdownTimer: null, | |||||
giftList: [ | |||||
{ | |||||
name: '蛇行大运', | |||||
image: 'https://picb3.photophoto.cn/38/090/38090873_1.jpg' | |||||
}, | |||||
{ | |||||
name: '蛇来运转', | |||||
image: 'https://picb3.photophoto.cn/38/090/38090873_1.jpg' | |||||
}, | |||||
{ | |||||
name: '2025', | |||||
image: 'https://picb3.photophoto.cn/38/090/38090873_1.jpg' | |||||
}, | |||||
{ | |||||
name: '身体健康', | |||||
image: 'https://picb3.photophoto.cn/38/090/38090873_1.jpg' | |||||
} | |||||
] | |||||
} | |||||
}, | |||||
computed: { | |||||
selectedGift() { | |||||
return this.giftList[this.selectedIndex] | |||||
}, | |||||
countdownText() { | |||||
const hours = Math.floor(this.countdown / 3600) | |||||
const minutes = Math.floor((this.countdown % 3600) / 60) | |||||
const seconds = this.countdown % 60 | |||||
return `${hours}时${minutes}分${seconds}秒` | |||||
} | |||||
}, | |||||
methods: { | |||||
navigateBack() { | |||||
uni.navigateBack() | |||||
}, | |||||
selectGift(index) { | |||||
this.selectedIndex = index | |||||
}, | |||||
sendGift() { | |||||
// 实现送礼逻辑 | |||||
uni.showToast({ | |||||
title: '送礼成功', | |||||
icon: 'success' | |||||
}) | |||||
}, | |||||
startCountdown() { | |||||
this.countdownTimer = setInterval(() => { | |||||
if (this.countdown > 0) { | |||||
this.countdown-- | |||||
} else { | |||||
clearInterval(this.countdownTimer) | |||||
} | |||||
}, 1000) | |||||
} | |||||
}, | |||||
mounted() { | |||||
this.startCountdown() | |||||
}, | |||||
beforeDestroy() { | |||||
if (this.countdownTimer) { | |||||
clearInterval(this.countdownTimer) | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
.instant-gift { | |||||
min-height: 100vh; | |||||
background: #fff; | |||||
.nav-header { | |||||
display: flex; | |||||
align-items: center; | |||||
height: 88rpx; | |||||
padding: 0 30rpx; | |||||
.back-icon, .more-icon { | |||||
width: 60rpx; | |||||
text-align: center; | |||||
} | |||||
.title { | |||||
flex: 1; | |||||
text-align: center; | |||||
font-size: 32rpx; | |||||
font-weight: 500; | |||||
} | |||||
} | |||||
.main-image { | |||||
width: 100%; | |||||
height: 400rpx; | |||||
image { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
} | |||||
.gift-list { | |||||
padding: 30rpx; | |||||
white-space: nowrap; | |||||
.gift-item { | |||||
display: inline-block; | |||||
width: 200rpx; | |||||
margin-right: 20rpx; | |||||
text-align: center; | |||||
position: relative; | |||||
z-index: 1; | |||||
border: 4rpx solid transparent; | |||||
padding: 0 10rpx 10rpx 10rpx; | |||||
&.active { | |||||
position: relative; | |||||
z-index: 2; | |||||
border: 4rpx solid $uni-color; | |||||
border-radius: 12rpx; | |||||
} | |||||
image { | |||||
width: 100%; | |||||
height: 200rpx; | |||||
border-radius: 12rpx; | |||||
} | |||||
.gift-name { | |||||
display: block; | |||||
font-size: 28rpx; | |||||
margin-top: 10rpx; | |||||
} | |||||
} | |||||
} | |||||
.blessing-area { | |||||
padding: 30rpx; | |||||
.blessing-title { | |||||
font-size: 30rpx; | |||||
color: #666; | |||||
margin-bottom: 20rpx; | |||||
} | |||||
.blessing-input { | |||||
background: #FFF5F5; | |||||
padding: 20rpx; | |||||
border-radius: 12rpx; | |||||
border: 2rpx solid #FFE0E0; | |||||
input { | |||||
width: 100%; | |||||
height: 60rpx; | |||||
color: #333; | |||||
font-size: 28rpx; | |||||
} | |||||
} | |||||
} | |||||
.bottom-area { | |||||
position: fixed; | |||||
left: 0; | |||||
bottom: 0; | |||||
width: 100%; | |||||
box-sizing: border-box; | |||||
padding: 20rpx 30rpx calc(30rpx + env(safe-area-inset-bottom)) 30rpx; | |||||
background: #fff; | |||||
box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05); | |||||
z-index: 10; | |||||
.countdown { | |||||
text-align: center; | |||||
font-size: 28rpx; | |||||
color: #666; | |||||
margin-bottom: 20rpx; | |||||
font-weight: 500; | |||||
} | |||||
.send-btn { | |||||
width: calc(100%); | |||||
height: 88rpx; | |||||
line-height: 88rpx; | |||||
background: linear-gradient(to right, #FF4B4B, $uni-color); | |||||
color: #fff; | |||||
border-radius: 44rpx; | |||||
font-size: 32rpx; | |||||
font-weight: 500; | |||||
} | |||||
} | |||||
} | |||||
</style> |
@ -0,0 +1,232 @@ | |||||
<template> | |||||
<view class="receive-gift"> | |||||
<navbar title="礼品领取" leftClick @leftClick="$utils.navigateBack" /> | |||||
<!-- 主图片展示区 --> | |||||
<view class="main-image"> | |||||
<image :src="giftInfo.image" mode="aspectFill"></image> | |||||
</view> | |||||
<!-- 礼品信息区域 --> | |||||
<view class="gift-info"> | |||||
<view class="gift-name">{{giftInfo.name}}</view> | |||||
<view class="gift-value"> | |||||
<text>礼品价值:</text> | |||||
<text class="price">¥{{giftInfo.price}}</text> | |||||
</view> | |||||
</view> | |||||
<!-- 祝福语区域 --> | |||||
<view class="blessing-area"> | |||||
<view class="sender-info"> | |||||
<text class="label">来自</text> | |||||
<text class="sender">{{giftInfo.senderName}}</text> | |||||
<text class="label">的祝福</text> | |||||
</view> | |||||
<view class="blessing-content"> | |||||
{{giftInfo.message}} | |||||
</view> | |||||
</view> | |||||
<!-- 底部区域 --> | |||||
<view class="bottom-area"> | |||||
<view class="countdown">距离礼包失效:{{countdownText}}</view> | |||||
<button class="receive-btn" @click="receiveGift" :disabled="giftInfo.state !== 0">{{giftInfo.state === 0 ? '立即领取' : '已领取'}}</button> | |||||
</view> | |||||
</view> | |||||
</template> | |||||
<script> | |||||
export default { | |||||
data() { | |||||
return { | |||||
giftId: '', | |||||
giftInfo: { | |||||
name: '', | |||||
image: '', | |||||
price: 0, | |||||
senderName: '', | |||||
message: '', | |||||
state: 0, // 0-未领取 1-已领取 | |||||
expireTime: '' | |||||
}, | |||||
countdown: 24 * 60 * 60, // 倒计时秒数 | |||||
countdownTimer: null | |||||
} | |||||
}, | |||||
computed: { | |||||
countdownText() { | |||||
const hours = Math.floor(this.countdown / 3600) | |||||
const minutes = Math.floor((this.countdown % 3600) / 60) | |||||
const seconds = this.countdown % 60 | |||||
return `${hours}时${minutes}分${seconds}秒` | |||||
} | |||||
}, | |||||
methods: { | |||||
// 获取礼品信息 | |||||
async getGiftInfo() { | |||||
try { | |||||
const res = await this.$http.get(`/gift/detail/${this.giftId}`) | |||||
this.giftInfo = res.data | |||||
// 计算倒计时 | |||||
if (this.giftInfo.expireTime) { | |||||
const expireTime = new Date(this.giftInfo.expireTime).getTime() | |||||
const now = new Date().getTime() | |||||
this.countdown = Math.max(0, Math.floor((expireTime - now) / 1000)) | |||||
this.startCountdown() | |||||
} | |||||
} catch (e) { | |||||
uni.showToast({ | |||||
title: '获取礼品信息失败', | |||||
icon: 'none' | |||||
}) | |||||
} | |||||
}, | |||||
// 领取礼品 | |||||
async receiveGift() { | |||||
try { | |||||
await this.$http.post('/gift/receive', { | |||||
id: this.giftId | |||||
}) | |||||
uni.showToast({ | |||||
title: '领取成功', | |||||
icon: 'success' | |||||
}) | |||||
this.giftInfo.state = 1 | |||||
} catch (e) { | |||||
uni.showToast({ | |||||
title: '领取失败', | |||||
icon: 'none' | |||||
}) | |||||
} | |||||
}, | |||||
// 开始倒计时 | |||||
startCountdown() { | |||||
this.countdownTimer = setInterval(() => { | |||||
if (this.countdown > 0) { | |||||
this.countdown-- | |||||
} else { | |||||
clearInterval(this.countdownTimer) | |||||
} | |||||
}, 1000) | |||||
} | |||||
}, | |||||
onLoad(options) { | |||||
if (options.id) { | |||||
this.giftId = options.id | |||||
this.getGiftInfo() | |||||
} | |||||
}, | |||||
beforeDestroy() { | |||||
if (this.countdownTimer) { | |||||
clearInterval(this.countdownTimer) | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
.receive-gift { | |||||
min-height: 100vh; | |||||
background: #fff; | |||||
.main-image { | |||||
width: 100%; | |||||
height: 400rpx; | |||||
image { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
} | |||||
.gift-info { | |||||
padding: 30rpx; | |||||
.gift-name { | |||||
font-size: 36rpx; | |||||
font-weight: 600; | |||||
color: #333; | |||||
margin-bottom: 20rpx; | |||||
} | |||||
.gift-value { | |||||
font-size: 28rpx; | |||||
color: #666; | |||||
.price { | |||||
color: #E3441A; | |||||
font-weight: 600; | |||||
margin-left: 10rpx; | |||||
} | |||||
} | |||||
} | |||||
.blessing-area { | |||||
padding: 30rpx; | |||||
background: #FFF5F5; | |||||
margin: 30rpx; | |||||
border-radius: 12rpx; | |||||
.sender-info { | |||||
text-align: center; | |||||
margin-bottom: 20rpx; | |||||
.label { | |||||
color: #666; | |||||
font-size: 28rpx; | |||||
} | |||||
.sender { | |||||
color: #333; | |||||
font-size: 32rpx; | |||||
font-weight: 600; | |||||
margin: 0 10rpx; | |||||
} | |||||
} | |||||
.blessing-content { | |||||
color: #333; | |||||
font-size: 30rpx; | |||||
line-height: 1.6; | |||||
text-align: center; | |||||
} | |||||
} | |||||
.bottom-area { | |||||
position: fixed; | |||||
left: 0; | |||||
bottom: 0; | |||||
width: 100%; | |||||
box-sizing: border-box; | |||||
padding: 20rpx 30rpx calc(30rpx + env(safe-area-inset-bottom)) 30rpx; | |||||
background: #fff; | |||||
box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05); | |||||
z-index: 10; | |||||
.countdown { | |||||
text-align: center; | |||||
font-size: 28rpx; | |||||
color: #666; | |||||
margin-bottom: 20rpx; | |||||
font-weight: 500; | |||||
} | |||||
.receive-btn { | |||||
width: 100%; | |||||
height: 88rpx; | |||||
line-height: 88rpx; | |||||
background: linear-gradient(to right, #FF4B4B, #E3441A); | |||||
color: #fff; | |||||
border-radius: 44rpx; | |||||
font-size: 32rpx; | |||||
font-weight: 500; | |||||
&[disabled] { | |||||
background: #ccc; | |||||
opacity: 0.8; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
</style> |