图书馆小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

252 lines
5.8 KiB

<template>
<view class="user-info-page">
<view class="user-info-section">
<!-- 点击获取头像 -->
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" class="avatar-btn">
<image v-if="avatarUrl" :src="avatarUrl" class="avatar-img"></image>
<image v-else src="@/static/images/logo.jpg" class="avatar-img"></image>
<text class="tip-text">点击更换头像</text>
</button>
</view>
<!-- 昵称 -->
<view class="form-item">
<text class="label">昵称</text>
<input
class="input"
type="nickname"
v-model="nickname"
placeholder="请输入昵称"
/>
<uni-icons type="right" size="18" color="#ccc"></uni-icons>
</view>
<!-- 保存按钮 -->
<view class="save-box">
<button class="save-btn" @click="saveUserInfo">保存修改</button>
</view>
</view>
</template>
<script>
import config from '@/utils/config'
import { FetchBindRead } from '@/api/user';
const USER_KEY = 'user-info';
export default {
data() {
return {
nickname: '',
avatarUrl: '', // 仅存放 base64,用于显示
imgId: '', // 仅用于提交后端
saving: false // 防重复提交
};
},
onLoad() {
this.loadUserInfo();
},
methods:{
// 加载用户信息
async loadUserInfo() {
const userInfo = uni.getStorageSync(USER_KEY) || {};
this.nickname = userInfo.nickname || '';
const avatarId = userInfo.avatarId || '';
this.imgId = avatarId;
if (avatarId) {
try {
uni.showLoading({ title: '加载头像中...' });
const url = `${config.baseUrl}/api/fileRelevant/getImg?imgType=5&imgId=${avatarId}`;
this.avatarUrl = await this.urlToBase64(url);
} catch (err) {
console.error('头像加载失败', err);
this.avatarUrl = '';
} finally {
uni.hideLoading();
}
} else {
this.avatarUrl = '';
}
},
// 选择头像 + 上传 + 转base64预览
async onChooseAvatar(e) {
const tempFilePath = e.detail.avatarUrl;
uni.showLoading({ title: '上传中...' });
try {
// 上传头像
const uploadRes = await new Promise((resolve, reject) => {
uni.uploadFile({
url: config.baseUrl + '/api/fileRelevant/uploadWxAvatarImg',
filePath: tempFilePath,
name: 'file',
success: resolve,
fail: reject
});
});
const resData = JSON.parse(uploadRes.data);
const imgId = resData.data;
this.imgId = imgId;
// 转base64显示
const url = `${config.baseUrl}/api/fileRelevant/getImg?imgType=5&imgId=${imgId}`;
this.avatarUrl = await this.urlToBase64(url);
uni.showToast({ title: '头像上传成功', icon: 'success' });
} catch (err) {
console.error(err);
uni.showToast({ title: '头像上传失败', icon: 'none' });
} finally {
uni.hideLoading();
}
},
// 最简稳定版:图片链接转base64
urlToBase64(url) {
return new Promise((resolve, reject) => {
uni.request({
url,
method: 'GET',
responseType: 'arraybuffer',
success: (res) => {
try {
const base64 = uni.arrayBufferToBase64(res.data);
resolve(`data:image/jpeg;base64,${base64}`);
} catch (e) {
reject(e);
}
},
fail: reject
});
});
},
// 保存(防重复提交 + 同步缓存)
async saveUserInfo() {
if (this.saving) return;
if (!this.nickname.trim()) {
uni.showToast({ title: '请输入昵称', icon: 'none' });
return;
}
this.saving = true;
uni.showLoading({ title: '保存中...' });
try {
const openId = uni.getStorageSync('wx_login_code') || '';
const params = {
avatar: this.imgId,
libcode: config.LIB_CODE,
nickname: this.nickname,
openid: openId
};
await FetchBindRead(params);
// 保存到缓存
uni.setStorageSync(USER_KEY, {
nickname: this.nickname,
avatarId: this.imgId
});
uni.showToast({ title: '保存成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
} catch (error) {
console.error(error);
uni.showToast({ title: '保存失败', icon: 'none' });
} finally {
uni.hideLoading();
this.saving = false;
}
}
}
};
</script>
<style lang="scss" scoped>
.user-info-page {
background-color: #f5f5f5;
min-height: 100vh;
padding: 20rpx;
box-sizing: border-box;
}
.user-info-section {
background: #fff;
padding: 40rpx 0;
border-radius: 12rpx;
margin-bottom: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.avatar-btn {
background: transparent;
display: flex;
flex-direction: column;
align-items: center;
&::after {
border: none;
}
}
.avatar-img {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
object-fit: cover;
margin-bottom: 10rpx;
}
.tip-text {
font-size: 26rpx;
color: #999;
}
.form-item {
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;
height: 88rpx;
border-radius: 12rpx;
margin-bottom: 20rpx;
}
.label {
font-size: 30rpx;
color: #333;
width: 120rpx;
}
.input {
flex: 1;
font-size: 30rpx;
color: #333;
text-align: right;
}
.save-box {
margin-top: 60rpx;
padding: 0 20rpx;
}
.save-btn {
height: 88rpx;
line-height: 88rpx;
background-color: #007aff;
color: #fff;
border-radius: 44rpx;
font-size: 32rpx;
}
</style>