Files
spring-festival-greetings/pages/mine/profile.vue
2026-01-30 17:56:14 +08:00

314 lines
6.7 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="profile-page" :style="{ paddingTop: navBarHeight + 'px' }">
<!-- Custom Navbar -->
<view
class="nav-bar"
:style="{
height: navBarHeight + 'px',
paddingTop: statusBarHeight + 'px',
}"
>
<view class="nav-left" @click="goBack">
<uni-icons type="left" size="24" color="#000" />
</view>
<text class="nav-title">个人信息</text>
</view>
<!-- Content -->
<view class="content">
<!-- Avatar Section -->
<view class="avatar-section">
<view class="avatar-wrapper" @click="handleAvatarClick">
<image
class="avatar"
:src="userInfo.avatarUrl || 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'"
mode="aspectFill"
/>
<view class="camera-badge">
<uni-icons type="camera-filled" size="16" color="#ff3b30" />
</view>
</view>
<text class="change-avatar-text">更换头像</text>
</view>
<!-- Info List -->
<view class="info-card">
<view class="info-item" @click="handleEditName">
<text class="label">名字 / 昵称</text>
<view class="value-box">
<text class="value">{{ userInfo.nickName || "微信用户" }}</text>
<uni-icons type="right" size="14" color="#ccc" />
</view>
</view>
<view class="info-item">
<text class="label">性别</text>
<view class="value-box">
<text class="value"></text>
<uni-icons type="right" size="14" color="#ccc" />
</view>
</view>
<view class="info-item" @click="handleEditManifesto">
<text class="label">新春宣言</text>
<view class="value-box">
<text class="value red-text">万事如意岁岁平安</text>
<uni-icons type="compose" size="16" color="#ccc" />
</view>
</view>
</view>
<!-- Account Binding -->
<view class="section-header">
<text class="section-title">账号绑定</text>
</view>
<view class="info-card">
<view class="info-item">
<text class="label">手机号</text>
<view class="value-box">
<text class="value">138 **** 8888</text>
</view>
</view>
<view class="info-item">
<text class="label">微信号</text>
<view class="value-box">
<text class="value">WX_CN_2026</text>
</view>
</view>
</view>
<!-- Trophy Decoration -->
<view class="trophy-decoration">
<uni-icons type="medal" size="60" color="#e0e0e0" />
</view>
</view>
<!-- Bottom Action Bar -->
<view class="bottom-bar safe-area-bottom">
<button class="save-btn" @click="handleSave">
<text>保存修改</text>
</button>
</view>
</view>
</template>
<script setup>
import { ref } from "vue";
import { storeToRefs } from "pinia";
import { getBavBarHeight, getStatusBarHeight as getStatus } from "@/utils/system";
import { useUserStore } from "@/stores/user";
const navBarHeight = getBavBarHeight();
const statusBarHeight = getStatus();
const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore);
const goBack = () => {
uni.navigateBack();
};
const handleAvatarClick = () => {
// Navigate to avatar page or open picker
uni.navigateTo({
url: "/pages/mine/avatar",
});
};
const handleEditName = () => {
uni.showToast({ title: "修改昵称功能开发中", icon: "none" });
};
const handleEditManifesto = () => {
uni.showToast({ title: "修改宣言功能开发中", icon: "none" });
};
const handleSave = () => {
uni.showLoading({ title: "保存中..." });
setTimeout(() => {
uni.hideLoading();
uni.showToast({ title: "保存成功", icon: "success" });
setTimeout(() => {
uni.navigateBack();
}, 1500);
}, 1000);
};
</script>
<style lang="scss" scoped>
.profile-page {
min-height: 100vh;
background-color: #fcfcfc;
box-sizing: border-box;
padding-bottom: 200rpx;
}
.nav-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: #fcfcfc;
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
.nav-left {
position: absolute;
left: 30rpx;
bottom: 0;
height: 44px;
display: flex;
align-items: center;
}
.nav-title {
font-size: 34rpx;
font-weight: 600;
color: #000;
}
}
.content {
padding: 30rpx;
}
/* Avatar Section */
.avatar-section {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 40rpx;
margin-bottom: 60rpx;
}
.avatar-wrapper {
position: relative;
width: 180rpx;
height: 180rpx;
background: #f8cb8c;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
border: 4rpx solid #fff;
box-shadow: 0 10rpx 30rpx rgba(248, 203, 140, 0.4);
}
.avatar {
width: 160rpx;
height: 160rpx;
border-radius: 36rpx;
}
.camera-badge {
position: absolute;
bottom: -10rpx;
right: -10rpx;
background: #fff;
width: 50rpx;
height: 50rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.1);
}
.change-avatar-text {
font-size: 26rpx;
color: #8a6d65;
}
/* Info List */
.info-card {
background: #fff;
border-radius: 30rpx;
padding: 0 30rpx;
margin-bottom: 40rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.02);
}
.info-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 110rpx;
border-bottom: 2rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
}
.label {
font-size: 30rpx;
color: #666;
}
.value-box {
display: flex;
align-items: center;
}
.value {
font-size: 30rpx;
color: #333;
margin-right: 10rpx;
font-weight: 500;
&.red-text {
color: #ff3b30;
}
}
/* Section Header */
.section-header {
padding: 0 10rpx;
margin-bottom: 20rpx;
}
.section-title {
font-size: 28rpx;
font-weight: bold;
color: #8a6d65;
}
/* Trophy Decoration */
.trophy-decoration {
display: flex;
justify-content: center;
margin-top: 60rpx;
opacity: 0.5;
}
/* Bottom Bar */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background: #fcfcfc;
padding: 20rpx 40rpx;
box-sizing: border-box;
z-index: 99;
}
.save-btn {
background: #d32f2f;
color: #fff;
border-radius: 50rpx;
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: bold;
border: none;
box-shadow: 0 10rpx 20rpx rgba(211, 47, 47, 0.2);
&:active {
opacity: 0.9;
}
}
</style>