269 lines
6.7 KiB
Vue
269 lines
6.7 KiB
Vue
<template>
|
||
<view class="page">
|
||
<view class="padding bg-white">
|
||
<!-- 头像 -->
|
||
<view class="flex justify-between align-center padding-tb solid-bottom" @click="chooseAvatar">
|
||
<view class="text-black">头像</view>
|
||
<view class="flex align-center">
|
||
<image class="avatar" :src="avatarPreview || getImageUrl(userInfo.avatar) || defaultAvatar" mode="aspectFill"></image>
|
||
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 昵称 -->
|
||
<view class="flex justify-between align-center padding-tb solid-bottom">
|
||
<view class="text-black label-text">昵称</view>
|
||
<view class="flex align-center flex-sub justify-end">
|
||
<input class="input-right" v-model="userInfo.nickName" placeholder="请输入昵称" />
|
||
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 电话号码 -->
|
||
<view class="flex justify-between align-center padding-tb solid-bottom">
|
||
<view class="text-black label-text">电话号码</view>
|
||
<view class="flex align-center flex-sub justify-end">
|
||
<input class="input-right" v-model="userInfo.phonenumber" placeholder="请输入电话号码" type="number" />
|
||
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 邮箱 -->
|
||
<view class="flex justify-between align-center padding-tb solid-bottom">
|
||
<view class="text-black label-text">邮箱</view>
|
||
<view class="flex align-center flex-sub justify-end">
|
||
<input class="input-right" v-model="userInfo.email" placeholder="请输入邮箱" />
|
||
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 性别 -->
|
||
<view class="flex justify-between align-center padding-tb solid-bottom">
|
||
<view class="text-black">性别</view>
|
||
<view class="flex align-center">
|
||
<view class="gender-switch">
|
||
<view
|
||
class="gender-item"
|
||
:class="{ 'gender-active': userInfo.sex === '0', 'gender-male': userInfo.sex === '0' }"
|
||
@click="userInfo.sex = '0'"
|
||
>
|
||
<text class="cuIcon-male"></text>
|
||
</view>
|
||
<view
|
||
class="gender-item"
|
||
:class="{ 'gender-active': userInfo.sex === '1', 'gender-female': userInfo.sex === '1' }"
|
||
@click="userInfo.sex = '1'"
|
||
>
|
||
<text class="cuIcon-female"></text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<button class="bg-blue round margin-top-xl" @click="handleSave" :loading="saving">保存</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted } from 'vue';
|
||
import { baseUrl, getToken } from '@/request/request.js';
|
||
import { getProfileDetail, updateProfile } from '@/request/three_one_api/info.js';
|
||
|
||
const saving = ref(false);
|
||
const defaultAvatar = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg';
|
||
const avatarPreview = ref(''); // 用于显示选择的图片临时预览
|
||
|
||
const userInfo = reactive({
|
||
avatar: '', // 保存相对路径,用于提交
|
||
nickName: '',
|
||
phonenumber: '',
|
||
email: '',
|
||
sex: '0' // '0'-男 '1'-女
|
||
});
|
||
|
||
// 获取图片完整URL(用于显示)
|
||
const getImageUrl = (path) => {
|
||
if (!path) return '';
|
||
if (path.startsWith('http')) return path;
|
||
return baseUrl + path;
|
||
};
|
||
|
||
// 页面加载时获取个人信息
|
||
onMounted(() => {
|
||
loadProfileDetail();
|
||
});
|
||
|
||
// 获取个人信息
|
||
const loadProfileDetail = async () => {
|
||
try {
|
||
uni.showLoading({ title: '加载中...' });
|
||
const res = await getProfileDetail();
|
||
uni.hideLoading();
|
||
if (res.code === 0 && res.data) {
|
||
userInfo.avatar = res.data.avatar || '';
|
||
userInfo.nickName = res.data.nickName || '';
|
||
userInfo.phonenumber = res.data.phonenumber || '';
|
||
userInfo.email = res.data.email || '';
|
||
userInfo.sex = res.data.sex || '0';
|
||
}
|
||
} catch (err) {
|
||
uni.hideLoading();
|
||
console.error('获取个人信息失败:', err);
|
||
}
|
||
};
|
||
|
||
// 选择头像
|
||
const chooseAvatar = () => {
|
||
uni.chooseImage({
|
||
count: 1,
|
||
sizeType: ['compressed'],
|
||
sourceType: ['album', 'camera'],
|
||
success: (res) => {
|
||
const tempFilePath = res.tempFilePaths[0];
|
||
// 显示临时预览
|
||
avatarPreview.value = tempFilePath;
|
||
// 上传获取链接
|
||
uploadAvatar(tempFilePath);
|
||
}
|
||
});
|
||
};
|
||
|
||
// 上传头像获取链接
|
||
const uploadAvatar = (filePath) => {
|
||
uni.showLoading({ title: '上传中...' });
|
||
|
||
uni.uploadFile({
|
||
url: baseUrl + '/frontend/attachment/upload',
|
||
filePath: filePath,
|
||
name: 'file',
|
||
header: {
|
||
'Authorization': getToken()
|
||
},
|
||
success: (uploadRes) => {
|
||
uni.hideLoading();
|
||
try {
|
||
const data = JSON.parse(uploadRes.data);
|
||
if (data.code === 0 && data.data) {
|
||
// 上传成功,保存相对路径(用于提交)
|
||
userInfo.avatar = data.data.url || data.data;
|
||
uni.showToast({ title: '上传成功', icon: 'success' });
|
||
} else {
|
||
avatarPreview.value = ''; // 上传失败,清除预览
|
||
uni.showToast({ title: data.msg || '上传失败', icon: 'none' });
|
||
}
|
||
} catch (e) {
|
||
avatarPreview.value = '';
|
||
uni.showToast({ title: '上传失败', icon: 'none' });
|
||
}
|
||
},
|
||
fail: () => {
|
||
uni.hideLoading();
|
||
avatarPreview.value = '';
|
||
uni.showToast({ title: '上传失败', icon: 'none' });
|
||
}
|
||
});
|
||
};
|
||
|
||
// 保存
|
||
const handleSave = async () => {
|
||
// 表单验证
|
||
if (!userInfo.nickName) {
|
||
uni.showToast({ title: '请输入昵称', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
saving.value = true;
|
||
try {
|
||
const params = {
|
||
nickName: userInfo.nickName,
|
||
phonenumber: userInfo.phonenumber,
|
||
email: userInfo.email,
|
||
sex: userInfo.sex,
|
||
avatar: userInfo.avatar // 提交相对路径
|
||
};
|
||
|
||
const res = await updateProfile(params);
|
||
if (res.code === 0) {
|
||
uni.showToast({ title: '保存成功', icon: 'success' });
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1500);
|
||
} else {
|
||
uni.showToast({ title: res.msg || '保存失败', icon: 'none' });
|
||
}
|
||
} catch (err) {
|
||
console.error('保存失败:', err);
|
||
uni.showToast({ title: '保存失败', icon: 'none' });
|
||
} finally {
|
||
saving.value = false;
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.page {
|
||
min-height: 100vh;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.avatar {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.label-text {
|
||
flex-shrink: 0;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.input-right {
|
||
text-align: right;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.padding-tb {
|
||
padding: 30rpx 0;
|
||
}
|
||
|
||
.gender-switch {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #f0f0f0;
|
||
border-radius: 40rpx;
|
||
padding: 4rpx;
|
||
}
|
||
|
||
.gender-item {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 32rpx;
|
||
color: #999;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.gender-active {
|
||
color: #fff;
|
||
}
|
||
|
||
.gender-male {
|
||
background: #2667E9;
|
||
}
|
||
|
||
.gender-female {
|
||
background: #ff6b81;
|
||
}
|
||
|
||
.line-blue {
|
||
border: 1rpx solid #2667E9;
|
||
color: #2667E9;
|
||
background: #fff;
|
||
}
|
||
</style>
|