- 新增钱包流水功能,包括充值记录和支付记录展示 - 新增签到记录弹窗组件 - 优化小说详情页的订阅和阅读体验 - 修复修改个人信息页面签名字段不显示的问题 - 调整章节编辑页面的付费开关样式和大小 - 优化书架页面跳转逻辑,支持直接跳转到阅读记录章节 - 修复任务中心签到状态判断逻辑 - 新增书籍状态组件,统一展示连载/完结状态 - 优化评论列表和我的评论页面显示逻辑 - 调整个人中心页面布局和样式 - 新增充值功能入口页面 - 优化章节列表和章节内容的付费标识显示 - 修复成就等级设置页面数据加载问题 - 优化打赏排行榜数据显示和交互 - 调整环境配置为开发环境master
| @ -0,0 +1,17 @@ | |||||
| const api = { | |||||
| // 获取我的可用积分数 | |||||
| getMyMoneyNum : { | |||||
| url: '/all_money/getMyMoneyNum', | |||||
| method: 'GET', | |||||
| auth: true, | |||||
| }, | |||||
| // 获取我的流水列表带分页 | |||||
| getMyMoneyLogPage : { | |||||
| url: '/all_money/getMyMoneyLogPage', | |||||
| method: 'GET', | |||||
| auth: true, | |||||
| }, | |||||
| } | |||||
| export default api | |||||
| @ -0,0 +1,51 @@ | |||||
| <template> | |||||
| <view class="book-status" | |||||
| :class="statusClass"> | |||||
| {{ statusText }} | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| export default { | |||||
| props : ['status'], | |||||
| computed: { | |||||
| statusClass() { | |||||
| const statusMap = { | |||||
| '0': 'ongoing', | |||||
| '1': 'completed' | |||||
| }; | |||||
| return statusMap[this.status] || 'ongoing'; | |||||
| }, | |||||
| statusText() { | |||||
| const textMap = { | |||||
| // '0': '新建', | |||||
| '0': '连载中', | |||||
| '1': '已完结' | |||||
| }; | |||||
| return textMap[this.status] || '连载中'; | |||||
| }, | |||||
| }, | |||||
| data() { | |||||
| return { | |||||
| } | |||||
| }, | |||||
| methods: { | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style scoped lang="scss"> | |||||
| .book-status { | |||||
| font-size: 20rpx; | |||||
| color: #67C23A; | |||||
| background-color: rgba(103, 194, 58, 0.1); | |||||
| border-radius: 20rpx; | |||||
| padding: 4rpx 12rpx; | |||||
| &.ongoing{ | |||||
| color: #ffa502; | |||||
| background-color: #ffa50223; | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @ -0,0 +1,408 @@ | |||||
| <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> | |||||
| @ -0,0 +1,218 @@ | |||||
| <template> | |||||
| <view class="sign-record-popup" :class="{'dark-mode': isDarkMode}"> | |||||
| <uv-popup ref="popup" mode="center" :closeOnClickOverlay="true" :customStyle="popupStyle"> | |||||
| <view class="content theme-transition"> | |||||
| <view class="popup-header"> | |||||
| <view class="popup-title theme-transition">签到记录</view> | |||||
| <view class="close-btn" @click="close"> | |||||
| <uv-icon name="close" :color="isDarkMode ? '#ccc' : '#666'" size="32rpx"></uv-icon> | |||||
| </view> | |||||
| </view> | |||||
| <view class="record-list"> | |||||
| <scroll-view scroll-y class="record-scroll"> | |||||
| <view class="record-item" v-for="(record, index) in recordList" :key="index"> | |||||
| <view class="record-left"> | |||||
| <view class="record-date">{{ formatDate(record.createTime) }}</view> | |||||
| <view class="record-task">{{ record.taskName || '每日签到' }}</view> | |||||
| </view> | |||||
| <view class="record-right"> | |||||
| <text class="record-reward">+{{ record.num || 1 }}推荐票</text> | |||||
| <text class="record-status success">已签到</text> | |||||
| </view> | |||||
| </view> | |||||
| <view class="no-record" v-if="recordList.length === 0 && !loading">暂无签到记录</view> | |||||
| <view class="loading" v-if="loading">加载中...</view> | |||||
| </scroll-view> | |||||
| </view> | |||||
| </view> | |||||
| </uv-popup> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| import themeMixin from '@/mixins/themeMode.js' | |||||
| export default { | |||||
| name: 'signRecordPopup', | |||||
| mixins: [themeMixin], | |||||
| data() { | |||||
| return { | |||||
| recordList: [], | |||||
| loading: false, | |||||
| pageNo: 1, | |||||
| pageSize: 20 | |||||
| } | |||||
| }, | |||||
| computed: { | |||||
| popupStyle() { | |||||
| return { | |||||
| 'background': this.isDarkMode ? '#232323' : '#fff', | |||||
| 'border-radius': '24rpx', | |||||
| 'width': '600rpx', | |||||
| 'max-height': '700rpx' | |||||
| } | |||||
| } | |||||
| }, | |||||
| methods: { | |||||
| // 打开弹窗 | |||||
| open() { | |||||
| this.$refs.popup.open(); | |||||
| this.getRecordList(); | |||||
| }, | |||||
| // 关闭弹窗 | |||||
| close() { | |||||
| this.$refs.popup.close(); | |||||
| }, | |||||
| // 获取签到记录列表 | |||||
| getRecordList() { | |||||
| this.loading = true; | |||||
| this.$fetch('getSignTaskRecordPage', { | |||||
| pageNo: this.pageNo, | |||||
| pageSize: this.pageSize | |||||
| }).then(res => { | |||||
| this.recordList = res.records || []; | |||||
| this.loading = false; | |||||
| }).catch(err => { | |||||
| console.error('获取签到记录失败:', err); | |||||
| this.loading = false; | |||||
| }); | |||||
| }, | |||||
| // 格式化日期 | |||||
| formatDate(dateString) { | |||||
| if (!dateString) return ''; | |||||
| const date = new Date(dateString); | |||||
| const month = (date.getMonth() + 1).toString().padStart(2, '0'); | |||||
| const day = date.getDate().toString().padStart(2, '0'); | |||||
| return `${month}-${day}`; | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .sign-record-popup { | |||||
| .content { | |||||
| padding: 0; | |||||
| .popup-header { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| padding: 32rpx 32rpx 24rpx; | |||||
| border-bottom: 1rpx solid #f5f5f5; | |||||
| .popup-title { | |||||
| font-size: 32rpx; | |||||
| font-weight: bold; | |||||
| color: #222; | |||||
| } | |||||
| .close-btn { | |||||
| width: 48rpx; | |||||
| height: 48rpx; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| } | |||||
| } | |||||
| .record-list { | |||||
| .record-scroll { | |||||
| max-height: 560rpx; | |||||
| .record-item { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| padding: 32rpx; | |||||
| border-bottom: 1rpx solid #f8f8f8; | |||||
| .record-left { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: flex-start; | |||||
| .record-date { | |||||
| font-size: 28rpx; | |||||
| color: #333; | |||||
| font-weight: 500; | |||||
| margin-bottom: 8rpx; | |||||
| } | |||||
| .record-task { | |||||
| font-size: 24rpx; | |||||
| color: #999; | |||||
| } | |||||
| } | |||||
| .record-right { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: flex-end; | |||||
| .record-reward { | |||||
| font-size: 26rpx; | |||||
| color: #ff6b35; | |||||
| margin-bottom: 4rpx; | |||||
| font-weight: 500; | |||||
| } | |||||
| .record-status { | |||||
| font-size: 22rpx; | |||||
| &.success { | |||||
| color: #4caf50; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .no-record, .loading { | |||||
| text-align: center; | |||||
| padding: 80rpx 32rpx; | |||||
| color: #999; | |||||
| font-size: 26rpx; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| &.dark-mode { | |||||
| .content { | |||||
| .popup-header { | |||||
| border-bottom-color: #333; | |||||
| .popup-title { | |||||
| color: #eee; | |||||
| } | |||||
| } | |||||
| .record-list { | |||||
| .record-scroll { | |||||
| .record-item { | |||||
| border-bottom-color: #333; | |||||
| .record-left { | |||||
| .record-date { | |||||
| color: #ccc; | |||||
| } | |||||
| .record-task { | |||||
| color: #888; | |||||
| } | |||||
| } | |||||
| } | |||||
| .no-record, .loading { | |||||
| color: #666; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @ -0,0 +1,364 @@ | |||||
| <!-- 钱包流水页面 --> | |||||
| <template> | |||||
| <view class="walletflow-page"> | |||||
| <!-- 顶部导航栏 --> | |||||
| <navbar title="钱包流水" leftClick @leftClick="$utils.navigateBack" /> | |||||
| <!-- 账户余额卡片 --> | |||||
| <view class="balance-card"> | |||||
| <view class="balance-label">账户</view> | |||||
| <view class="balance-row"> | |||||
| <text class="balance-amount">{{ accountBalance }}</text> | |||||
| <button class="recharge-btn" @click="goRecharge">充值</button> | |||||
| </view> | |||||
| </view> | |||||
| <!-- tab和流水列表卡片 --> | |||||
| <view class="flow-card"> | |||||
| <uv-tabs | |||||
| :list="tabList" | |||||
| :current="activeTab" | |||||
| @change="switchTab" | |||||
| :scrollable="false" | |||||
| activeColor="#223a7a" | |||||
| inactiveColor="#888" | |||||
| lineColor="#223a7a" | |||||
| lineWidth="44rpx" | |||||
| lineHeight="4rpx" | |||||
| :itemStyle="{ | |||||
| height: '88rpx', | |||||
| fontSize: '30rpx', | |||||
| fontWeight: 'bold' | |||||
| }" | |||||
| ></uv-tabs> | |||||
| <scroll-view scroll-y class="flow-list" @scrolltolower="loadMore"> | |||||
| <view v-if="activeTab === 0"> | |||||
| <view class="flow-item" v-for="(item, idx) in rechargeList" :key="idx"> | |||||
| <view class="flow-item-row"> | |||||
| <view class="flow-item-left"> | |||||
| <view class="flow-title">{{ item.title || item.type || '充值' }}</view> | |||||
| <view class="flow-date">{{ formatDate(item.createTime) }}</view> | |||||
| </view> | |||||
| <view class="flow-amount plus">+{{ item.num }}</view> | |||||
| </view> | |||||
| </view> | |||||
| <view v-if="rechargeList.length === 0 && !loading" class="empty-tip">暂无充值记录</view> | |||||
| </view> | |||||
| <view v-else> | |||||
| <view class="flow-item" v-for="(item, idx) in payList" :key="idx"> | |||||
| <view class="flow-item-row"> | |||||
| <view class="flow-item-left"> | |||||
| <view class="flow-title">{{ item.title || item.type || '支付' }}</view> | |||||
| <view class="flow-date">{{ formatDate(item.createTime) }}</view> | |||||
| </view> | |||||
| <view class="flow-amount minus">-{{ item.num }}</view> | |||||
| </view> | |||||
| </view> | |||||
| <view v-if="payList.length === 0 && !loading" class="empty-tip">暂无支付记录</view> | |||||
| </view> | |||||
| <view v-if="loading" class="loading-tip">加载中...</view> | |||||
| <view v-if="noMore && (rechargeList.length > 0 || payList.length > 0)" class="no-more-tip">没有更多了</view> | |||||
| </scroll-view> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| import mixinsList from '@/mixins/list.js' | |||||
| export default { | |||||
| mixins: [mixinsList], | |||||
| components: { | |||||
| }, | |||||
| data() { | |||||
| return { | |||||
| accountBalance: 0, | |||||
| activeTab: 0, | |||||
| rechargeList: [], | |||||
| payList: [], | |||||
| loading: false, | |||||
| noMore: false, | |||||
| pageNo: 1, | |||||
| pageSize: 20, | |||||
| tabList: [ | |||||
| { | |||||
| name: '充值', | |||||
| value: 0 | |||||
| }, | |||||
| { | |||||
| name: '支付', | |||||
| value: 1 | |||||
| } | |||||
| ] | |||||
| } | |||||
| }, | |||||
| onLoad() { | |||||
| this.getAccountBalance(); | |||||
| this.getFlowList(); | |||||
| }, | |||||
| methods: { | |||||
| // 获取账户余额 | |||||
| getAccountBalance() { | |||||
| this.$fetch('getMyMoneyNum').then(res => { | |||||
| this.accountBalance = res || 0; | |||||
| }).catch(err => { | |||||
| console.error('获取账户余额失败:', err); | |||||
| this.accountBalance = 0; | |||||
| }); | |||||
| }, | |||||
| // 切换tab | |||||
| switchTab(tab) { | |||||
| // uv-tabs组件传递的可能是对象,需要获取index | |||||
| const tabIndex = typeof tab === 'object' ? tab.index : tab; | |||||
| if (this.activeTab === tabIndex) return; | |||||
| this.activeTab = tabIndex; | |||||
| this.pageNo = 1; | |||||
| this.noMore = false; | |||||
| // 清空对应列表 | |||||
| if (tabIndex === 0) { | |||||
| this.rechargeList = []; | |||||
| } else { | |||||
| this.payList = []; | |||||
| } | |||||
| this.getFlowList(); | |||||
| }, | |||||
| // 获取流水列表 | |||||
| getFlowList() { | |||||
| if (this.loading || this.noMore) return; | |||||
| this.loading = true; | |||||
| // 根据当前tab确定流水类型:0-充值,1-支付 | |||||
| const logType = this.activeTab === 0 ? 0 : 1; | |||||
| this.$fetch('getMyMoneyLogPage', { | |||||
| pageNo: this.pageNo, | |||||
| pageSize: this.pageSize, | |||||
| status: logType // 0-充值记录,1-支付记录 | |||||
| }).then(res => { | |||||
| const records = res.records || []; | |||||
| if (records.length === 0) { | |||||
| this.noMore = true; | |||||
| } else { | |||||
| if (this.activeTab === 0) { | |||||
| // 充值记录 | |||||
| if (this.pageNo === 1) { | |||||
| this.rechargeList = records; | |||||
| } else { | |||||
| this.rechargeList = [...this.rechargeList, ...records]; | |||||
| } | |||||
| } else { | |||||
| // 支付记录 | |||||
| if (this.pageNo === 1) { | |||||
| this.payList = records; | |||||
| } else { | |||||
| this.payList = [...this.payList, ...records]; | |||||
| } | |||||
| } | |||||
| // 如果返回的记录数少于pageSize,说明没有更多了 | |||||
| if (records.length < this.pageSize) { | |||||
| this.noMore = true; | |||||
| } | |||||
| } | |||||
| this.loading = false; | |||||
| }).catch(err => { | |||||
| console.error('获取流水列表失败:', err); | |||||
| this.loading = false; | |||||
| uni.showToast({ | |||||
| title: '获取流水失败', | |||||
| icon: 'none' | |||||
| }); | |||||
| }); | |||||
| }, | |||||
| // 加载更多 | |||||
| loadMore() { | |||||
| if (this.loading || this.noMore) return; | |||||
| this.pageNo++; | |||||
| this.getFlowList(); | |||||
| }, | |||||
| // 格式化日期 | |||||
| formatDate(dateString) { | |||||
| if (!dateString) return ''; | |||||
| const date = new Date(dateString); | |||||
| const year = date.getFullYear(); | |||||
| const month = (date.getMonth() + 1).toString().padStart(2, '0'); | |||||
| const day = date.getDate().toString().padStart(2, '0'); | |||||
| return `${year}.${month}.${day}`; | |||||
| }, | |||||
| goRecharge() { | |||||
| uni.navigateTo({ | |||||
| url: '/pages_order/mine/recharge' | |||||
| }) | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .walletflow-page { | |||||
| min-height: 100vh; | |||||
| background: linear-gradient(180deg, #f8f8fc 0%, #fff 100%); | |||||
| padding-bottom: 30rpx; | |||||
| } | |||||
| .balance-card { | |||||
| background: linear-gradient(90deg, #f7f2fa 0%, #fbeaf2 100%); | |||||
| border-radius: 18rpx; | |||||
| margin: 24rpx 12rpx 0 12rpx; | |||||
| padding: 18rpx 24rpx 14rpx 24rpx; | |||||
| box-shadow: none; | |||||
| border: 1rpx solid #ede7ef; | |||||
| position: relative; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| min-height: 130rpx; | |||||
| justify-content: center; | |||||
| .balance-label { | |||||
| color: #bbb; | |||||
| font-size: 26rpx; | |||||
| margin-bottom: 8rpx; | |||||
| } | |||||
| .balance-row { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-top: 0; | |||||
| position: relative; | |||||
| .balance-amount { | |||||
| color: #e94f7a; | |||||
| font-size: 48rpx; | |||||
| font-weight: bold; | |||||
| } | |||||
| .recharge-btn { | |||||
| position: absolute; | |||||
| right: 0; | |||||
| top: 50%; | |||||
| transform: translateY(-50%); | |||||
| background: linear-gradient(90deg, #ffb6c1 0%, #fa5a99 100%); | |||||
| color: #fff; | |||||
| font-size: 28rpx; | |||||
| border-radius: 32rpx; | |||||
| padding: 0 40rpx; | |||||
| height: 56rpx; | |||||
| line-height: 56rpx; | |||||
| font-weight: 500; | |||||
| border: none; | |||||
| box-shadow: none; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| } | |||||
| } | |||||
| } | |||||
| .flow-card { | |||||
| background: #fff; | |||||
| border-radius: 20rpx; | |||||
| margin: 32rpx 16rpx 0 16rpx; | |||||
| box-shadow: 0 4rpx 24rpx 0 rgba(0, 0, 0, 0.06); | |||||
| padding-bottom: 8rpx; | |||||
| overflow: hidden; | |||||
| // uv-tabs组件样式调整 | |||||
| :deep(.uv-tabs) { | |||||
| background: #fff; | |||||
| border-top-left-radius: 20rpx; | |||||
| border-top-right-radius: 20rpx; | |||||
| } | |||||
| :deep(.uv-tabs__wrapper__nav__line) { | |||||
| border-radius: 2rpx !important; | |||||
| } | |||||
| } | |||||
| .flow-list { | |||||
| margin: 0; | |||||
| padding: 0 16rpx; | |||||
| max-height: calc(75vh - 88rpx); | |||||
| background: #fff; | |||||
| } | |||||
| .flow-item { | |||||
| border-bottom: 1px solid #f5f5f5; | |||||
| padding: 18rpx 0 8rpx 0; | |||||
| &:last-child { | |||||
| border-bottom: none; | |||||
| } | |||||
| .flow-item-row { | |||||
| display: flex; | |||||
| align-items: flex-start; | |||||
| justify-content: space-between; | |||||
| padding-right: 45rpx; | |||||
| padding-left: 15rpx; | |||||
| } | |||||
| .flow-item-left { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: flex-start; | |||||
| .flow-title { | |||||
| font-size: 28rpx; | |||||
| color: #222; | |||||
| font-weight: 500; | |||||
| margin-bottom: 2rpx; | |||||
| } | |||||
| .flow-date { | |||||
| color: #bbb; | |||||
| font-size: 22rpx; | |||||
| margin-top: 0; | |||||
| } | |||||
| } | |||||
| .flow-amount { | |||||
| font-size: 26rpx; | |||||
| font-weight: 500; | |||||
| margin-left: 24rpx; | |||||
| margin-top: 2rpx; | |||||
| &.plus { | |||||
| color: #223a7a; | |||||
| } | |||||
| &.minus { | |||||
| color: #e94f7a; | |||||
| } | |||||
| } | |||||
| } | |||||
| // 提示文字样式 | |||||
| .empty-tip, | |||||
| .loading-tip, | |||||
| .no-more-tip { | |||||
| text-align: center; | |||||
| padding: 40rpx 0; | |||||
| color: #999; | |||||
| font-size: 26rpx; | |||||
| } | |||||
| .loading-tip { | |||||
| color: #666; | |||||
| } | |||||
| </style> | |||||
| @ -0,0 +1,530 @@ | |||||
| <template> | |||||
| <!-- 豆豆充值页面 --> | |||||
| <view class="recharge-page"> | |||||
| <!-- 顶部导航栏 --> | |||||
| <navbar title="豆豆充值" leftClick @leftClick="$utils.navigateBack" /> | |||||
| <!-- 当前余额卡片 --> | |||||
| <view class="card balance-card"> | |||||
| <view class="card-title">当前余额</view> | |||||
| <view class="current-balance"> | |||||
| <text class="balance-amount">{{ userInfo.integerPrice || 0 }}</text> | |||||
| <text class="balance-unit">豆豆</text> | |||||
| </view> | |||||
| </view> | |||||
| <!-- 充值套餐选择 --> | |||||
| <view class="card package-card"> | |||||
| <view class="card-title">选择充值套餐</view> | |||||
| <view class="package-grid"> | |||||
| <view | |||||
| v-for="(item, index) in rechargePackages" | |||||
| :key="index" | |||||
| :class="['package-item', { selected: selectedPackage === index }]" | |||||
| @click="selectPackage(index)" | |||||
| > | |||||
| <view class="package-beans">{{ item.num }}豆豆</view> | |||||
| <view class="package-price">¥{{ item.money }}</view> | |||||
| <view v-if="item.giveNum" class="package-bonus">送{{ item.giveNum }}豆豆</view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <!-- 自定义充值 --> | |||||
| <!-- <view class="card custom-card"> | |||||
| <view class="card-title">自定义充值</view> | |||||
| <view class="form-row"> | |||||
| <view class="form-label required"> | |||||
| <text class="star">*</text> 充值金额(元) | |||||
| </view> | |||||
| <input | |||||
| class="form-input" | |||||
| placeholder="请输入充值金额" | |||||
| v-model="customAmount" | |||||
| type="number" | |||||
| :placeholder-style="'color:#bbb;'" | |||||
| :style="customAmount ? 'color:#222;' : ''" | |||||
| @input="onCustomAmountChange" | |||||
| /> | |||||
| </view> | |||||
| <view class="divider"></view> | |||||
| <view class="form-row"> | |||||
| <view class="form-label">可获得豆豆</view> | |||||
| <view class="form-value">{{ customBeans }}豆豆</view> | |||||
| </view> | |||||
| </view> --> | |||||
| <!-- 订单信息卡片 --> | |||||
| <view class="card order-card" v-if="totalPrice > 0"> | |||||
| <view class="order-title">订单信息</view> | |||||
| <view class="order-item"> | |||||
| <text class="order-label">充值金额:</text> | |||||
| <text class="order-value">¥{{ totalPrice.toFixed(2) }}</text> | |||||
| </view> | |||||
| <view class="order-item"> | |||||
| <text class="order-label">获得豆豆:</text> | |||||
| <text class="order-value">{{ totalBeans }}豆豆</text> | |||||
| </view> | |||||
| <view class="order-divider"></view> | |||||
| <view class="order-item total-row"> | |||||
| <view class="order-total-label">合计:</view> | |||||
| <view class="order-total"> | |||||
| <text class="order-total-highlight">¥{{ totalPrice.toFixed(2) }}</text> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <!-- 支付方式 --> | |||||
| <!-- <view class="card payment-card"> | |||||
| <view class="card-title">支付方式</view> | |||||
| <view class="payment-methods"> | |||||
| <view | |||||
| v-for="(method, index) in paymentMethods" | |||||
| :key="index" | |||||
| :class="['payment-item', { selected: selectedPayment === index }]" | |||||
| @click="selectPayment(index)" | |||||
| > | |||||
| <view class="payment-icon"> | |||||
| <uv-icon :name="method.icon" size="40rpx" color="#223a7a" /> | |||||
| </view> | |||||
| <text class="payment-name">{{ method.name }}</text> | |||||
| <view class="payment-radio"> | |||||
| <view v-if="selectedPayment === index" class="radio-checked"></view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </view> --> | |||||
| <!-- 提示信息 --> | |||||
| <view class="tip-text"> | |||||
| 请仔细核查并确认相关信息。因用户个人疏忽导致的充值错误,需由用户自行承担。一旦完成充值,概不退换。 | |||||
| </view> | |||||
| <!-- 底部充值按钮 --> | |||||
| <view class="footer-bar"> | |||||
| <button class="recharge-btn" @click="handleRecharge" :disabled="totalPrice <= 0"> | |||||
| 立即充值 ¥{{ totalPrice.toFixed(2) }} | |||||
| </button> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| selectedPackage: null, | |||||
| customAmount: '', | |||||
| selectedPayment: 0, | |||||
| rechargePackages: [ | |||||
| // { beans: 100, price: 10, bonus: 0 }, | |||||
| // { beans: 300, price: 30, bonus: 20 }, | |||||
| // { beans: 680, price: 68, bonus: 50 }, | |||||
| // { beans: 1280, price: 128, bonus: 120 }, | |||||
| // { beans: 3280, price: 328, bonus: 320 }, | |||||
| // { beans: 6480, price: 648, bonus: 680 } | |||||
| ], | |||||
| paymentMethods: [ | |||||
| { name: '微信支付', icon: 'weixin-fill' }, | |||||
| ] | |||||
| } | |||||
| }, | |||||
| computed: { | |||||
| customBeans() { | |||||
| const amount = parseFloat(this.customAmount) | |||||
| return isNaN(amount) ? 0 : Math.floor(amount * 10) | |||||
| }, | |||||
| totalPrice() { | |||||
| if (this.selectedPackage !== null) { | |||||
| return this.rechargePackages[this.selectedPackage].money | |||||
| } else if (this.customAmount) { | |||||
| return parseFloat(this.customAmount) || 0 | |||||
| } | |||||
| return 0 | |||||
| }, | |||||
| totalBeans() { | |||||
| if (this.selectedPackage !== null) { | |||||
| const pkg = this.rechargePackages[this.selectedPackage] | |||||
| return pkg.num + (pkg.giveNum || 0) | |||||
| } else if (this.customAmount) { | |||||
| return this.customBeans | |||||
| } | |||||
| return 0 | |||||
| } | |||||
| }, | |||||
| onLoad(query) { | |||||
| // 可以通过参数预设充值金额 | |||||
| if (query.amount) { | |||||
| this.customAmount = query.amount | |||||
| } | |||||
| }, | |||||
| onShow() { | |||||
| this.$store.commit('getUserInfo') | |||||
| this.getPayPackageList() | |||||
| }, | |||||
| methods: { | |||||
| getPayPackageList(){ | |||||
| this.$api('getPayPackageList') | |||||
| .then(res => { | |||||
| if(res.code == 200){ | |||||
| this.rechargePackages = res.result | |||||
| } | |||||
| }) | |||||
| }, | |||||
| // 选择充值套餐 | |||||
| selectPackage(index) { | |||||
| this.selectedPackage = index | |||||
| this.customAmount = '' | |||||
| }, | |||||
| // 选择支付方式 | |||||
| selectPayment(index) { | |||||
| this.selectedPayment = index | |||||
| }, | |||||
| // 自定义金额输入变化 | |||||
| onCustomAmountChange() { | |||||
| if (this.customAmount) { | |||||
| this.selectedPackage = null | |||||
| } | |||||
| }, | |||||
| // 处理充值 | |||||
| async handleRecharge() { | |||||
| if (this.totalPrice <= 0) { | |||||
| uni.showToast({ | |||||
| title: '请选择充值套餐或输入充值金额', | |||||
| icon: 'none' | |||||
| }) | |||||
| return | |||||
| } | |||||
| if (this.selectedPayment === null) { | |||||
| uni.showToast({ | |||||
| title: '请选择支付方式', | |||||
| icon: 'none' | |||||
| }) | |||||
| return | |||||
| } | |||||
| try { | |||||
| // 这里应该调用充值接口 | |||||
| const result = await this.$fetch('createPayPackageOrder', { | |||||
| // amount: this.totalPrice, | |||||
| // beans: this.totalBeans, | |||||
| // paymentMethod: this.paymentMethods[this.selectedPayment].name | |||||
| packageId : this.rechargePackages[this.selectedPackage].id | |||||
| }) | |||||
| await uni.requestPaymentWxPay({result}) | |||||
| uni.showToast({ | |||||
| title: `充值成功,获得${this.totalBeans}豆豆`, | |||||
| icon: 'success' | |||||
| }) | |||||
| // 更新用户信息 | |||||
| this.$store.commit('getUserInfo') | |||||
| setTimeout(() => { | |||||
| uni.navigateBack() | |||||
| }, 1500) | |||||
| } catch (error) { | |||||
| uni.showToast({ | |||||
| title: '充值失败,请重试', | |||||
| icon: 'none' | |||||
| }) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style scoped lang="scss"> | |||||
| .recharge-page { | |||||
| min-height: 100vh; | |||||
| background: #f8f8f8; | |||||
| padding-bottom: 120rpx; | |||||
| } | |||||
| .card { | |||||
| background: #fff; | |||||
| border-radius: 20rpx; | |||||
| margin: 24rpx 16rpx 0 16rpx; | |||||
| padding: 24rpx; | |||||
| box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03); | |||||
| } | |||||
| .card-title { | |||||
| font-size: 32rpx; | |||||
| font-weight: bold; | |||||
| color: #222; | |||||
| margin-bottom: 24rpx; | |||||
| } | |||||
| // 当前余额卡片 | |||||
| .balance-card { | |||||
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |||||
| color: #fff; | |||||
| text-align: center; | |||||
| .card-title { | |||||
| color: #fff; | |||||
| opacity: 0.9; | |||||
| } | |||||
| .current-balance { | |||||
| display: flex; | |||||
| align-items: baseline; | |||||
| justify-content: center; | |||||
| gap: 8rpx; | |||||
| margin-top: 16rpx; | |||||
| .balance-amount { | |||||
| font-size: 56rpx; | |||||
| font-weight: bold; | |||||
| } | |||||
| .balance-unit { | |||||
| font-size: 28rpx; | |||||
| opacity: 0.8; | |||||
| } | |||||
| } | |||||
| } | |||||
| // 充值套餐 | |||||
| .package-grid { | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| gap: 16rpx; | |||||
| } | |||||
| .package-item { | |||||
| width: calc(50% - 8rpx); | |||||
| background: #f8f9ff; | |||||
| border: 2rpx solid #f0f0f0; | |||||
| border-radius: 16rpx; | |||||
| padding: 24rpx 16rpx; | |||||
| text-align: center; | |||||
| transition: all 0.2s; | |||||
| position: relative; | |||||
| box-sizing: border-box; | |||||
| &.selected { | |||||
| border-color: #223a7a; | |||||
| background: rgba(34, 58, 122, 0.05); | |||||
| } | |||||
| .package-beans { | |||||
| font-size: 32rpx; | |||||
| font-weight: bold; | |||||
| color: #222; | |||||
| margin-bottom: 8rpx; | |||||
| } | |||||
| .package-price { | |||||
| font-size: 28rpx; | |||||
| color: #223a7a; | |||||
| font-weight: 500; | |||||
| margin-bottom: 4rpx; | |||||
| } | |||||
| .package-bonus { | |||||
| font-size: 20rpx; | |||||
| color: #e94f7a; | |||||
| background: rgba(233, 79, 122, 0.1); | |||||
| padding: 2rpx 8rpx; | |||||
| border-radius: 8rpx; | |||||
| display: inline-block; | |||||
| } | |||||
| } | |||||
| // 表单样式 | |||||
| .form-row { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: flex-start; | |||||
| margin-bottom: 24rpx; | |||||
| } | |||||
| .form-label { | |||||
| color: #888; | |||||
| font-size: 28rpx; | |||||
| margin-bottom: 12rpx; | |||||
| font-weight: 400; | |||||
| &.required { | |||||
| color: #222; | |||||
| font-weight: 500; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| } | |||||
| .star { | |||||
| color: #e94f7a; | |||||
| margin-right: 4rpx; | |||||
| font-size: 28rpx; | |||||
| } | |||||
| .form-value { | |||||
| color: #222; | |||||
| font-size: 28rpx; | |||||
| font-weight: 600; | |||||
| } | |||||
| .form-input { | |||||
| width: 100%; | |||||
| border: 1rpx solid #e5e5e5; | |||||
| border-radius: 12rpx; | |||||
| font-size: 28rpx; | |||||
| padding: 16rpx; | |||||
| background: #fafafa; | |||||
| color: #222; | |||||
| box-sizing: border-box; | |||||
| } | |||||
| .divider { | |||||
| height: 1rpx; | |||||
| background: #f2f2f2; | |||||
| margin: 16rpx 0; | |||||
| width: 100%; | |||||
| } | |||||
| // 订单信息 | |||||
| .order-card { | |||||
| .order-item { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| margin-bottom: 16rpx; | |||||
| .order-label { | |||||
| font-size: 28rpx; | |||||
| color: #666; | |||||
| } | |||||
| .order-value { | |||||
| font-size: 28rpx; | |||||
| color: #222; | |||||
| font-weight: 500; | |||||
| } | |||||
| &.total-row { | |||||
| margin-bottom: 0; | |||||
| margin-top: 16rpx; | |||||
| .order-total-label { | |||||
| font-size: 32rpx; | |||||
| color: #222; | |||||
| font-weight: 600; | |||||
| } | |||||
| .order-total-highlight { | |||||
| font-size: 32rpx; | |||||
| color: #223a7a; | |||||
| font-weight: bold; | |||||
| } | |||||
| } | |||||
| } | |||||
| .order-divider { | |||||
| height: 1rpx; | |||||
| background: #f2f2f2; | |||||
| margin: 16rpx 0; | |||||
| } | |||||
| } | |||||
| // 支付方式 | |||||
| .payment-methods { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| gap: 16rpx; | |||||
| } | |||||
| .payment-item { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| padding: 20rpx; | |||||
| border: 2rpx solid #f0f0f0; | |||||
| border-radius: 12rpx; | |||||
| transition: all 0.2s; | |||||
| &.selected { | |||||
| border-color: #223a7a; | |||||
| background: rgba(34, 58, 122, 0.05); | |||||
| } | |||||
| .payment-icon { | |||||
| width: 48rpx; | |||||
| height: 48rpx; | |||||
| margin-right: 16rpx; | |||||
| image { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| } | |||||
| } | |||||
| .payment-name { | |||||
| flex: 1; | |||||
| font-size: 28rpx; | |||||
| color: #222; | |||||
| } | |||||
| .payment-radio { | |||||
| width: 32rpx; | |||||
| height: 32rpx; | |||||
| border: 2rpx solid #ddd; | |||||
| border-radius: 50%; | |||||
| position: relative; | |||||
| .radio-checked { | |||||
| width: 16rpx; | |||||
| height: 16rpx; | |||||
| background: #223a7a; | |||||
| border-radius: 50%; | |||||
| position: absolute; | |||||
| top: 50%; | |||||
| left: 50%; | |||||
| transform: translate(-50%, -50%); | |||||
| } | |||||
| } | |||||
| } | |||||
| .tip-text { | |||||
| color: #bbb; | |||||
| font-size: 22rpx; | |||||
| margin: 32rpx 32rpx 0 32rpx; | |||||
| line-height: 1.6; | |||||
| } | |||||
| .footer-bar { | |||||
| // position: fixed; | |||||
| // left: 0; | |||||
| // right: 0; | |||||
| // bottom: 90rpx; | |||||
| background: #fff; | |||||
| padding: 24rpx 32rpx 32rpx 32rpx; | |||||
| box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05); | |||||
| z-index: 10; | |||||
| } | |||||
| .recharge-btn { | |||||
| width: 100%; | |||||
| background: #223a7a; | |||||
| color: #fff; | |||||
| font-size: 32rpx; | |||||
| border-radius: 32rpx; | |||||
| height: 88rpx; | |||||
| line-height: 88rpx; | |||||
| border: none; | |||||
| font-weight: 500; | |||||
| &[disabled] { | |||||
| background: #ccc; | |||||
| color: #999; | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @ -1,388 +0,0 @@ | |||||
| <!-- 钱包流水页面 --> | |||||
| <template> | |||||
| <view class="walletflow-page"> | |||||
| <!-- 顶部导航栏 --> | |||||
| <navbar title="钱包流水" leftClick @leftClick="$utils.navigateBack" /> | |||||
| <!-- 账户余额卡片 --> | |||||
| <view class="balance-card"> | |||||
| <view class="balance-label">账户</view> | |||||
| <view class="balance-row"> | |||||
| <text class="balance-amount">{{ balance }}</text> | |||||
| <button class="recharge-btn" @click="goRecharge">充值</button> | |||||
| </view> | |||||
| </view> | |||||
| <!-- tab和流水列表卡片 --> | |||||
| <view class="flow-card"> | |||||
| <view class="tab-header"> | |||||
| <view :class="['tab-item', {active: activeTab === 0}]" @click="activeTab = 0"> | |||||
| 充值 | |||||
| <view v-if="activeTab === 0" class="tab-underline"></view> | |||||
| </view> | |||||
| <view :class="['tab-item', {active: activeTab === 1}]" @click="activeTab = 1"> | |||||
| 支付 | |||||
| <view v-if="activeTab === 1" class="tab-underline"></view> | |||||
| </view> | |||||
| </view> | |||||
| <scroll-view scroll-y class="flow-list"> | |||||
| <view v-if="activeTab === 0"> | |||||
| <view class="flow-item" v-for="(item, idx) in rechargeList" :key="idx"> | |||||
| <view class="flow-item-row"> | |||||
| <view class="flow-item-left"> | |||||
| <view class="flow-title">{{ item.title }}</view> | |||||
| <view class="flow-date">{{ item.date }}</view> | |||||
| </view> | |||||
| <view class="flow-amount plus">+{{ item.amount }}</view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| <view v-else> | |||||
| <view class="flow-item" v-for="(item, idx) in payList" :key="idx"> | |||||
| <view class="flow-item-row"> | |||||
| <view class="flow-item-left"> | |||||
| <view class="flow-title">{{ item.title }}</view> | |||||
| <view class="flow-date">{{ item.date }}</view> | |||||
| </view> | |||||
| <view class="flow-amount minus">-{{ item.amount }}</view> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </scroll-view> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| export default { | |||||
| components: { | |||||
| }, | |||||
| data() { | |||||
| return { | |||||
| balance: 34532, | |||||
| activeTab: 0, | |||||
| rechargeList: [{ | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '推荐票', | |||||
| date: '2025.03.18', | |||||
| amount: 5 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| { | |||||
| title: '豆豆充值', | |||||
| date: '2025.03.18', | |||||
| amount: 55 | |||||
| }, | |||||
| ], | |||||
| payList: [{ | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| { | |||||
| title: '章节支付', | |||||
| date: '2025.03.18', | |||||
| amount: 10 | |||||
| }, | |||||
| ] | |||||
| } | |||||
| }, | |||||
| methods: { | |||||
| goRecharge() { | |||||
| uni.showToast({ | |||||
| title: '充值功能开发中', | |||||
| icon: 'none' | |||||
| }) | |||||
| } | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .walletflow-page { | |||||
| min-height: 100vh; | |||||
| background: linear-gradient(180deg, #f8f8fc 0%, #fff 100%); | |||||
| padding-bottom: 30rpx; | |||||
| } | |||||
| .balance-card { | |||||
| background: linear-gradient(90deg, #f7f2fa 0%, #fbeaf2 100%); | |||||
| border-radius: 18rpx; | |||||
| margin: 24rpx 12rpx 0 12rpx; | |||||
| padding: 18rpx 24rpx 14rpx 24rpx; | |||||
| box-shadow: none; | |||||
| border: 1rpx solid #ede7ef; | |||||
| position: relative; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| min-height: 130rpx; | |||||
| justify-content: center; | |||||
| .balance-label { | |||||
| color: #bbb; | |||||
| font-size: 26rpx; | |||||
| margin-bottom: 8rpx; | |||||
| } | |||||
| .balance-row { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-top: 0; | |||||
| position: relative; | |||||
| .balance-amount { | |||||
| color: #e94f7a; | |||||
| font-size: 48rpx; | |||||
| font-weight: bold; | |||||
| } | |||||
| .recharge-btn { | |||||
| position: absolute; | |||||
| right: 0; | |||||
| top: 50%; | |||||
| transform: translateY(-50%); | |||||
| background: linear-gradient(90deg, #ffb6c1 0%, #fa5a99 100%); | |||||
| color: #fff; | |||||
| font-size: 28rpx; | |||||
| border-radius: 32rpx; | |||||
| padding: 0 40rpx; | |||||
| height: 56rpx; | |||||
| line-height: 56rpx; | |||||
| font-weight: 500; | |||||
| border: none; | |||||
| box-shadow: none; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| } | |||||
| } | |||||
| } | |||||
| .flow-card { | |||||
| background: #fff; | |||||
| border-radius: 20rpx; | |||||
| margin: 32rpx 16rpx 0 16rpx; | |||||
| box-shadow: 0 4rpx 24rpx 0 rgba(0, 0, 0, 0.06); | |||||
| padding-bottom: 8rpx; | |||||
| overflow: hidden; | |||||
| } | |||||
| .tab-header { | |||||
| display: flex; | |||||
| margin: 0; | |||||
| background: #fff; | |||||
| border-top-left-radius: 20rpx; | |||||
| border-top-right-radius: 20rpx; | |||||
| overflow: hidden; | |||||
| .tab-item { | |||||
| flex: 1; | |||||
| text-align: center; | |||||
| font-size: 30rpx; | |||||
| color: #888; | |||||
| padding: 0 0 18rpx 0; | |||||
| font-weight: bold; | |||||
| background: transparent; | |||||
| position: relative; | |||||
| &.active { | |||||
| color: #223a7a; | |||||
| font-weight: bold; | |||||
| } | |||||
| .tab-underline { | |||||
| position: absolute; | |||||
| left: 50%; | |||||
| bottom: 0; | |||||
| transform: translateX(-50%); | |||||
| width: 44rpx; | |||||
| height: 4rpx; | |||||
| background: #223a7a; | |||||
| border-radius: 2rpx; | |||||
| margin-top: 4rpx; | |||||
| } | |||||
| } | |||||
| } | |||||
| .flow-list { | |||||
| margin: 0; | |||||
| padding: 0 16rpx; | |||||
| max-height: 75vh; | |||||
| background: #fff; | |||||
| } | |||||
| .flow-item { | |||||
| border-bottom: 1px solid #f5f5f5; | |||||
| padding: 18rpx 0 8rpx 0; | |||||
| &:last-child { | |||||
| border-bottom: none; | |||||
| } | |||||
| .flow-item-row { | |||||
| display: flex; | |||||
| align-items: flex-start; | |||||
| justify-content: space-between; | |||||
| padding-right: 45rpx; | |||||
| padding-left: 15rpx; | |||||
| } | |||||
| .flow-item-left { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: flex-start; | |||||
| .flow-title { | |||||
| font-size: 28rpx; | |||||
| color: #222; | |||||
| font-weight: 500; | |||||
| margin-bottom: 2rpx; | |||||
| } | |||||
| .flow-date { | |||||
| color: #bbb; | |||||
| font-size: 22rpx; | |||||
| margin-top: 0; | |||||
| } | |||||
| } | |||||
| .flow-amount { | |||||
| font-size: 26rpx; | |||||
| font-weight: 500; | |||||
| margin-left: 24rpx; | |||||
| margin-top: 2rpx; | |||||
| &.plus { | |||||
| color: #223a7a; | |||||
| } | |||||
| &.minus { | |||||
| color: #e94f7a; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> | |||||