feat: 添加微信授权登录和修改昵称功能
This commit is contained in:
@@ -21,6 +21,10 @@ export default class ProfileScene extends BaseScene {
|
||||
this.selectedStoryRecords = []; // 选中故事的记录列表
|
||||
this.selectedStoryInfo = {}; // 选中故事的信息
|
||||
|
||||
// 头像相关
|
||||
this.avatarImage = null;
|
||||
this.avatarImageLoaded = false;
|
||||
|
||||
// 统计
|
||||
this.stats = {
|
||||
works: 0,
|
||||
@@ -40,6 +44,29 @@ export default class ProfileScene extends BaseScene {
|
||||
|
||||
async init() {
|
||||
await this.loadData();
|
||||
this.loadAvatarImage();
|
||||
}
|
||||
|
||||
// 加载头像图片
|
||||
loadAvatarImage() {
|
||||
let avatarUrl = this.main.userManager.avatarUrl;
|
||||
if (!avatarUrl) return;
|
||||
|
||||
// 如果是相对路径,拼接完整 URL
|
||||
if (avatarUrl.startsWith('/uploads')) {
|
||||
avatarUrl = 'http://172.20.10.8:8000' + avatarUrl;
|
||||
}
|
||||
|
||||
if (avatarUrl.startsWith('http')) {
|
||||
this.avatarImage = wx.createImage();
|
||||
this.avatarImage.onload = () => {
|
||||
this.avatarImageLoaded = true;
|
||||
};
|
||||
this.avatarImage.onerror = () => {
|
||||
this.avatarImageLoaded = false;
|
||||
};
|
||||
this.avatarImage.src = avatarUrl;
|
||||
}
|
||||
}
|
||||
|
||||
async loadData() {
|
||||
@@ -155,18 +182,42 @@ export default class ProfileScene extends BaseScene {
|
||||
const avatarSize = 50;
|
||||
const avatarX = 30;
|
||||
const avatarY = cardY + 18;
|
||||
const avatarGradient = ctx.createLinearGradient(avatarX, avatarY, avatarX + avatarSize, avatarY + avatarSize);
|
||||
avatarGradient.addColorStop(0, '#ff6b6b');
|
||||
avatarGradient.addColorStop(1, '#ffd700');
|
||||
ctx.fillStyle = avatarGradient;
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// 保存头像区域用于点击检测
|
||||
this.avatarRect = { x: avatarX, y: avatarY, width: avatarSize, height: avatarSize };
|
||||
|
||||
// 如果有头像图片则绘制图片,否则绘制默认渐变头像
|
||||
if (this.avatarImage && this.avatarImageLoaded) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
|
||||
ctx.clip();
|
||||
ctx.drawImage(this.avatarImage, avatarX, avatarY, avatarSize, avatarSize);
|
||||
ctx.restore();
|
||||
} else {
|
||||
const avatarGradient = ctx.createLinearGradient(avatarX, avatarY, avatarX + avatarSize, avatarY + avatarSize);
|
||||
avatarGradient.addColorStop(0, '#ff6b6b');
|
||||
avatarGradient.addColorStop(1, '#ffd700');
|
||||
ctx.fillStyle = avatarGradient;
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.font = 'bold 20px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(user.nickname ? user.nickname[0] : '游', avatarX + avatarSize / 2, avatarY + avatarSize / 2 + 7);
|
||||
}
|
||||
|
||||
// 编辑图标(头像右下角)
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.5)';
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize - 8, avatarY + avatarSize - 8, 10, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.font = 'bold 20px sans-serif';
|
||||
ctx.font = '10px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(user.nickname ? user.nickname[0] : '游', avatarX + avatarSize / 2, avatarY + avatarSize / 2 + 7);
|
||||
ctx.fillText('✎', avatarX + avatarSize - 8, avatarY + avatarSize - 5);
|
||||
|
||||
// 昵称和ID
|
||||
ctx.textAlign = 'left';
|
||||
@@ -713,6 +764,21 @@ export default class ProfileScene extends BaseScene {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置按钮(右上角)
|
||||
if (y < 50 && x > this.screenWidth - 50) {
|
||||
this.showSettingsMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
// 头像点击
|
||||
if (this.avatarRect) {
|
||||
const rect = this.avatarRect;
|
||||
if (x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height) {
|
||||
this.showAvatarOptions();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Tab切换
|
||||
if (this.tabRects) {
|
||||
for (const rect of this.tabRects) {
|
||||
@@ -946,4 +1012,196 @@ export default class ProfileScene extends BaseScene {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示设置菜单
|
||||
showSettingsMenu() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['修改头像', '修改昵称', '退出登录'],
|
||||
success: (res) => {
|
||||
switch (res.tapIndex) {
|
||||
case 0:
|
||||
this.chooseAndUploadAvatar();
|
||||
break;
|
||||
case 1:
|
||||
this.showEditNicknameDialog();
|
||||
break;
|
||||
case 2:
|
||||
this.confirmLogout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示头像选项
|
||||
showAvatarOptions() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['从相册选择', '取消'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
this.chooseAndUploadAvatar();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 选择并上传头像
|
||||
chooseAndUploadAvatar() {
|
||||
console.log('[ProfileScene] 开始选择头像');
|
||||
wx.chooseMedia({
|
||||
count: 1,
|
||||
mediaType: ['image'],
|
||||
sourceType: ['album', 'camera'],
|
||||
sizeType: ['compressed'],
|
||||
success: async (res) => {
|
||||
console.log('[ProfileScene] 选择图片成功:', res);
|
||||
const tempFilePath = res.tempFiles[0].tempFilePath;
|
||||
|
||||
wx.showLoading({ title: '上传中...' });
|
||||
|
||||
try {
|
||||
// 上传图片到服务器
|
||||
const uploadRes = await this.uploadAvatar(tempFilePath);
|
||||
console.log('[ProfileScene] 上传结果:', uploadRes);
|
||||
|
||||
if (uploadRes && uploadRes.url) {
|
||||
// 更新用户头像
|
||||
const success = await this.main.userManager.updateProfile(
|
||||
this.main.userManager.nickname,
|
||||
uploadRes.url
|
||||
);
|
||||
|
||||
wx.hideLoading();
|
||||
|
||||
if (success) {
|
||||
// 重新加载头像
|
||||
this.loadAvatarImage();
|
||||
wx.showToast({ title: '头像更新成功', icon: 'success' });
|
||||
} else {
|
||||
wx.showToast({ title: '更新失败', icon: 'none' });
|
||||
}
|
||||
} else {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '上传失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
wx.hideLoading();
|
||||
console.error('[ProfileScene] 上传头像失败:', error);
|
||||
wx.showToast({ title: '上传失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[ProfileScene] 选择图片失败:', err);
|
||||
if (err.errMsg && err.errMsg.indexOf('cancel') === -1) {
|
||||
wx.showToast({ title: '选择图片失败', icon: 'none' });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 上传头像到服务器
|
||||
uploadAvatar(filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const token = this.main.userManager.token || '';
|
||||
const baseUrl = 'http://172.20.10.8:8000'; // 与 http.js 保持一致
|
||||
|
||||
wx.uploadFile({
|
||||
url: `${baseUrl}/api/upload/avatar`,
|
||||
filePath: filePath,
|
||||
name: 'file',
|
||||
header: {
|
||||
'Authorization': token ? `Bearer ${token}` : ''
|
||||
},
|
||||
success: (res) => {
|
||||
try {
|
||||
const data = JSON.parse(res.data);
|
||||
if (data.code === 0) {
|
||||
resolve(data.data);
|
||||
} else {
|
||||
reject(new Error(data.message || '上传失败'));
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 修改昵称弹窗
|
||||
showEditNicknameDialog() {
|
||||
console.log('[ProfileScene] 显示修改昵称弹窗');
|
||||
const currentNickname = this.main.userManager.nickname || '';
|
||||
|
||||
// 微信小游戏使用 wx.showModal 的 editable 参数
|
||||
wx.showModal({
|
||||
title: '修改昵称',
|
||||
editable: true,
|
||||
placeholderText: '请输入新昵称',
|
||||
success: async (res) => {
|
||||
console.log('[ProfileScene] showModal 回调:', res);
|
||||
if (res.confirm) {
|
||||
const newNickname = (res.content || '').trim();
|
||||
console.log('[ProfileScene] 新昵称:', newNickname);
|
||||
|
||||
if (!newNickname) {
|
||||
wx.showToast({ title: '昵称不能为空', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (newNickname === currentNickname) {
|
||||
wx.showToast({ title: '昵称未变更', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
wx.showLoading({ title: '保存中...' });
|
||||
try {
|
||||
const success = await this.main.userManager.updateProfile(
|
||||
newNickname,
|
||||
this.main.userManager.avatarUrl || ''
|
||||
);
|
||||
wx.hideLoading();
|
||||
|
||||
if (success) {
|
||||
wx.showToast({ title: '修改成功', icon: 'success' });
|
||||
} else {
|
||||
wx.showToast({ title: '修改失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
wx.hideLoading();
|
||||
console.error('[ProfileScene] 修改昵称失败:', e);
|
||||
wx.showToast({ title: '修改失败', icon: 'none' });
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[ProfileScene] showModal 失败:', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 确认退出登录
|
||||
confirmLogout() {
|
||||
wx.showModal({
|
||||
title: '确认退出',
|
||||
content: '退出登录后需要重新授权登录,确定退出吗?',
|
||||
confirmText: '退出',
|
||||
confirmColor: '#e74c3c',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 执行退出登录
|
||||
this.main.userManager.logout();
|
||||
|
||||
// 停止草稿检查
|
||||
this.main.stopDraftChecker();
|
||||
|
||||
// 跳转到登录页
|
||||
this.main.sceneManager.switchScene('login');
|
||||
|
||||
wx.showToast({ title: '已退出登录', icon: 'success' });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user