JewelryMall/miniprogram/pages/mine/index.vue
2026-03-05 00:43:04 +08:00

308 lines
8.0 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="mine-page">
<!-- 自定义导航栏 -->
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="custom-navbar__content" :style="{ height: navBarHeight + 'px' }">
<text class="custom-navbar__title">我的</text>
</view>
</view>
<!-- 顶部用户卡片 -->
<view class="user-card" @click="handleUserCardClick">
<image class="user-card__avatar" :src="userStore.user?.avatar || '/static/logo.png'" mode="aspectFill" />
<view class="user-card__info">
<text class="user-card__name">{{ isLoggedIn ? (userStore.user?.nickname || '微信用户') : '点击注册/登录' }}</text>
<text v-if="isLoggedIn" class="user-card__id">UID: {{ userStore.user?.uid }}</text>
</view>
<text class="user-card__arrow"></text>
</view>
<!-- 我的订单 -->
<view class="order-entry" @click="navigateTo('/pages/order/list')">
<image class="order-entry__icon" src="/static/tab/me_s.png" mode="aspectFit" />
<text class="order-entry__text">我的订单 {{ orderCount }}</text>
<text class="order-entry__arrow"></text>
</view>
<!-- 功能菜单 -->
<view class="menu-group">
<view class="menu-item" @click="navigateTo('/pages/address/index')">
<image class="menu-item__icon" src="/static/ic_address.png" mode="aspectFit" />
<text class="menu-item__label">收货地址</text>
<text class="menu-item__arrow"></text>
</view>
<view class="menu-item" @click="showQrCode = true">
<image class="menu-item__icon" src="/static/ic_customer.png" mode="aspectFit" />
<text class="menu-item__label">联系客服</text>
<text class="menu-item__arrow"></text>
</view>
<view class="menu-item" @click="showAbout = true">
<image class="menu-item__icon" src="/static/ic_about.png" mode="aspectFit" />
<text class="menu-item__label">关于我们</text>
<text class="menu-item__arrow"></text>
</view>
<view class="menu-item" @click="showAgreement('user')">
<image class="menu-item__icon" src="/static/ic_agreement1.png" mode="aspectFit" />
<text class="menu-item__label">用户协议</text>
<text class="menu-item__arrow"></text>
</view>
<view class="menu-item" @click="showAgreement('privacy')">
<image class="menu-item__icon" src="/static/ic_agreement2.png" mode="aspectFit" />
<text class="menu-item__label">隐私协议</text>
<text class="menu-item__arrow"></text>
</view>
<view v-if="isLoggedIn" class="menu-item" @click="handleLogout">
<image class="menu-item__icon" src="/static/ic_loginout.png" mode="aspectFit" />
<text class="menu-item__label">退出登录</text>
<text class="menu-item__arrow"></text>
</view>
</view>
<!-- 客服二维码弹窗 -->
<CustomerServiceBtn v-if="showQrCode" mode="qrcode" @close="showQrCode = false" />
<!-- 关于我们弹窗 -->
<view class="modal-mask" v-if="showAbout" @click="showAbout = false">
<view class="modal-popup" @click.stop>
<text class="modal-popup__title">关于我们</text>
<text class="modal-popup__content">{{ aboutUsText }}</text>
<view class="modal-popup__close" @click="showAbout = false">关闭</view>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useUserStore } from '../../store/user'
import { getOrderList } from '../../api/order'
import { get } from '../../utils/request'
import CustomerServiceBtn from '../../components/CustomerServiceBtn.vue'
const userStore = useUserStore()
const showQrCode = ref(false)
const showAbout = ref(false)
const orderCount = ref(0)
const isLoggedIn = ref(false)
const aboutUsText = ref('珠宝商城 专注珠宝零售为您提供优质珠宝商品和贴心服务')
const statusBarHeight = ref(20)
const navBarHeight = ref(44)
try {
const sysInfo = uni.getSystemInfoSync()
statusBarHeight.value = sysInfo.statusBarHeight || 20
// #ifdef MP-WEIXIN
const menuBtn = uni.getMenuButtonBoundingClientRect()
navBarHeight.value = (menuBtn.top - (sysInfo.statusBarHeight || 20)) * 2 + menuBtn.height
// #endif
} catch { /* fallback */ }
function refreshData() {
const token = uni.getStorageSync('token')
isLoggedIn.value = !!token
if (token) {
userStore.fetchProfile()
getOrderList().then((data: any) => {
orderCount.value = Array.isArray(data) ? data.length : (data?.total || 0)
}).catch(() => {})
}
// 加载关于我们(无需登录)
get('/api/config/about_us').then((data: any) => {
if (data && typeof data === 'string') aboutUsText.value = data
}).catch(() => {})
}
onShow(() => {
refreshData()
})
function handleUserCardClick() {
if (!isLoggedIn.value) {
uni.navigateTo({ url: '/pages/login/index' })
}
}
function navigateTo(url: string) {
const token = uni.getStorageSync('token')
if (!token) {
uni.navigateTo({ url: '/pages/login/index' })
return
}
uni.navigateTo({ url })
}
function showAgreement(type: 'user' | 'privacy') {
uni.navigateTo({ url: `/pages/agreement/index?type=${type}` })
}
function handleLogout() {
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
userStore.logout()
isLoggedIn.value = false
orderCount.value = 0
uni.showToast({ title: '已退出登录', icon: 'success' })
setTimeout(() => {
uni.switchTab({ url: '/pages/index/index' })
}, 1000)
}
}
})
}
</script>
<style scoped>
.mine-page {
min-height: 100vh;
background: #f5f5f5;
}
.custom-navbar {
background: linear-gradient(to right, #FFCFDE, #FFA6C4);
}
.custom-navbar__content {
display: flex;
align-items: center;
justify-content: center;
}
.custom-navbar__title {
font-size: 34rpx;
font-weight: bold;
color: #333;
}
/* 用户卡片 */
.user-card {
display: flex;
align-items: center;
background: #fff;
margin: 0 24rpx;
padding: 32rpx;
border-radius: 16rpx;
}
.user-card__avatar {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
background: #f0f0f0;
flex-shrink: 0;
}
.user-card__info {
flex: 1;
margin-left: 24rpx;
}
.user-card__name {
font-size: 32rpx;
color: #333;
font-weight: bold;
}
.user-card__id {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
display: block;
}
.user-card__arrow {
font-size: 36rpx;
color: #ccc;
}
/* 我的订单入口 */
.order-entry {
display: flex;
align-items: center;
margin: 20rpx 24rpx 0;
padding: 24rpx 32rpx;
background: linear-gradient(135deg, #fce4ec, #f8bbd0);
border-radius: 16rpx;
}
.order-entry__icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.order-entry__text {
flex: 1;
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.order-entry__arrow {
font-size: 32rpx;
color: #999;
}
/* 功能菜单 */
.menu-group {
background: #fff;
margin: 20rpx 24rpx 0;
border-radius: 16rpx;
overflow: hidden;
}
.menu-item {
display: flex;
align-items: center;
padding: 30rpx 32rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.menu-item:last-child {
border-bottom: none;
}
.menu-item__icon {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
.menu-item__label {
flex: 1;
font-size: 28rpx;
color: #333;
}
.menu-item__arrow {
font-size: 32rpx;
color: #ccc;
}
/* 弹窗 */
.modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
.modal-popup {
background: #fff;
border-radius: 16rpx;
padding: 40rpx;
text-align: center;
width: 560rpx;
}
.modal-popup__title {
font-size: 32rpx;
color: #333;
font-weight: bold;
display: block;
margin-bottom: 20rpx;
}
.modal-popup__content {
font-size: 26rpx;
color: #666;
line-height: 44rpx;
display: block;
}
.modal-popup__close {
margin-top: 28rpx;
font-size: 28rpx;
color: #999;
}
</style>