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