bindbox-mini/pages/mine/index.vue
2025-11-24 22:37:11 +08:00

176 lines
6.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="wrap">
<view class="header">
<image class="avatar" :src="avatar || '/static/logo.png'" mode="aspectFill"></image>
<view class="profile">
<view class="nickname">{{ nickname || '未登录' }}</view>
<view class="userid">ID{{ userId || '-' }}</view>
</view>
</view>
<view class="info">
<view class="info-item">
<text class="info-label">手机号</text>
<text class="info-value">{{ phoneNumber || '未绑定' }}</text>
</view>
<view class="info-item">
<text class="info-label">邀请码</text>
<text class="info-value">{{ inviteCode || '-' }}</text>
</view>
</view>
<view class="stats">
<view class="stat">
<view class="stat-label" @click="toPoints">积分</view>
<view class="stat-value">{{ pointsBalance }}</view>
</view>
<view class="stat">
<view class="stat-label">卡券</view>
<view class="stat-value">{{ stats.coupon_count || 0 }}</view>
</view>
<view class="stat">
<view class="stat-label">道具卡</view>
<view class="stat-value">{{ stats.item_card_count || 0 }}</view>
</view>
</view>
<button class="refresh" @click="refresh" :disabled="loading">刷新数据</button>
<view v-if="error" class="error">{{ error }}</view>
</view>
<view class="orders">
<view class="orders-title">我的订单</view>
<view class="orders-cats">
<view class="orders-cat" @click="toOrders('pending')">
<view class="orders-cat-title">待付款</view>
</view>
<view class="orders-cat" @click="toOrders('completed')">
<view class="orders-cat-title">已完成</view>
</view>
</view>
</view>
<view class="addresses">
<view class="addresses-title">地址管理</view>
<view class="addresses-entry" @click="toAddresses">
<text class="addresses-text">管理收货地址</text>
<text class="addresses-arrow"></text>
</view>
</view>
<view class="addresses">
<view class="addresses-title">使用帮助</view>
<view class="addresses-entry" @click="toHelp">
<text class="addresses-text">查看协议与说明</text>
<text class="addresses-arrow"></text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onShow, onLoad } from '@dcloudio/uni-app'
import { getUserStats, getPointsBalance } from '../../api/appUser'
const avatar = ref(uni.getStorageSync('avatar') || '')
const nickname = ref(uni.getStorageSync('nickname') || '')
const userId = ref(uni.getStorageSync('user_id') || '')
const phoneNumber = ref(uni.getStorageSync('phone_number') || '')
const inviteCode = ref(uni.getStorageSync('invite_code') || (uni.getStorageSync('user_info') || {}).invite_code || '')
const pointsBalance = ref(uni.getStorageSync('points_balance') || 0)
const stats = ref(uni.getStorageSync('user_stats') || {})
const loading = ref(false)
const error = ref('')
async function refresh() {
const token = uni.getStorageSync('token')
const phoneBound = !!uni.getStorageSync('phone_bound')
if (!token || !phoneBound) {
uni.showModal({
title: '提示',
content: '请先登录并绑定手机号',
confirmText: '去登录',
success: (res) => {
if (res.confirm) {
uni.navigateTo({ url: '/pages/login/index' })
}
}
})
return
}
const user_id = uni.getStorageSync('user_id')
loading.value = true
error.value = ''
try {
const s = await getUserStats(user_id)
stats.value = s || {}
uni.setStorageSync('user_stats', stats.value)
const b = await getPointsBalance(user_id)
const balance = b && b.balance !== undefined ? b.balance : b
pointsBalance.value = balance || 0
uni.setStorageSync('points_balance', pointsBalance.value)
} catch (e) {
error.value = e && (e.message || e.errMsg) || '数据获取失败'
} finally {
loading.value = false
}
}
function toPoints() {
uni.navigateTo({ url: '/pages/points/index' })
}
function toOrders(status) {
const s = status === 'completed' ? 'completed' : 'pending'
uni.navigateTo({ url: `/pages/orders/index?status=${s}` })
}
function toAddresses() {
uni.navigateTo({ url: '/pages/address/index' })
}
function toHelp() {
uni.navigateTo({ url: '/pages/help/index' })
}
onShow(() => {
avatar.value = uni.getStorageSync('avatar') || avatar.value
nickname.value = uni.getStorageSync('nickname') || nickname.value
userId.value = uni.getStorageSync('user_id') || userId.value
phoneNumber.value = uni.getStorageSync('phone_number') || phoneNumber.value
const ui = uni.getStorageSync('user_info') || {}
inviteCode.value = uni.getStorageSync('invite_code') || ui.invite_code || inviteCode.value
pointsBalance.value = uni.getStorageSync('points_balance') || pointsBalance.value
const s = uni.getStorageSync('user_stats')
if (s) stats.value = s
refresh()
})
onLoad(() => {
refresh()
})
</script>
<style scoped>
.wrap { padding: 40rpx }
.header { display: flex; align-items: center; margin-bottom: 24rpx }
.avatar { width: 120rpx; height: 120rpx; border-radius: 60rpx; background-color: #f5f5f5 }
.profile { margin-left: 20rpx; display: flex; flex-direction: column }
.nickname { font-size: 32rpx }
.userid { margin-top: 6rpx; font-size: 24rpx; color: #999 }
.info { display: flex; flex-direction: column; background: #fff; border-radius: 12rpx; padding: 20rpx; margin-bottom: 20rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04) }
.info-item { display: flex; justify-content: space-between; margin-bottom: 12rpx }
.info-label { color: #666; font-size: 24rpx }
.info-value { font-size: 28rpx }
.stats { display: flex; background: #fafafa; border-radius: 12rpx; padding: 20rpx; justify-content: space-between; margin-bottom: 20rpx }
.stat { flex: 1; align-items: center }
.stat-label { color: #666; font-size: 24rpx }
.stat-value { font-size: 36rpx; margin-top: 8rpx }
.orders { background: #fff; border-radius: 12rpx; padding: 20rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04); margin-bottom: 20rpx }
.orders-title { font-size: 30rpx; margin-bottom: 12rpx }
.orders-cats { display: flex; justify-content: space-between }
.orders-cat { flex: 1; background: #f7f7f7; border-radius: 12rpx; padding: 20rpx; margin-right: 12rpx }
.orders-cat:last-child { margin-right: 0 }
.orders-cat-title { font-size: 28rpx; text-align: center }
.addresses { background: #fff; border-radius: 12rpx; padding: 20rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04); margin-bottom: 20rpx }
.addresses-title { font-size: 30rpx; margin-bottom: 12rpx }
.addresses-entry { display: flex; justify-content: space-between; align-items: center; background: #f7f7f7; border-radius: 12rpx; padding: 20rpx }
.addresses-text { font-size: 28rpx }
.addresses-arrow { font-size: 28rpx; color: #999 }
.refresh { width: 100%; margin-top: 12rpx }
.error { color: #e43; margin-top: 20rpx }
</style>