Files
yshop-drink/yshop-drink-uniapp-vue3/pages/mine/mine.vue
T

338 lines
7.3 KiB
Vue

<template>
<view class="mine-page">
<uv-navbar
:fixed="false"
title="我的"
bgColor="transparent"
leftIcon=""
/>
<!-- 用户卡片 -->
<view class="mine-user">
<view
class="mine-user__header"
@tap="isLogin ? serv({ type: 'pages', pages: '/pages/components/pages/mine/userinfo' }) : login()"
>
<view class="mine-user__avatar">
<image
:src="avatarSrc"
mode="aspectFill"
/>
</view>
<view class="mine-user__info">
<template v-if="isLogin">
<view class="mine-user__name">{{ member.nickname || '用户' }}</view>
<view class="mine-user__hint">个人资料</view>
</template>
<template v-else>
<view class="mine-user__name">点击登录</view>
<view class="mine-user__hint">登录后同步优惠券与积分</view>
</template>
</view>
<uv-icon name="arrow-right" size="14" color="#C4B5A5" />
</view>
<view class="mine-user__stats">
<view
class="mine-user__stat"
@tap="serv({ type: 'pages', pages: '/pages/components/pages/coupons/coupons' })"
>
<view class="mine-user__stat-value">{{ isLogin ? (member.couponCount || 0) : 0 }}</view>
<view class="mine-user__stat-label">优惠券</view>
</view>
<view
class="mine-user__stat"
@tap="serv({ type: 'pages', pages: '/pages/components/pages/balance/bill?cate=1' })"
>
<view class="mine-user__stat-value">{{ isLogin ? (member.integral || 0) : 0 }}</view>
<view class="mine-user__stat-label">积分</view>
</view>
<view class="mine-user__stat">
<view class="mine-user__stat-value">{{ isLogin ? (member.nowMoney || 0) : 0 }}</view>
<view class="mine-user__stat-label">余额</view>
</view>
<view
class="mine-user__stat"
@tap="serv({ type: 'pages', pages: '/pages/components/pages/balance/bill?cate=0' })"
>
<view class="mine-user__stat-value">{{ isLogin ? (member.sumMoney || 0) : 0 }}</view>
<view class="mine-user__stat-label">历史消费</view>
</view>
</view>
</view>
<!-- 我的服务 -->
<view class="mine-service" v-if="services.length">
<view class="mine-service__title">我的服务</view>
<view class="mine-service__list">
<view
v-for="(item, index) in services"
:key="index"
class="mine-service__item"
@tap="onServiceTap(item)"
>
<image
v-if="item.image"
:src="item.image"
class="mine-service__icon"
mode="aspectFit"
/>
<view v-else class="mine-service__icon mine-service__icon--placeholder">
<uv-icon name="setting" size="18" color="#F28C38" />
</view>
<text class="mine-service__name">{{ item.name }}</text>
<uv-icon name="arrow-right" size="12" color="#C4B5A5" />
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { userGetUserInfo, mineService } from '@/api/user'
const main = useMainStore()
const { member, isLogin } = storeToRefs(main)
const services = ref([])
const avatarSrc = computed(() => {
if (isLogin.value && member.value?.avatar) return member.value.avatar
return '/static/images/mine/default.png'
})
onLoad(() => {
getServices()
})
onShow(() => {
getUserInfo()
})
const getUserInfo = async () => {
if (!isLogin.value) return
const data = await userGetUserInfo()
if (data) {
main.SET_MEMBER(data)
}
}
const getServices = async () => {
const data = await mineService()
if (data) {
services.value = data
}
}
const makePhoneCall = (phoneNumber) => {
uni.makePhoneCall({ phoneNumber })
}
const login = () => {
uni.navigateTo({ url: '/pages/components/pages/login/login' })
}
const serv = (item) => {
switch (item.type) {
case 'pages':
if (!isLogin.value) {
login()
return
}
uni.navigateTo({ url: item.pages })
break
case 'miniprogram':
uni.navigateToMiniProgram({ appId: item.app_id })
break
case 'menu':
uni.navigateTo({
url: '/pages/components/pages/mine/service?id=' + item.id + '&name=' + item.name
})
break
case 'content':
uni.navigateTo({
url: '/pages/components/pages/mine/content?id=' + item.id + '&name=' + item.name
})
break
}
}
const onServiceTap = (item) => {
if (item.type === 'call') {
makePhoneCall(item.phone)
return
}
if (item.type === 'contact') {
// 与原 uv-cell contact 项一致:仅展示,无额外跳转
return
}
serv(item)
}
</script>
<style lang="scss" scoped>
$bg-top: #fff3e6;
$bg-mid: #fff8f0;
$bg-bottom: #ffffff;
$accent: #f28c38;
$text-main: #2b2b2b;
$text-sub: #9a9590;
$card-radius: 24rpx;
/* #ifdef H5 */
page {
height: auto;
min-height: 100%;
}
/* #endif */
.mine-page {
min-height: 100vh;
padding: 0 24rpx 40rpx;
box-sizing: border-box;
background: linear-gradient(180deg, $bg-top 0%, $bg-mid 42%, $bg-bottom 100%);
}
.mine-user {
margin-bottom: 24rpx;
padding: 28rpx 24rpx 8rpx;
border-radius: $card-radius;
background: #fff;
box-shadow: 0 8rpx 24rpx rgba(180, 120, 60, 0.08);
&__header {
display: flex;
align-items: center;
padding: 8rpx 8rpx 28rpx;
}
&__avatar {
width: 112rpx;
height: 112rpx;
margin-right: 24rpx;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background: #fff3e6;
border: 4rpx solid #fff3e6;
image {
width: 100%;
height: 100%;
}
}
&__info {
flex: 1;
min-width: 0;
}
&__name {
font-size: 34rpx;
font-weight: 700;
color: $text-main;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__hint {
margin-top: 8rpx;
font-size: 24rpx;
color: $text-sub;
}
&__stats {
display: flex;
align-items: stretch;
margin: 0 4rpx 16rpx;
padding: 8rpx 0;
border-radius: 20rpx;
background: #fffaf4;
}
&__stat {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 22rpx 8rpx;
position: relative;
&:not(:last-child)::after {
content: '';
position: absolute;
right: 0;
top: 28%;
bottom: 28%;
width: 1rpx;
background: #f0e4d6;
}
}
&__stat-value {
font-size: 34rpx;
font-weight: 700;
color: $accent;
line-height: 1.2;
}
&__stat-label {
margin-top: 10rpx;
font-size: 22rpx;
color: $text-sub;
}
}
.mine-service {
padding: 28rpx 8rpx 12rpx;
border-radius: $card-radius;
background: #fff;
box-shadow: 0 8rpx 24rpx rgba(180, 120, 60, 0.08);
&__title {
padding: 0 20rpx 8rpx;
font-size: 30rpx;
font-weight: 700;
color: $text-main;
}
&__item {
display: flex;
align-items: center;
padding: 28rpx 20rpx;
border-bottom: 1rpx solid #f3ebe3;
&:last-child {
border-bottom: none;
}
}
&__icon {
width: 44rpx;
height: 44rpx;
margin-right: 20rpx;
flex-shrink: 0;
&--placeholder {
display: flex;
align-items: center;
justify-content: center;
border-radius: 12rpx;
background: #fff3e6;
}
}
&__name {
flex: 1;
min-width: 0;
font-size: 28rpx;
color: $text-main;
}
}
</style>