mahjong_group/pages/me/edit-info.vue
2025-09-10 13:54:09 +08:00

408 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="content column">
<view class="header">
<image src="/static/back.png" class="back-icon" @click="goBack()" mode=""></image>
<text class="header-title">修改信息</text>
<view class="header-spacer"></view>
</view>
<view class="form-container">
<view class="form-row">
<text class="form-label">我的UID</text>
<text class="form-value">{{ user.id }}</text>
</view>
<view class="divider"></view>
<view class="form-row avatar-row">
<text class="form-label">我的头像</text>
<button class="avatar-wrapper" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<image :src="user.avatarImage" class="avatar-image" mode="">
</image>
</button>
</view>
<view class="divider"></view>
<view class="form-row">
<text class="form-label">我的昵称</text>
<input type="nickname" v-model="user.nickName" class="form-input" />
</view>
<view class="divider"></view>
<view class="form-row">
<text class="form-label">我的年龄</text>
<text class="form-value">{{ calculatedAge }}岁</text>
</view>
<view class="divider"></view>
<view class="form-row">
<text class="form-label">我的性别</text>
<picker mode="selector" :value="genderIndex" :range="GENDER_OPTIONS" @change="onGenderChange">
<view class="picker-text">
{{ currentGender }}
</view>
</picker>
</view>
<view class="divider"></view>
<view class="form-row">
<text class="form-label">我的生日</text>
<picker mode="date" :value="user.birthday" @change="onBirthdayChange">
<view class="picker-text">
{{ user.birthday || '请选择生日' }}
</view>
</picker>
</view>
<view class="divider"></view>
</view>
<!-- 保存按钮 -->
<view class="save-button-container">
<button class="save-button" @click="saveUserInfo" :disabled="isSaving">
{{ isSaving ? '保存中...' : '保存修改' }}
</button>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { userInfo, updateUserInfo } from '@/common/server/user'
// 常量配置
const GENDER_OPTIONS = ['男', '女']
// 响应式数据
const genderIndex = ref(0)
const isSaving = ref(false)
// 用户信息
const user = ref({
avatarImage: userInfo.value.avatarImage || '',
nickName: userInfo.value.nickName || '',
id: userInfo.value.id || '',
sex: userInfo.value.sex == 1 ? '男' : '女',
birthday: userInfo.value.birthday ?? "1990-01-01"
})
// 计算属性
const currentGender = computed(() => GENDER_OPTIONS[genderIndex.value])
// 根据生日计算年龄
const calculatedAge = computed(() => {
if (!user.value.birthday) return 0
const today = new Date()
const birthDate = new Date(user.value.birthday)
let age = today.getFullYear() - birthDate.getFullYear()
const monthDiff = today.getMonth() - birthDate.getMonth()
// 如果还没到生日年龄减1
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
age--
}
return age
})
// 初始化picker索引
const initializePickerIndexes = () => {
// 设置性别索引
genderIndex.value = userInfo.value.sex === '女' ? 1 : 0
}
onMounted(() => {
console.log("userInfo", userInfo.value)
initializePickerIndexes()
})
// 方法
const goBack = () => {
uni.navigateBack({ delta: 1 })
}
/**
* 选择头像
*/
const onChooseAvatar = (e) => {
const { avatarUrl } = e?.detail || {}
console.log("avatarUrl", avatarUrl);
if (avatarUrl) {
convertToBase64(avatarUrl)
}
}
/**
* 性别选择变化
*/
const onGenderChange = (e) => {
const selectedIndex = e.detail.value
genderIndex.value = selectedIndex
user.value.sex = GENDER_OPTIONS[selectedIndex]
}
/**
* 生日选择变化
*/
const onBirthdayChange = (e) => {
user.value.birthday = e.detail.value
}
/**
* 将图片转换为Base64
*/
const convertToBase64 = (filePath) => {
if (!filePath) {
showErrorToast('图片路径无效')
return
}
uni.getFileSystemManager().readFile({
filePath,
encoding: "base64",
success: (res) => {
user.value.avatarImage = `data:image/png;base64,${res.data}`
},
fail: (err) => {
console.error("读取文件失败:", err)
showErrorToast("图片处理失败")
},
})
}
/**
* 保存用户信息
*/
const saveUserInfo = async () => {
if (isSaving.value) return
// 验证必填字段
if (!user.value.nickName.trim()) {
showErrorToast('请输入昵称')
return
}
if (!user.value.birthday) {
showErrorToast('请选择生日')
return
}
isSaving.value = true
try {
// 准备保存的数据
const saveData = {
avatarImage: user.value.avatarImage,
nickName: user.value.nickName.trim(),
sex: user.value.sex === '男' ? 1 : 2,
birthday: user.value.birthday,
}
console.log('保存用户信息:', saveData)
// 这里应该调用实际的API保存数据
// await updateUserInfo(saveData)
//async (nickName, avatar, sex, birthday)
await updateUserInfo(user.value.nickName.trim(), user.value.avatarImage,
user.value.sex === '男' ? 1 : 2,
user.value.birthday
);
// 模拟API调用延迟
// await new Promise(resolve => setTimeout(resolve, 1000))
// 更新全局用户信息
// Object.assign(userInfo.value, saveData)
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
})
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack({ delta: 1 })
}, 1500)
} catch (error) {
console.error('保存失败:', error)
showErrorToast('保存失败,请重试')
} finally {
isSaving.value = false
}
}
/**
* 显示错误提示
*/
const showErrorToast = (message) => {
uni.showToast({
title: message,
icon: "none",
duration: 2000
})
}
</script>
<style lang="scss">
// 变量定义
$primary-color: #333;
$border-color: antiquewhite;
$font-size-normal: 26rpx;
$font-size-title: 30rpx;
$avatar-size: 70rpx;
$border-radius: 50%;
$container-width: 90%;
$header-margin-top: 100rpx;
$form-margin-top: 80rpx;
$row-margin-top: 40rpx;
$divider-margin-top: 20rpx;
.content {
width: 100%;
height: 100vh;
}
// 头部样式
.header {
width: $container-width;
margin: $header-margin-top auto 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.back-icon {
width: 40rpx;
height: 40rpx;
}
.header-title {
font-size: $font-size-title;
}
.header-spacer {
width: 40rpx;
}
// 表单容器样式
.form-container {
width: $container-width;
margin: $form-margin-top auto 0;
}
// 表单行样式
.form-row {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin-top: $row-margin-top;
font-size: $font-size-normal;
&.avatar-row {
margin-top: $divider-margin-top;
}
}
.form-label {
font-size: $font-size-normal;
}
.form-value {
font-size: $font-size-normal;
}
.form-input {
text-align: right;
font-size: $font-size-normal;
}
// 分割线样式
.divider {
width: 100%;
height: 1rpx;
background-color: $border-color;
margin-top: $divider-margin-top;
}
// 头像相关样式
.avatar-wrapper {
margin: 0;
float: right;
border-radius: 128rpx;
overflow: hidden;
border: 0;
background-color: transparent;
padding: 0;
line-height: normal;
&::after {
border: none;
}
.avatar {
width: 170rpx;
height: 160rpx;
border-radius: $border-radius;
}
}
.avatar-image {
width: $avatar-size;
height: $avatar-size;
background-color: aquamarine;
border-radius: $border-radius;
}
// Picker样式
.picker-text {
display: flex;
align-items: center;
color: $primary-color;
font-size: $font-size-normal;
}
// 保存按钮样式
.save-button-container {
width: $container-width;
margin: 60rpx auto 0;
padding-bottom: 40rpx;
}
.save-button {
width: 100%;
height: 80rpx;
background: linear-gradient(135deg, #F36903 0%, #E55A00 100%);
color: white;
border: none;
border-radius: 40rpx;
font-size: 32rpx;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 20rpx rgba(243, 105, 3, 0.3);
transition: all 0.3s ease;
&:active {
transform: translateY(2rpx);
box-shadow: 0 8rpx 20rpx rgba(243, 105, 3, 0.3);
}
&:disabled {
background: #ccc;
box-shadow: none;
transform: none;
}
}
</style>