feat:新增头像和昵称修改
This commit is contained in:
parent
9c3775624f
commit
61df7fca5e
@ -222,6 +222,19 @@ export function getUserInvites(user_id, page = 1, page_size = 20) {
|
||||
// 兼容性适配接口 (适配 pages/mine/index.vue)
|
||||
// ============================================
|
||||
|
||||
// ============================================
|
||||
// 用户信息修改 API
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 修改用户信息
|
||||
* @param {number} user_id - 用户ID
|
||||
* @param {object} data - 用户数据 { nickname, avatar(base64) }
|
||||
*/
|
||||
export function modifyUser(user_id, data) {
|
||||
return authRequest({ url: `/api/app/users/${user_id}`, method: 'PUT', data })
|
||||
}
|
||||
|
||||
export function getUserInfo() {
|
||||
const user_info = uni.getStorageSync('user_info')
|
||||
if (user_info) return Promise.resolve(user_info)
|
||||
|
||||
@ -654,11 +654,6 @@ function fetchExtraData(userId) {
|
||||
box-shadow: 0 12rpx 32rpx rgba(7, 193, 96, 0.3);
|
||||
}
|
||||
|
||||
&.toutiao-icon {
|
||||
background: linear-gradient(135deg, #000000 0%, #1a1a1a 100%);
|
||||
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.icon-emoji {
|
||||
font-size: 56rpx;
|
||||
}
|
||||
@ -678,6 +673,53 @@ function fetchExtraData(userId) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 抖音登录面板 */
|
||||
.toutiao-panel {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 48rpx;
|
||||
|
||||
.panel-icon-wrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.panel-icon {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.toutiao-icon {
|
||||
background: linear-gradient(135deg, #000000 0%, #1a1a1a 100%);
|
||||
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.icon-emoji {
|
||||
font-size: 56rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: $text-main;
|
||||
margin-bottom: 12rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.panel-desc {
|
||||
font-size: 26rpx;
|
||||
color: $text-sub;
|
||||
margin-bottom: 48rpx;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 短信登录面板 */
|
||||
.sms-panel {
|
||||
.panel-title {
|
||||
|
||||
@ -7,9 +7,23 @@
|
||||
<view class="header-section">
|
||||
<view class="user-info-card glass-card">
|
||||
<view class="user-main">
|
||||
<image class="avatar" :src="avatar || '/static/logo.png'" mode="aspectFill"></image>
|
||||
<view class="avatar-wrapper" @click="handleEditAvatar" v-if="nickname">
|
||||
<image class="avatar" :src="avatar || '/static/logo.png'" mode="aspectFill"></image>
|
||||
<view class="avatar-edit-badge">
|
||||
<text class="edit-icon">📷</text>
|
||||
</view>
|
||||
</view>
|
||||
<image v-else class="avatar" :src="avatar || '/static/logo.png'" mode="aspectFill"></image>
|
||||
<view class="user-meta">
|
||||
<view class="name-row">
|
||||
<view class="name-row" @click="handleEditNickname" v-if="nickname">
|
||||
<text class="nickname">{{ nickname || '未登录' }}</text>
|
||||
<text class="edit-nickname-icon">✏️</text>
|
||||
<view class="level-badge" v-if="title">
|
||||
<image class="level-icon" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNGRjZCMDAiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNiAzSDE4TDIxIDlMOSAyMSAzIDlMNiAzWiIgLz48L3N2Zz4=" mode="aspectFit"></image>
|
||||
<text class="level-text">Lv1 {{ title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="name-row" v-else>
|
||||
<text class="nickname">{{ nickname || '未登录' }}</text>
|
||||
<view class="level-badge" v-if="title">
|
||||
<image class="level-icon" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNGRjZCMDAiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNiAzSDE4TDIxIDlMOSAyMSAzIDlMNiAzWiIgLz48L3N2Zz4=" mode="aspectFit"></image>
|
||||
@ -454,7 +468,7 @@
|
||||
<script>
|
||||
import {
|
||||
getUserInfo, getUserStats, getPointsBalance, getUserPoints, getUserCoupons, getItemCards,
|
||||
getUserTasks, getTaskProgress, getInviteRecords
|
||||
getUserTasks, getTaskProgress, getInviteRecords, modifyUser
|
||||
} from '../../api/appUser.js'
|
||||
|
||||
export default {
|
||||
@ -540,6 +554,124 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 修改头像
|
||||
handleEditAvatar() {
|
||||
if (!this.userId) {
|
||||
uni.showToast({ title: '请先登录', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'], // 选择压缩图
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const tempFilePath = res.tempFilePaths[0]
|
||||
this.uploadAvatar(tempFilePath)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 上传头像并转换为 base64
|
||||
async uploadAvatar(filePath) {
|
||||
uni.showLoading({ title: '上传中...' })
|
||||
|
||||
try {
|
||||
// 将图片转换为 base64
|
||||
const base64 = await this.fileToBase64(filePath)
|
||||
|
||||
// 调用修改用户信息接口
|
||||
const data = await modifyUser(this.userId, { avatar: base64 })
|
||||
|
||||
// 更新本地存储
|
||||
uni.setStorageSync('avatar', data.avatar || base64)
|
||||
this.avatar = data.avatar || base64
|
||||
|
||||
const userInfo = uni.getStorageSync('user_info') || {}
|
||||
userInfo.avatar = data.avatar || base64
|
||||
uni.setStorageSync('user_info', userInfo)
|
||||
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '头像修改成功', icon: 'success' })
|
||||
} catch (err) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: err.message || '上传失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
// 文件转 base64
|
||||
fileToBase64(filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.getFileSystemManager().readFile({
|
||||
filePath: filePath,
|
||||
encoding: 'base64',
|
||||
success: (res) => {
|
||||
// 判断文件类型并添加 data URI 前缀
|
||||
const ext = filePath.split('.').pop().toLowerCase()
|
||||
let mimeType = 'image/jpeg'
|
||||
if (ext === 'png') mimeType = 'image/png'
|
||||
if (ext === 'gif') mimeType = 'image/gif'
|
||||
if (ext === 'webp') mimeType = 'image/webp'
|
||||
|
||||
resolve(`data:${mimeType};base64,${res.data}`)
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 修改昵称
|
||||
handleEditNickname() {
|
||||
if (!this.userId) {
|
||||
uni.showToast({ title: '请先登录', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '修改昵称',
|
||||
editable: true,
|
||||
placeholderText: '请输入新昵称',
|
||||
content: this.nickname,
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
const newNickname = res.content?.trim()
|
||||
if (!newNickname) {
|
||||
uni.showToast({ title: '昵称不能为空', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
if (newNickname.length > 20) {
|
||||
uni.showToast({ title: '昵称不能超过20个字符', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
uni.showLoading({ title: '修改中...' })
|
||||
|
||||
// 调用修改用户信息接口
|
||||
const data = await modifyUser(this.userId, { nickname: newNickname })
|
||||
|
||||
// 更新本地存储
|
||||
uni.setStorageSync('nickname', data.nickname || newNickname)
|
||||
this.nickname = data.nickname || newNickname
|
||||
|
||||
const userInfo = uni.getStorageSync('user_info') || {}
|
||||
userInfo.nickname = data.nickname || newNickname
|
||||
uni.setStorageSync('user_info', userInfo)
|
||||
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '昵称修改成功', icon: 'success' })
|
||||
} catch (err) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: err.message || '修改失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getInviteCode() {
|
||||
const v = this.inviteCode || uni.getStorageSync('invite_code') || (uni.getStorageSync('user_info') || {}).invite_code || ''
|
||||
return String(v || '').trim()
|
||||
@ -1186,16 +1318,57 @@ export default {
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
margin-right: 24rpx;
|
||||
cursor: pointer;
|
||||
|
||||
.avatar {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.avatar-edit-badge {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background: linear-gradient(135deg, $brand-primary, $brand-secondary);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 3rpx solid $bg-card;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
|
||||
|
||||
.edit-icon {
|
||||
font-size: 20rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-meta { flex: 1; }
|
||||
|
||||
.name-row {
|
||||
display: flex; align-items: center; margin-bottom: 12rpx;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
.nickname {
|
||||
font-size: $font-xl; font-weight: 900; color: $text-main;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.edit-nickname-icon {
|
||||
font-size: 28rpx;
|
||||
margin-right: 8rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.level-badge {
|
||||
background: linear-gradient(90deg, #333, #555);
|
||||
color: $accent-gold;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user