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)
|
// 兼容性适配接口 (适配 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() {
|
export function getUserInfo() {
|
||||||
const user_info = uni.getStorageSync('user_info')
|
const user_info = uni.getStorageSync('user_info')
|
||||||
if (user_info) return Promise.resolve(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);
|
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 {
|
.icon-emoji {
|
||||||
font-size: 56rpx;
|
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 {
|
.sms-panel {
|
||||||
.panel-title {
|
.panel-title {
|
||||||
|
|||||||
@ -7,9 +7,23 @@
|
|||||||
<view class="header-section">
|
<view class="header-section">
|
||||||
<view class="user-info-card glass-card">
|
<view class="user-info-card glass-card">
|
||||||
<view class="user-main">
|
<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="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>
|
<text class="nickname">{{ nickname || '未登录' }}</text>
|
||||||
<view class="level-badge" v-if="title">
|
<view class="level-badge" v-if="title">
|
||||||
<image class="level-icon" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNGRjZCMDAiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNiAzSDE4TDIxIDlMOSAyMSAzIDlMNiAzWiIgLz48L3N2Zz4=" mode="aspectFit"></image>
|
<image class="level-icon" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNGRjZCMDAiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNiAzSDE4TDIxIDlMOSAyMSAzIDlMNiAzWiIgLz48L3N2Zz4=" mode="aspectFit"></image>
|
||||||
@ -454,7 +468,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
getUserInfo, getUserStats, getPointsBalance, getUserPoints, getUserCoupons, getItemCards,
|
getUserInfo, getUserStats, getPointsBalance, getUserPoints, getUserCoupons, getItemCards,
|
||||||
getUserTasks, getTaskProgress, getInviteRecords
|
getUserTasks, getTaskProgress, getInviteRecords, modifyUser
|
||||||
} from '../../api/appUser.js'
|
} from '../../api/appUser.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -540,6 +554,124 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
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() {
|
getInviteCode() {
|
||||||
const v = this.inviteCode || uni.getStorageSync('invite_code') || (uni.getStorageSync('user_info') || {}).invite_code || ''
|
const v = this.inviteCode || uni.getStorageSync('invite_code') || (uni.getStorageSync('user_info') || {}).invite_code || ''
|
||||||
return String(v || '').trim()
|
return String(v || '').trim()
|
||||||
@ -1186,16 +1318,57 @@ export default {
|
|||||||
margin-right: 24rpx;
|
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; }
|
.user-meta { flex: 1; }
|
||||||
|
|
||||||
.name-row {
|
.name-row {
|
||||||
display: flex; align-items: center; margin-bottom: 12rpx;
|
display: flex; align-items: center; margin-bottom: 12rpx;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.nickname {
|
.nickname {
|
||||||
font-size: $font-xl; font-weight: 900; color: $text-main;
|
font-size: $font-xl; font-weight: 900; color: $text-main;
|
||||||
margin-right: 16rpx;
|
margin-right: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-nickname-icon {
|
||||||
|
font-size: 28rpx;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
.level-badge {
|
.level-badge {
|
||||||
background: linear-gradient(90deg, #333, #555);
|
background: linear-gradient(90deg, #333, #555);
|
||||||
color: $accent-gold;
|
color: $accent-gold;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user