refactor(uniapp): 重构"我的"页信息层级
This commit is contained in:
1 parent
9384c68662
commit
0f2752867c
2 files changed
+232
-185
No files matched your search
@@ -32,6 +32,8 @@
|
|||||||
"style" :
|
"style" :
|
||||||
{
|
{
|
||||||
"navigationBarTitleText": "我的",
|
"navigationBarTitleText": "我的",
|
||||||
|
"navigationBarBackgroundColor": "#fff3e6",
|
||||||
|
"backgroundColor": "#fff3e6",
|
||||||
"enablePullDownRefresh": true
|
"enablePullDownRefresh": true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,160 +1,140 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout>
|
<view class="mine-page">
|
||||||
<uv-navbar
|
<uv-navbar
|
||||||
:fixed="false"
|
:fixed="false"
|
||||||
:title="title"
|
title="我的"
|
||||||
left-arrow
|
bgColor="transparent"
|
||||||
@leftClick="$onClickLeft"
|
leftIcon=""
|
||||||
/>
|
/>
|
||||||
<view class="container mine-page">
|
|
||||||
<view class="mine-page__user-section">
|
|
||||||
<!-- user box begin -->
|
|
||||||
<view class="mine-user d-flex flex-column bg-white">
|
|
||||||
|
|
||||||
<view class="mine-user__header d-flex align-items-center">
|
<!-- 用户卡片 -->
|
||||||
<view class="mine-user__avatar rounded-circle">
|
<view class="mine-user">
|
||||||
<image :src="isLogin ? member.avatar ? member.avatar : '/static/images/mine/default.png' : '/static/images/mine/default.png'"></image>
|
<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>
|
||||||
<view class="mine-user__info d-flex flex-column flex-fill overflow-hidden">
|
<view class="mine-user__info">
|
||||||
<view v-if="isLogin"
|
<template v-if="isLogin">
|
||||||
class="font-size-lg font-weight-bold d-flex justify-content-start align-items-center"
|
<view class="mine-user__name">{{ member.nickname || '用户' }}</view>
|
||||||
@tap="serv({type:'pages',pages:'/pages/components/pages/mine/userinfo'})">
|
<view class="mine-user__hint">个人资料</view>
|
||||||
<view class="text-truncate">{{ member.nickname }}</view>
|
</template>
|
||||||
<view class="iconfont iconarrow-right line-height-100"></view>
|
<template v-else>
|
||||||
|
<view class="mine-user__name">点击登录</view>
|
||||||
|
<view class="mine-user__hint">登录后同步优惠券与积分</view>
|
||||||
|
</template>
|
||||||
</view>
|
</view>
|
||||||
<view v-else class="font-size-lg font-weight-bold" @tap="login">游客</view>
|
<uv-icon name="arrow-right" size="14" color="#C4B5A5" />
|
||||||
</view>
|
</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>
|
||||||
<!-- user grid begin -->
|
<view
|
||||||
<view class="mine-user__stats w-100 d-flex align-items-center just-content-center">
|
class="mine-user__stat"
|
||||||
<view class="mine-user__stat" @tap="serv({type:'pages',pages:'/pages/components/pages/coupons/coupons'})">
|
@tap="serv({ type: 'pages', pages: '/pages/components/pages/balance/bill?cate=1' })"
|
||||||
<view class="value font-size-extra-lg font-weight-bold text-color-base">
|
>
|
||||||
{{ isLogin ? member.couponCount : 0}}
|
<view class="mine-user__stat-value">{{ isLogin ? (member.integral || 0) : 0 }}</view>
|
||||||
</view>
|
<view class="mine-user__stat-label">积分</view>
|
||||||
<view class="font-size-sm text-color-assist">优惠券</view>
|
|
||||||
</view>
|
|
||||||
<view class="mine-user__stat" @tap="serv({type:'pages', pages: '/pages/components/pages/balance/bill?cate=1'})">
|
|
||||||
<view class="value font-size-extra-lg font-weight-bold text-color-base">
|
|
||||||
{{ isLogin ? member.integral : 0 }}
|
|
||||||
</view>
|
|
||||||
<view class="font-size-sm text-color-assist">积分</view>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="mine-user__stat">
|
<view class="mine-user__stat">
|
||||||
<view class="value font-size-extra-lg font-weight-bold text-color-base">
|
<view class="mine-user__stat-value">{{ isLogin ? (member.nowMoney || 0) : 0 }}</view>
|
||||||
{{ isLogin ? member.nowMoney : 0 }}
|
<view class="mine-user__stat-label">余额</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="font-size-sm text-color-assist">余额</view>
|
<view
|
||||||
</view>
|
class="mine-user__stat"
|
||||||
<view class="mine-user__stat" @tap="serv({type:'pages', pages: '/pages/components/pages/balance/bill?cate=0'})">
|
@tap="serv({ type: 'pages', pages: '/pages/components/pages/balance/bill?cate=0' })"
|
||||||
<view class="value font-size-extra-lg font-weight-bold text-color-base">
|
>
|
||||||
{{ isLogin ? member.sumMoney : 0 }}
|
<view class="mine-user__stat-value">{{ isLogin ? (member.sumMoney || 0) : 0 }}</view>
|
||||||
</view>
|
<view class="mine-user__stat-label">历史消费</view>
|
||||||
<view class="font-size-sm text-color-assist">历史消费</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- user grid end -->
|
|
||||||
</view>
|
</view>
|
||||||
<!-- user box end -->
|
|
||||||
|
|
||||||
|
<!-- 我的服务 -->
|
||||||
|
<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>
|
||||||
<!-- service box begin -->
|
|
||||||
<view class="mine-service">
|
|
||||||
<view class="mine-service__title font-size-lg text-color-base font-weight-bold">我的服务</view>
|
|
||||||
<view class="u-m-t-20">
|
|
||||||
<uv-cell-group>
|
|
||||||
<block v-for="(item, index) in services" :key='index'>
|
|
||||||
<uv-cell :title="item.name" v-if="item.type == 'contact'" :isLink="true">
|
|
||||||
<template #icon>
|
|
||||||
<image :src="item.image" class="mine-service__icon mr-1"></image>
|
|
||||||
</template>
|
|
||||||
</uv-cell>
|
|
||||||
<uv-cell :isLink="true" :title="item.name" v-else-if="item.type == 'call'" v-on:click="makePhoneCall(item.phone)">
|
|
||||||
<template #icon>
|
|
||||||
<image :src="item.image" class="mine-service__icon mr-1"></image>
|
|
||||||
</template>
|
|
||||||
</uv-cell>
|
|
||||||
<uv-cell :isLink="true" :title="item.name" v-else @tap="serv(item)">
|
|
||||||
<template #icon>
|
|
||||||
<image :src="item.image" class="mine-service__icon mr-1"></image>
|
|
||||||
</template>
|
|
||||||
</uv-cell>
|
|
||||||
</block>
|
|
||||||
</uv-cell-group>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</layout>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import { ref, computed } from 'vue'
|
||||||
ref,
|
|
||||||
computed
|
|
||||||
} from 'vue'
|
|
||||||
import { useMainStore } from '@/store/store'
|
import { useMainStore } from '@/store/store'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { onLoad,onShow} from '@dcloudio/uni-app'
|
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||||
import { formatDateTime,kmUnit } from '@/utils/util'
|
import { userGetUserInfo, mineService } from '@/api/user'
|
||||||
import {
|
|
||||||
userGetUserInfo,
|
|
||||||
mineService
|
|
||||||
} from '@/api/user'
|
|
||||||
const main = useMainStore()
|
|
||||||
const { member,isLogin } = storeToRefs(main)
|
|
||||||
|
|
||||||
const title = ref('个人中心')
|
const main = useMainStore()
|
||||||
|
const { member, isLogin } = storeToRefs(main)
|
||||||
const services = ref([])
|
const services = ref([])
|
||||||
|
|
||||||
const growthValue = computed(() => {
|
const avatarSrc = computed(() => {
|
||||||
if (!isLogin.value) return 0
|
if (isLogin.value && member.value?.avatar) return member.value.avatar
|
||||||
const {
|
return '/static/images/mine/default.png'
|
||||||
currentValue,
|
|
||||||
needValue
|
|
||||||
} = member.value
|
|
||||||
return currentValue / (currentValue + needValue) * 100
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getServices();
|
getServices()
|
||||||
})
|
})
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
getUserInfo();
|
getUserInfo()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const getUserInfo = async () => {
|
||||||
|
if (!isLogin.value) return
|
||||||
|
const data = await userGetUserInfo()
|
||||||
|
if (data) {
|
||||||
|
main.SET_MEMBER(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getUserInfo = async() => {
|
const getServices = async () => {
|
||||||
if (isLogin.value) {
|
const data = await mineService()
|
||||||
let data = await userGetUserInfo();
|
|
||||||
if (data) {
|
if (data) {
|
||||||
main.SET_MEMBER(data);
|
services.value = data
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const getServices = async() => {
|
|
||||||
let data = await mineService();
|
|
||||||
if (data) {
|
|
||||||
services.value = data;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const makePhoneCall = (phoneNumber) => {
|
const makePhoneCall = (phoneNumber) => {
|
||||||
uni.makePhoneCall({
|
uni.makePhoneCall({ phoneNumber })
|
||||||
phoneNumber: phoneNumber,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const login = () => {
|
const login = () => {
|
||||||
uni.navigateTo({
|
uni.navigateTo({ url: '/pages/components/pages/login/login' })
|
||||||
url: '/pages/components/pages/login/login'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const packages = () => {
|
|
||||||
if (!isLogin.value) {
|
|
||||||
login()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
uni.navigateTo({
|
|
||||||
url: '/pages/components/pages/packages/index'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const serv = (item) => {
|
const serv = (item) => {
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case 'pages':
|
case 'pages':
|
||||||
@@ -162,52 +142,45 @@ const serv = (item) => {
|
|||||||
login()
|
login()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uni.navigateTo({
|
uni.navigateTo({ url: item.pages })
|
||||||
url: item.pages
|
break
|
||||||
})
|
|
||||||
break;
|
|
||||||
case 'miniprogram':
|
case 'miniprogram':
|
||||||
uni.navigateToMiniProgram({
|
uni.navigateToMiniProgram({ appId: item.app_id })
|
||||||
appId: item.app_id
|
break
|
||||||
})
|
|
||||||
break;
|
|
||||||
case 'menu':
|
case 'menu':
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/components/pages/mine/service?id=' + item.id + '&name=' + item.name
|
url: '/pages/components/pages/mine/service?id=' + item.id + '&name=' + item.name
|
||||||
})
|
})
|
||||||
break;
|
break
|
||||||
case 'content':
|
case 'content':
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/components/pages/mine/content?id=' + item.id + '&name=' + item.name
|
url: '/pages/components/pages/mine/content?id=' + item.id + '&name=' + item.name
|
||||||
})
|
})
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onServiceTap = (item) => {
|
||||||
|
if (item.type === 'call') {
|
||||||
|
makePhoneCall(item.phone)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (item.type === 'contact') {
|
||||||
|
// 与原 uv-cell contact 项一致:仅展示,无额外跳转
|
||||||
|
return
|
||||||
|
}
|
||||||
|
serv(item)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
// 个人中心页局部 token(与 uni.scss 全局变量配合)
|
$bg-top: #fff3e6;
|
||||||
$mine-section-padding-x: $spacing-row-lg;
|
$bg-mid: #fff8f0;
|
||||||
$mine-user-box-radius: $border-radius-lg;
|
$bg-bottom: #ffffff;
|
||||||
$mine-user-box-margin-top: 70rpx;
|
$accent: #f28c38;
|
||||||
$mine-user-box-margin-bottom: $spacing-row-lg;
|
$text-main: #2b2b2b;
|
||||||
$mine-avatar-size: 160rpx;
|
$text-sub: #9a9590;
|
||||||
$mine-avatar-image-size: 140rpx;
|
$card-radius: 24rpx;
|
||||||
$mine-avatar-offset-top: -35rpx;
|
|
||||||
$mine-avatar-margin-x: 35rpx;
|
|
||||||
$mine-avatar-radius: 20rpx;
|
|
||||||
$mine-avatar-shadow: 0 0 20rpx rgba(0, 0, 0, 0.2);
|
|
||||||
$mine-stat-width: 25%;
|
|
||||||
$mine-stat-padding: $spacing-row-lg;
|
|
||||||
$mine-stat-value-gap: $spacing-row-base;
|
|
||||||
$mine-info-margin-top: $spacing-row-base;
|
|
||||||
$mine-service-padding-y: 32rpx;
|
|
||||||
$mine-service-padding-bottom: 10rpx;
|
|
||||||
$mine-service-icon-size: $img-size-sm;
|
|
||||||
$mine-service-title-gap: $spacing-row-base;
|
|
||||||
|
|
||||||
/* #ifdef H5 */
|
/* #ifdef H5 */
|
||||||
page {
|
page {
|
||||||
@@ -217,76 +190,148 @@ page {
|
|||||||
/* #endif */
|
/* #endif */
|
||||||
|
|
||||||
.mine-page {
|
.mine-page {
|
||||||
--mine-avatar-size: #{$mine-avatar-size};
|
min-height: 100vh;
|
||||||
--mine-avatar-image-size: #{$mine-avatar-image-size};
|
padding: 0 24rpx 40rpx;
|
||||||
--mine-service-icon-size: #{$mine-service-icon-size};
|
box-sizing: border-box;
|
||||||
|
background: linear-gradient(180deg, $bg-top 0%, $bg-mid 42%, $bg-bottom 100%);
|
||||||
&__user-section {
|
|
||||||
padding: 0 $mine-section-padding-x;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mine-user {
|
.mine-user {
|
||||||
position: relative;
|
margin-bottom: 24rpx;
|
||||||
margin-top: $mine-user-box-margin-top;
|
padding: 28rpx 24rpx 8rpx;
|
||||||
margin-bottom: $mine-user-box-margin-bottom;
|
border-radius: $card-radius;
|
||||||
border-radius: $mine-user-box-radius;
|
background: #fff;
|
||||||
box-shadow: $box-shadow;
|
box-shadow: 0 8rpx 24rpx rgba(180, 120, 60, 0.08);
|
||||||
|
|
||||||
&__info {
|
&__header {
|
||||||
margin-top: $mine-info-margin-top;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8rpx 8rpx 28rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__avatar {
|
&__avatar {
|
||||||
position: relative;
|
width: 112rpx;
|
||||||
display: flex;
|
height: 112rpx;
|
||||||
align-items: center;
|
margin-right: 24rpx;
|
||||||
justify-content: center;
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: var(--mine-avatar-size);
|
background: #fff3e6;
|
||||||
height: var(--mine-avatar-size);
|
border: 4rpx solid #fff3e6;
|
||||||
margin-top: $mine-avatar-offset-top;
|
|
||||||
margin-left: $mine-avatar-margin-x;
|
|
||||||
margin-right: $mine-avatar-margin-x;
|
|
||||||
border-radius: $mine-avatar-radius;
|
|
||||||
background-color: $text-color-white;
|
|
||||||
box-shadow: $mine-avatar-shadow;
|
|
||||||
|
|
||||||
image {
|
image {
|
||||||
width: var(--mine-avatar-image-size);
|
width: 100%;
|
||||||
height: var(--mine-avatar-image-size);
|
height: 100%;
|
||||||
border-radius: $border-radius-circle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__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 {
|
&__stat {
|
||||||
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: $mine-stat-width;
|
padding: 22rpx 8rpx;
|
||||||
padding: $mine-stat-padding;
|
position: relative;
|
||||||
|
|
||||||
.value {
|
&:not(:last-child)::after {
|
||||||
margin-bottom: $mine-stat-value-gap;
|
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 {
|
.mine-service {
|
||||||
width: 100%;
|
padding: 28rpx 8rpx 12rpx;
|
||||||
padding: $mine-service-padding-y $mine-section-padding-x $mine-service-padding-bottom;
|
border-radius: $card-radius;
|
||||||
background-color: $text-color-white;
|
background: #fff;
|
||||||
box-shadow: $box-shadow;
|
box-shadow: 0 8rpx 24rpx rgba(180, 120, 60, 0.08);
|
||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
margin-bottom: $mine-service-title-gap;
|
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 {
|
&__icon {
|
||||||
width: var(--mine-service-icon-size);
|
width: 44rpx;
|
||||||
height: var(--mine-service-icon-size);
|
height: 44rpx;
|
||||||
|
margin-right: 20rpx;
|
||||||
flex-shrink: 0;
|
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>
|
</style>
|
||||||
Reference in new issue
Block a user