小说小程序前端代码仓库(小程序)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

408 lines
8.1 KiB

<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>