<template>
|
|
<uv-popup ref="popup" mode="bottom" :round="20" :safeAreaInsetBottom="true" @close="handleClose">
|
|
<view class="interactive-gift-popup">
|
|
<!-- 标题栏 -->
|
|
<view class="popup-header">
|
|
<text class="popup-title">互动打赏</text>
|
|
<uv-icon name="close" size="40rpx" color="#999" @click="close"></uv-icon>
|
|
</view>
|
|
|
|
|
|
<!-- 当前选中礼物信息 -->
|
|
<view class="selected-gift-info" v-if="selectedGift">
|
|
<view class="selected-gift-left">
|
|
<view class="selected-gift-img">
|
|
<image :src="selectedGift.image" mode="aspectFill"></image>
|
|
</view>
|
|
<view class="selected-gift-details">
|
|
<text class="selected-gift-name">{{ selectedGift.title }}</text>
|
|
<text class="selected-gift-price">{{ selectedGift.integerPrice }}豆豆</text>
|
|
</view>
|
|
</view>
|
|
<view class="selected-gift-right">
|
|
<uv-number-box
|
|
v-model="giftCount"
|
|
:min="1"
|
|
:max="99"
|
|
size="small"
|
|
bgColor="#f5f5f5"
|
|
color="#223a7a"
|
|
/>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 用户余额信息 -->
|
|
<view class="balance-info">
|
|
<view class="balance-text">
|
|
账户余额:<text class="bean-amount">{{ userInfo.integerPrice }} 豆豆</text>
|
|
</view>
|
|
<view v-if="selectedGift && totalPrice > userInfo.integerPrice" class="insufficient-tip">
|
|
余额不足,请先充值
|
|
</view>
|
|
</view>
|
|
|
|
<view class="gift-grid">
|
|
<view
|
|
v-for="(gift, idx) in giftList"
|
|
:key="gift.id"
|
|
:class="['gift-item', { selected: selectedIndex === idx }]"
|
|
@click="selectGift(idx)"
|
|
>
|
|
<view class="gift-img">
|
|
<image :src="gift.image" mode="aspectFill"></image>
|
|
</view>
|
|
<view class="gift-name">{{ gift.title }}</view>
|
|
<view class="gift-price">{{ gift.integerPrice }}豆豆</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 底部操作栏 -->
|
|
<view class="popup-bottom">
|
|
<view class="total-info">
|
|
<text class="total-text">总计:</text>
|
|
<text class="total-price">{{ totalPrice }}豆豆</text>
|
|
</view>
|
|
<button class="gift-btn" @click="sendGift" :disabled="!selectedGift || loading">
|
|
{{ loading ? '赠送中...' : '赠送' }}
|
|
</button>
|
|
</view>
|
|
</view>
|
|
</uv-popup>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'InteractiveGiftPopup',
|
|
props: {
|
|
bookId: {
|
|
type: [String, Number],
|
|
required: true
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
giftList: [],
|
|
selectedIndex: 0,
|
|
selectedGift: null,
|
|
giftCount: 1,
|
|
loading: false,
|
|
}
|
|
},
|
|
computed: {
|
|
totalPrice() {
|
|
if (!this.selectedGift) return 0;
|
|
return this.selectedGift.integerPrice * this.giftCount;
|
|
}
|
|
},
|
|
methods: {
|
|
// 打开弹窗
|
|
open() {
|
|
this.$refs.popup.open();
|
|
this.getGiftList();
|
|
this.getUserBalance();
|
|
},
|
|
|
|
// 关闭弹窗
|
|
close() {
|
|
this.$refs.popup.close();
|
|
},
|
|
|
|
// 处理关闭事件
|
|
handleClose() {
|
|
this.resetData();
|
|
},
|
|
|
|
// 重置数据
|
|
resetData() {
|
|
this.selectedIndex = 0;
|
|
this.selectedGift = null;
|
|
this.giftCount = 1;
|
|
this.loading = false;
|
|
},
|
|
|
|
// 获取礼物列表
|
|
getGiftList() {
|
|
this.$fetch('getInteractionGiftList').then(res => {
|
|
this.giftList = res.records || [];
|
|
if (this.giftList.length > 0) {
|
|
this.selectGift(0);
|
|
}
|
|
}).catch(err => {
|
|
console.error('获取礼物列表失败:', err);
|
|
uni.showToast({
|
|
title: '获取礼物列表失败',
|
|
icon: 'none'
|
|
});
|
|
});
|
|
},
|
|
|
|
// 选择礼物
|
|
selectGift(index) {
|
|
this.selectedIndex = index;
|
|
this.selectedGift = this.giftList[index];
|
|
this.giftCount = 1;
|
|
},
|
|
|
|
// 获取用户余额
|
|
getUserBalance() {
|
|
// 从store中获取用户信息
|
|
this.$store.commit('getUserInfo');
|
|
},
|
|
|
|
// 赠送礼物
|
|
sendGift() {
|
|
if (!this.selectedGift) {
|
|
uni.showToast({
|
|
title: '请选择礼物',
|
|
icon: 'none'
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 检查余额是否足够
|
|
if (this.totalPrice > this.userInfo.integerPrice) {
|
|
uni.showToast({
|
|
title: '余额不足,请先充值',
|
|
icon: 'none'
|
|
});
|
|
setTimeout(() => {
|
|
uni.navigateTo({
|
|
url: '/pages_order/mine/recharge'
|
|
})
|
|
}, 600)
|
|
return;
|
|
}
|
|
|
|
this.loading = true;
|
|
|
|
// 创建订单
|
|
this.$fetch('giveGift', {
|
|
giftId: this.selectedGift.id,
|
|
num: this.giftCount,
|
|
bookId: this.bookId,
|
|
}).then(res => {
|
|
// 支付成功
|
|
uni.showToast({
|
|
title: '赠送成功',
|
|
icon: 'success'
|
|
});
|
|
|
|
// 通知父组件更新数据
|
|
this.$emit('giftSent', {
|
|
gift: this.selectedGift,
|
|
count: this.giftCount,
|
|
totalPrice: this.totalPrice
|
|
});
|
|
|
|
this.getUserBalance()
|
|
|
|
this.close();
|
|
}).catch(err => {
|
|
console.error('赠送失败:', err);
|
|
uni.showToast({
|
|
title: err.message || '赠送失败',
|
|
icon: 'none'
|
|
});
|
|
}).finally(() => {
|
|
this.loading = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.interactive-gift-popup {
|
|
background: #fff;
|
|
border-radius: 20rpx 20rpx 0 0;
|
|
max-height: 80vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.popup-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 32rpx 32rpx 24rpx 32rpx;
|
|
border-bottom: 1rpx solid #f5f5f5;
|
|
|
|
.popup-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
}
|
|
|
|
.selected-gift-info {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 24rpx 32rpx;
|
|
background: #f8f9ff;
|
|
margin: 0 32rpx 24rpx 32rpx;
|
|
border-radius: 16rpx;
|
|
|
|
.selected-gift-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16rpx;
|
|
|
|
.selected-gift-img {
|
|
width: 60rpx;
|
|
height: 60rpx;
|
|
border-radius: 8rpx;
|
|
overflow: hidden;
|
|
|
|
image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
.selected-gift-details {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4rpx;
|
|
|
|
.selected-gift-name {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.selected-gift-price {
|
|
font-size: 24rpx;
|
|
color: #223a7a;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.balance-info {
|
|
padding: 0 32rpx 24rpx 32rpx;
|
|
|
|
.balance-text {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
margin-bottom: 8rpx;
|
|
|
|
.bean-amount {
|
|
color: #223a7a;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
.insufficient-tip {
|
|
font-size: 24rpx;
|
|
color: #e94f7a;
|
|
background: rgba(233, 79, 122, 0.1);
|
|
padding: 8rpx 16rpx;
|
|
border-radius: 8rpx;
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
.gift-grid {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 20rpx;
|
|
padding: 0 32rpx;
|
|
max-height: 400rpx;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.gift-item {
|
|
width: calc(25% - 18rpx);
|
|
background: #fff;
|
|
border-radius: 12rpx;
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding: 20rpx 4rpx;
|
|
border: 2rpx solid transparent;
|
|
transition: all 0.2s;
|
|
box-sizing: border-box;
|
|
|
|
&.selected {
|
|
border-color: #223a7a;
|
|
background: #f8f9ff;
|
|
}
|
|
|
|
.gift-img {
|
|
width: 70rpx;
|
|
height: 70rpx;
|
|
border-radius: 8rpx;
|
|
overflow: hidden;
|
|
margin-bottom: 8rpx;
|
|
|
|
image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
.gift-name {
|
|
font-size: 22rpx;
|
|
color: #333;
|
|
text-align: center;
|
|
margin-bottom: 4rpx;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.gift-price {
|
|
font-size: 20rpx;
|
|
color: #223a7a;
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
.popup-bottom {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 24rpx 32rpx;
|
|
border-top: 1rpx solid #f5f5f5;
|
|
background: #fff;
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
|
|
.total-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8rpx;
|
|
|
|
.total-text {
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.total-price {
|
|
font-size: 32rpx;
|
|
color: #223a7a;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
|
|
.gift-btn {
|
|
background: #223a7a;
|
|
color: #fff;
|
|
font-size: 28rpx;
|
|
border-radius: 32rpx;
|
|
padding: 0 48rpx;
|
|
height: 68rpx;
|
|
line-height: 68rpx;
|
|
border: none;
|
|
min-width: 140rpx;
|
|
margin-left: auto;
|
|
margin-right: 20rpx;
|
|
|
|
&[disabled] {
|
|
background: #ccc;
|
|
color: #999;
|
|
}
|
|
}
|
|
}
|
|
</style>
|