This commit is contained in:
2025-09-05 17:35:26 +08:00
parent 23123f3f9a
commit 3cbbd87a77
14 changed files with 1594 additions and 1745 deletions
+84 -666
View File
@@ -136,64 +136,7 @@
</view>
</view>
<!-- 用户信息设置模态框 -->
<u-modal
:show="showUserInfoModal"
title="完善个人信息"
@cancel="cancelUserInfo"
:show-cancel-button="false"
:show-confirm-button="false"
:mask-close-able="true"
>
<view class="user-info-form" :class="{ 'form-animate': showUserInfoModal }">
<view class="form-item avatar-form-item">
<text class="form-label">选择头像</text>
<view class="avatar-selector">
<button
class="avatar-button"
open-type="chooseAvatar"
@chooseavatar="onChooseAvatar"
>
<view class="avatar-container">
<u-avatar
:src="tempUserInfo.avatarUrl || ''"
:text="tempUserInfo.nickName ? tempUserInfo.nickName.charAt(0) : '👤'"
size="100"
shape="circle"
bg-color="linear-gradient(135deg, #FF8A80, #FFB6C1)"
color="white"
font-size="36"
></u-avatar>
<view class="avatar-edit-overlay">
<view class="edit-icon-wrapper">
<text class="edit-icon">📷</text>
</view>
</view>
</view>
</button>
</view>
</view>
<view class="form-item">
<text class="form-label">昵称</text>
<input
type="nickname"
v-model="tempUserInfo.nickName"
placeholder="请输入昵称"
class="nickname-input"
/>
</view>
<!-- 自定义保存按钮 -->
<view class="custom-button-area">
<button class="custom-save-button" @click="saveUserInfo">
<view class="button-content">
<text class="button-text">保存信息</text>
</view>
<view class="button-shine"></view>
</button>
</view>
</view>
</u-modal>
</view>
</template>
@@ -201,6 +144,13 @@
import { reactive, ref, onMounted, computed } from 'vue'
import { uploadImage } from '@/http/api/common.js'
import { updateUserInfo } from '@/http/api/profile.js'
import {
getCurrentLoginStep,
isLoginCompleted,
checkAndResumeLogin,
saveWxLoginData,
clearTempLoginData
} from '@/utils/loginState.js'
export default {
name: 'ProfilePage',
@@ -213,12 +163,7 @@ export default {
const loginDays = ref(0)
// 用户信息设置模态框相关数据
const showUserInfoModal = ref(false)
const tempUserInfo = ref({
nickName: '',
avatarUrl: ''
})
@@ -249,11 +194,39 @@ export default {
}
const checkLogin = () => {
// 检查是否已登录
const savedUserInfo = uni.getStorageSync('userInfo')
if (savedUserInfo) {
userInfo.value = savedUserInfo
calculateLoginDays()
// 检查登录状态
console.log('Profile页面登录状态检查')
// 检查是否需要继续未完成的登录流程
const nextPage = checkAndResumeLogin()
if (nextPage) {
console.log('检测到未完成的登录流程,跳转到:', nextPage)
// 显示提示信息
uni.showToast({
title: '继续完成登录流程',
icon: 'none',
duration: 1500
})
setTimeout(() => {
uni.navigateTo({
url: nextPage
})
}, 1500)
return
}
// 检查是否已完成登录
if (isLoginCompleted()) {
const savedUserInfo = uni.getStorageSync('userInfo')
if (savedUserInfo) {
userInfo.value = savedUserInfo
calculateLoginDays()
// 清理临时登录数据
clearTempLoginData()
}
}
}
@@ -306,18 +279,29 @@ export default {
} catch (error) {
console.error('加载用户统计数据失败:', error)
// 设置默认值
petStats.petCount = 0
petStats.recordCount = 0
petStats.reminderCount = 0
familyStats.memberCount = 1
familyStats.sharedPets = 0
familyStats.activityCount = 0
adoptionStats.publishedCount = 0
adoptionStats.applicationCount = 0
// 重置为默认值
resetStatsToDefault()
}
}
// 重置统计数据为默认值
const resetStatsToDefault = () => {
Object.assign(petStats, {
petCount: 0,
recordCount: 0,
reminderCount: 0
})
Object.assign(familyStats, {
memberCount: 1,
sharedPets: 0,
activityCount: 0
})
Object.assign(adoptionStats, {
publishedCount: 0,
applicationCount: 0
})
}
const handleUserAction = () => {
if (userInfo.value.nickName) {
// 已登录,跳转到个人信息设置
@@ -334,27 +318,22 @@ export default {
success: (res) => {
console.log('登录成功', res)
// 登录成功后显示用户信息设置模态框
// 清空临时用户信息,准备用户输入
tempUserInfo.value = {
nickName: '',
avatarUrl: ''
}
// 显示用户信息设置模态框
showUserInfoModal.value = true
// 保存登录时间,但不设置用户信息(等用户完善后再设置)
uni.setStorageSync('loginDate', new Date().toISOString())
// 使用状态管理工具保存微信登录数据
saveWxLoginData(res)
calculateLoginDays()
uni.showToast({
title: '登录成功,请完善个人信息',
title: '登录成功',
icon: 'success',
duration: 2000
duration: 1500
})
// 跳转到手机号授权页面
setTimeout(() => {
uni.navigateTo({
url: '/pages/auth/phone-auth'
})
}, 1500)
},
fail: (err) => {
console.error('登录失败', err)
@@ -366,12 +345,16 @@ export default {
})
}
const navigateTo = (url) => {
// 统一的页面导航方法
const navigateTo = (url, options = {}) => {
const { fallbackMessage = '页面开发中' } = options
uni.navigateTo({
url,
fail: () => {
fail: (error) => {
console.warn('页面导航失败:', url, error)
uni.showToast({
title: '页面开发中',
title: fallbackMessage,
icon: 'none'
})
}
@@ -379,7 +362,9 @@ export default {
}
const navigateToFamily = () => {
navigateTo('/pages/profile/family')
navigateTo('/pages/profile/family', {
fallbackMessage: '家庭功能开发中'
})
}
const inviteFamily = () => {
@@ -437,214 +422,11 @@ export default {
// 头像选择处理
const onChooseAvatar = async (e) => {
try {
console.log('选择头像:', e.detail)
// 检查微信基础库版本兼容性
const systemInfo = uni.getSystemInfoSync()
const SDKVersion = systemInfo.SDKVersion
if (SDKVersion) {
const versionArray = SDKVersion.split('.').map(Number)
const requiredVersion = [2, 21, 2]
let isSupported = false
for (let i = 0; i < 3; i++) {
if (versionArray[i] > requiredVersion[i]) {
isSupported = true
break
} else if (versionArray[i] < requiredVersion[i]) {
break
}
}
if (!isSupported && versionArray.join('.') !== requiredVersion.join('.')) {
uni.showToast({
title: '微信版本过低,请升级后使用',
icon: 'none'
})
return
}
}
const { avatarUrl } = e.detail
// 检查是否获取到头像路径
if (!avatarUrl) {
uni.showToast({
title: '头像选择失败',
icon: 'none'
})
return
}
// 先显示临时头像
tempUserInfo.value.avatarUrl = avatarUrl
// 上传头像到服务器
const imageData = {
filePath: avatarUrl,
name: 'avatar',
formData: {
type: 'user_avatar'
}
}
const uploadResult = await uploadImage(imageData, {
custom: {
auth: true,
loading: true,
loadingText: '正在上传头像...'
}
})
// 更新为服务器返回的永久URL
if (uploadResult && uploadResult.url) {
tempUserInfo.value.avatarUrl = uploadResult.url
uni.showToast({
title: '头像上传成功',
icon: 'success',
duration: 1500
})
} else {
throw new Error('上传结果无效')
}
} catch (error) {
console.error('头像上传失败:', error)
// 根据错误类型显示不同提示
let errorMessage = '头像上传失败'
// 处理微信内容安全检测失败
if (error.errCode === 87014 || (error.message && error.message.includes('安全检测'))) {
errorMessage = '头像内容不符合规范,请重新选择'
}
// 处理网络错误
else if (error.errCode === -1 || (error.message && error.message.includes('网络'))) {
errorMessage = '网络异常,请稍后重试'
}
// 处理文件大小超限
else if (error.errCode === 1003 || (error.message && error.message.includes('文件大小'))) {
errorMessage = '头像文件过大,请选择较小的图片'
}
// 处理服务器错误
else if (error.statusCode >= 500) {
errorMessage = '服务器异常,请稍后重试'
}
// 处理权限错误
else if (error.statusCode === 401 || error.statusCode === 403) {
errorMessage = '权限不足,请重新登录'
}
uni.showToast({
title: errorMessage,
icon: 'none',
duration: 2000
})
// 重置头像为空
tempUserInfo.value.avatarUrl = ''
}
}
// 保存用户信息
const saveUserInfo = async () => {
try {
// 验证头像和昵称信息的完整性
if (!tempUserInfo.value.nickName || !tempUserInfo.value.nickName.trim()) {
uni.showToast({
title: '请输入昵称',
icon: 'none'
})
return
}
// 验证头像
if (!tempUserInfo.value.avatarUrl) {
uni.showToast({
title: '请选择头像',
icon: 'none'
})
return
}
console.log('开始保存用户信息:', tempUserInfo.value)
// 调用API同步到服务器
const updateResult = await updateUserInfo({
nickName: tempUserInfo.value.nickName.trim(),
avatarUrl: tempUserInfo.value.avatarUrl
}, {
custom: {
auth: true,
loading: true,
loadingText: '正在保存用户信息...'
}
})
console.log('服务器保存成功:', updateResult)
// 更新本地存储中的userInfo
userInfo.value = {
nickName: tempUserInfo.value.nickName.trim(),
avatarUrl: tempUserInfo.value.avatarUrl
}
uni.setStorageSync('userInfo', userInfo.value)
// 关闭模态框
showUserInfoModal.value = false
// 重置临时数据
tempUserInfo.value = {
nickName: '',
avatarUrl: ''
}
// 显示成功提示
uni.showToast({
title: '用户信息保存成功',
icon: 'success',
duration: 2000
})
// 更新页面显示状态
calculateLoginDays()
} catch (error) {
console.error('保存用户信息失败:', error)
// 根据错误类型显示不同提示
let errorMessage = '保存失败,请重试'
if (error.statusCode === 401 || error.statusCode === 403) {
errorMessage = '登录已过期,请重新登录'
} else if (error.statusCode >= 500) {
errorMessage = '服务器异常,请稍后重试'
} else if (error.message && error.message.includes('网络')) {
errorMessage = '网络异常,请检查网络连接'
} else if (error.message && error.message.includes('昵称')) {
errorMessage = '昵称不符合要求,请修改后重试'
}
uni.showToast({
title: errorMessage,
icon: 'none',
duration: 3000
})
}
}
// 取消用户信息设置
const cancelUserInfo = () => {
showUserInfoModal.value = false
// 重置临时数据
tempUserInfo.value = {
nickName: '',
avatarUrl: ''
}
}
@@ -666,14 +448,9 @@ export default {
showReminders,
refreshData,
formatNumber,
resetStatsToDefault,
onShow,
onPullDownRefresh,
// 用户信息设置模态框相关
showUserInfoModal,
tempUserInfo,
onChooseAvatar,
saveUserInfo,
cancelUserInfo
onPullDownRefresh
}
},
@@ -1310,245 +1087,11 @@ export default {
}
}
/* 用户信息设置模态框样式 */
.user-info-form {
padding: 40rpx 32rpx 20rpx 32rpx;
opacity: 0;
transform: translateY(20rpx);
transition: all 0.3s ease;
background: linear-gradient(135deg, rgba(255, 138, 128, 0.02), rgba(255, 182, 193, 0.02));
border-radius: 24rpx;
display: flex;
flex-direction: column;
align-items: center;
&.form-animate {
opacity: 1;
transform: translateY(0);
}
.form-item {
margin-bottom: 40rpx;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
&:last-child {
margin-bottom: 0;
}
.form-label {
display: block;
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
text-align: center;
}
}
.avatar-form-item {
margin-bottom: 44rpx;
}
.avatar-selector {
display: flex;
flex-direction: column;
align-items: center;
.avatar-button {
position: relative;
background: none;
border: none;
padding: 0;
margin-bottom: 24rpx;
border-radius: 50%;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&::after {
border: none;
}
&:hover {
transform: scale(1.05);
}
&:active {
transform: scale(0.95);
}
.avatar-container {
position: relative;
padding: 8rpx;
border-radius: 50%;
background: linear-gradient(135deg, rgba(255, 138, 128, 0.1), rgba(255, 182, 193, 0.1));
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.15);
.avatar-edit-overlay {
position: absolute;
bottom: 8rpx;
right: 8rpx;
.edit-icon-wrapper {
width: 40rpx;
height: 40rpx;
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.4);
border: 3rpx solid white;
.edit-icon {
font-size: 22rpx;
color: white;
}
}
}
}
}
.avatar-tips {
font-size: 28rpx;
color: #666;
background: linear-gradient(135deg, rgba(255, 138, 128, 0.08), rgba(255, 182, 193, 0.08));
padding: 12rpx 24rpx;
border-radius: 24rpx;
border: 1rpx solid rgba(255, 138, 128, 0.15);
box-shadow: 0 2rpx 8rpx rgba(255, 138, 128, 0.1);
}
}
.nickname-input {
width: 80%;
max-width: 400rpx;
height: 96rpx;
padding: 0 32rpx;
border: 2rpx solid rgba(255, 138, 128, 0.2);
border-radius: 24rpx;
font-size: 32rpx;
color: #333;
background: linear-gradient(135deg, rgba(255, 138, 128, 0.03), rgba(255, 182, 193, 0.03));
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
text-align: center;
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.08);
box-sizing: border-box;
&:focus {
border-color: #FF8A80;
background: white;
box-shadow: 0 0 0 8rpx rgba(255, 138, 128, 0.12), 0 8rpx 24rpx rgba(255, 138, 128, 0.15);
transform: translateY(-2rpx);
}
&::placeholder {
color: rgba(255, 138, 128, 0.6);
font-size: 30rpx;
}
}
}
/* 自定义保存按钮样式 */
.custom-button-area {
width: 100%;
margin-top: 24rpx;
display: flex;
justify-content: center;
padding: 0 32rpx 8rpx 32rpx;
.custom-save-button {
position: relative;
width: 80%;
max-width: 400rpx;
height: 72rpx;
border: none;
border-radius: 24rpx;
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
box-shadow: 0 6rpx 20rpx rgba(255, 138, 128, 0.3);
overflow: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
box-sizing: border-box;
&::after {
border: none;
}
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05));
opacity: 0;
transition: opacity 0.3s ease;
}
.button-content {
position: relative;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
gap: 8rpx;
.button-icon {
font-size: 24rpx;
color: white;
transition: transform 0.3s ease;
}
.button-text {
font-size: 28rpx;
font-weight: 600;
color: white;
letter-spacing: 0.5rpx;
}
}
.button-shine {
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.3), transparent);
transform: translateX(-100%) translateY(-100%) rotate(45deg);
transition: transform 0.6s ease;
}
&:hover {
background: linear-gradient(135deg, #FF7A70, #FFA6B1);
transform: translateY(-3rpx) scale(1.02);
box-shadow: 0 12rpx 32rpx rgba(255, 138, 128, 0.4);
&::before {
opacity: 1;
}
.button-content .button-icon {
transform: scale(1.1) rotate(5deg);
}
.button-shine {
transform: translateX(100%) translateY(100%) rotate(45deg);
}
}
&:active {
transform: translateY(-1rpx) scale(0.98);
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.3);
transition: all 0.1s ease;
}
}
}
/* 动画效果 */
@keyframes fadeIn {
@@ -1617,135 +1160,10 @@ export default {
/* 响应式设计 */
@media screen and (max-width: 750rpx) {
.user-info-form {
padding: 32rpx 24rpx 16rpx 24rpx;
.form-item {
margin-bottom: 32rpx;
.form-label {
font-size: 30rpx;
margin-bottom: 16rpx;
}
}
.avatar-form-item {
margin-bottom: 36rpx;
.avatar-selector {
.avatar-button {
.avatar-container {
padding: 6rpx;
}
}
.avatar-tips {
font-size: 26rpx;
padding: 10rpx 20rpx;
}
}
}
.nickname-input {
width: 90%;
height: 88rpx;
font-size: 30rpx;
padding: 0 28rpx;
box-sizing: border-box;
}
}
// 小屏幕自定义按钮优化
.custom-button-area {
margin-top: 20rpx;
padding: 0 24rpx 6rpx 24rpx;
.custom-save-button {
width: 90%;
height: 64rpx;
border-radius: 24rpx;
.button-content {
gap: 6rpx;
.button-icon {
font-size: 20rpx;
}
.button-text {
font-size: 24rpx;
}
}
}
}
}
@media screen and (min-width: 1200rpx) {
.user-info-form {
padding: 48rpx 40rpx 24rpx 40rpx;
max-width: 640rpx;
margin: 0 auto;
.form-item {
margin-bottom: 48rpx;
.form-label {
font-size: 36rpx;
margin-bottom: 24rpx;
}
}
.avatar-form-item {
margin-bottom: 52rpx;
.avatar-selector {
.avatar-button {
margin-bottom: 28rpx;
.avatar-container {
padding: 12rpx;
}
}
.avatar-tips {
font-size: 30rpx;
padding: 14rpx 28rpx;
}
}
}
.nickname-input {
width: 70%;
height: 104rpx;
font-size: 36rpx;
padding: 0 40rpx;
box-sizing: border-box;
}
}
// 大屏幕自定义按钮优化
.custom-button-area {
margin-top: 32rpx;
padding: 0 40rpx 12rpx 40rpx;
.custom-save-button {
width: 70%;
height: 80rpx;
border-radius: 24rpx;
.button-content {
gap: 10rpx;
.button-icon {
font-size: 28rpx;
}
.button-text {
font-size: 32rpx;
}
}
}
}
}
.profile-container > view:nth-child(1) { animation-delay: 0.1s; }
+253 -40
View File
@@ -1,5 +1,10 @@
<template>
<view class="user-info-container page-container-with-bg">
<!-- 模式提示(仅首次设置模式显示) -->
<view v-if="isSetupMode" class="mode-tip">
<text class="tip-text">{{ phoneSkipped ? '完善个人信息' : '欢迎!请完善您的个人信息' }}</text>
</view>
<!-- 头像设置卡片 -->
<view class="avatar-card">
<view class="card-header">
@@ -42,7 +47,6 @@
placeholder="请输入昵称"
border="none"
:custom-style="inputStyle"
@change="onNickNameChange"
></u-input>
</view>
</view>
@@ -126,8 +130,13 @@
@click="saveUserInfo"
:loading="saving"
>
{{ saving ? '保存中...' : '保存修改' }}
{{ saving ? '保存中...' : (isSetupMode ? '完成设置' : '保存修改') }}
</u-button>
<!-- 跳过按钮(仅首次设置模式显示) -->
<view v-if="isSetupMode" class="skip-section">
<text class="skip-button" @click="skipSetup">暂时跳过</text>
</view>
</view>
<!-- 性别选择器 -->
@@ -159,6 +168,11 @@
<script>
import { reactive, ref, onMounted, computed } from 'vue'
import { completeUserProfile } from '@/http/api/profile.js'
import {
saveProfileData,
STORAGE_KEYS
} from '@/utils/loginState.js'
export default {
name: 'UserInfoPage',
@@ -173,9 +187,13 @@ export default {
bio: '',
registerTime: ''
})
const loginDays = ref(0)
const saving = ref(false)
// 页面模式相关
const isSetupMode = ref(false) // 是否为首次设置模式
const phoneSkipped = ref(false) // 是否跳过了手机号授权
// 选择器状态
const showGender = ref(false)
@@ -183,11 +201,11 @@ export default {
const showRegion = ref(false)
const selectedDate = ref(Date.now())
// 选择器数据
// 选择器数据配置
const genderColumns = ref([
['男', '女', '保密']
])
const regionColumns = ref([
['北京市', '上海市', '广州市', '深圳市', '杭州市', '成都市', '武汉市', '西安市', '南京市', '重庆市']
])
@@ -212,28 +230,97 @@ export default {
// 生命周期
onMounted(() => {
initPageMode()
validateLoginState()
loadUserInfo()
})
// 验证登录状态
const validateLoginState = () => {
if (isSetupMode.value) {
// 首次设置模式需要验证登录状态
console.log('个人信息设置页面状态验证')
// 检查是否有有效的登录状态
const currentStep = uni.getStorageSync(STORAGE_KEYS.LOGIN_STEP)
if (!currentStep || currentStep === 'not_logged') {
console.warn('无效的登录状态,返回profile页面')
uni.reLaunch({
url: '/pages/profile/profile'
})
return
}
}
}
// 方法定义
const loadUserInfo = () => {
const initPageMode = () => {
// 获取页面参数
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const options = currentPage.options || {}
// 判断页面模式
isSetupMode.value = options.mode === 'setup'
phoneSkipped.value = options.phoneSkipped === 'true'
console.log('页面模式:', isSetupMode.value ? '首次设置' : '编辑模式')
console.log('手机号授权状态:', phoneSkipped.value ? '已跳过' : '已授权')
}
const loadUserInfo = async () => {
try {
const savedUserInfo = uni.getStorageSync('userInfo') || {}
Object.assign(userInfo, {
nickName: savedUserInfo.nickName || '',
avatarUrl: savedUserInfo.avatarUrl || '',
gender: savedUserInfo.gender || '',
birthday: savedUserInfo.birthday || '',
region: savedUserInfo.region || '',
bio: savedUserInfo.bio || '',
registerTime: savedUserInfo.registerTime || new Date().toISOString()
})
if (isSetupMode.value) {
// 首次设置模式:尝试获取微信用户信息
await loadWechatUserInfo()
} else {
// 编辑模式:加载现有用户信息
const savedUserInfo = uni.getStorageSync('userInfo') || {}
Object.assign(userInfo, {
nickName: savedUserInfo.nickName || '',
avatarUrl: savedUserInfo.avatarUrl || '',
gender: savedUserInfo.gender || '',
birthday: savedUserInfo.birthday || '',
region: savedUserInfo.region || '',
bio: savedUserInfo.bio || '',
registerTime: savedUserInfo.registerTime || new Date().toISOString()
})
}
calculateLoginDays()
} catch (error) {
console.error('加载用户信息失败:', error)
}
}
const loadWechatUserInfo = async () => {
try {
// 在首次设置模式下,尝试获取微信用户信息
console.log('尝试获取微信用户信息...')
// 检查是否有存储的微信用户信息
const wxUserInfo = uni.getStorageSync(STORAGE_KEYS.WX_USER_INFO)
if (wxUserInfo) {
userInfo.nickName = wxUserInfo.nickName || ''
userInfo.avatarUrl = wxUserInfo.avatarUrl || ''
console.log('从存储中获取微信用户信息:', wxUserInfo)
return
}
// 如果没有存储的信息,使用默认值
userInfo.nickName = ''
userInfo.avatarUrl = ''
userInfo.registerTime = new Date().toISOString()
console.log('使用默认用户信息')
} catch (error) {
console.error('获取微信用户信息失败:', error)
// 使用默认值
userInfo.nickName = ''
userInfo.avatarUrl = ''
userInfo.registerTime = new Date().toISOString()
}
}
const calculateLoginDays = () => {
const loginDate = uni.getStorageSync('loginDate')
@@ -267,43 +354,53 @@ export default {
})
}
// 选择器控制方法
const showGenderPicker = () => {
showGender.value = true
}
const showDatePicker = () => {
showDate.value = true
}
const showRegionPicker = () => {
showRegion.value = true
}
// 选择器确认方法
const onGenderConfirm = (e) => {
userInfo.gender = e.value[0]
showGender.value = false
}
const onDateConfirm = (e) => {
const date = new Date(e.value)
userInfo.birthday = date.toISOString().split('T')[0]
showDate.value = false
}
const onRegionConfirm = (e) => {
userInfo.region = e.value[0]
showRegion.value = false
}
// 输入框变化处理
const onNickNameChange = (value) => {
userInfo.nickName = value
}
const onBioChange = (value) => {
userInfo.bio = value
}
const saveUserInfo = async () => {
// 防重复提交
if (saving.value) {
return
}
if (!userInfo.nickName.trim()) {
uni.showToast({
title: '请输入昵称',
@@ -311,36 +408,112 @@ export default {
})
return
}
saving.value = true
try {
// 保存到本地存储
uni.setStorageSync('userInfo', userInfo)
// 模拟网络请求延迟
await new Promise(resolve => setTimeout(resolve, 1000))
if (isSetupMode.value) {
// 首次设置模式:调用完善用户信息API
await completeUserProfile({
nickName: userInfo.nickName.trim(),
avatarUrl: userInfo.avatarUrl,
gender: userInfo.gender,
birthday: userInfo.birthday,
region: userInfo.region,
bio: userInfo.bio
}, {
custom: {
loading: false // 使用页面自己的loading状态
}
})
// 使用状态管理工具保存用户信息并标记完成
saveProfileData(userInfo)
} else {
// 编辑模式:直接保存到本地存储
uni.setStorageSync(STORAGE_KEYS.USER_INFO, userInfo)
// 模拟网络请求延迟
await new Promise(resolve => setTimeout(resolve, 1000))
}
uni.showToast({
title: '保存成功',
icon: 'success'
})
// 返回上一页
// 根据模式决定跳转逻辑
setTimeout(() => {
uni.navigateBack()
if (isSetupMode.value) {
// 首次设置完成后跳转到profile页面
uni.reLaunch({
url: '/pages/profile/profile'
})
} else {
// 编辑模式返回上一页
uni.navigateBack()
}
}, 1500)
} catch (error) {
console.error('保存用户信息失败:', error)
// 根据错误类型显示不同的提示信息
let errorMessage = '保存失败,请重试'
if (error.message) {
if (error.message.includes('网络')) {
errorMessage = '网络连接异常,请检查网络后重试'
} else if (error.statusCode === 401 || error.statusCode === 403) {
errorMessage = '登录已过期,请重新登录'
} else if (error.statusCode >= 500) {
errorMessage = '服务器异常,请稍后重试'
} else if (error.message.includes('昵称')) {
errorMessage = '昵称格式不正确,请修改后重试'
} else {
errorMessage = error.message
}
}
uni.showToast({
title: '保存失败',
icon: 'none'
title: errorMessage,
icon: 'none',
duration: 3000
})
} finally {
saving.value = false
}
}
const skipSetup = () => {
if (isSetupMode.value) {
uni.showModal({
title: '确认跳过',
content: '跳过个人信息设置,您可以稍后在个人中心完善信息',
success: (res) => {
if (res.confirm) {
// 设置默认用户信息
const defaultUserInfo = {
nickName: '用户' + Date.now().toString().slice(-6),
avatarUrl: '',
gender: '',
birthday: '',
region: '',
bio: '',
registerTime: new Date().toISOString()
}
// 使用状态管理工具保存默认用户信息
saveProfileData(defaultUserInfo)
// 跳转到profile页面
uni.reLaunch({
url: '/pages/profile/profile'
})
}
}
})
}
}
const formatDate = (dateString) => {
if (!dateString) return '未设置'
@@ -371,7 +544,12 @@ export default {
onNickNameChange,
onBioChange,
saveUserInfo,
formatDate
formatDate,
// 新增的模式相关变量和方法
isSetupMode,
phoneSkipped,
skipSetup,
validateLoginState
}
}
}
@@ -384,6 +562,25 @@ export default {
padding-bottom: 40rpx;
}
/* 模式提示 */
.mode-tip {
margin: 20rpx 30rpx;
padding: 24rpx;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(20rpx);
border-radius: 24rpx;
text-align: center;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
border: 1rpx solid rgba(255, 255, 255, 0.3);
.tip-text {
font-size: 32rpx;
font-weight: 600;
color: #333333;
line-height: 1.4;
}
}
/* 通用卡片样式 */
.avatar-card,
.info-card,
@@ -538,6 +735,22 @@ export default {
/* 保存按钮 */
.save-section {
margin: 40rpx 30rpx 0 30rpx;
.skip-section {
margin-top: 24rpx;
text-align: center;
.skip-button {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
text-decoration: underline;
padding: 12rpx 24rpx;
&:active {
opacity: 0.7;
}
}
}
}
/* 响应式设计 */