Refactor user profile handling and navigation logic in the mini program. Introduce functions to ensure user profile completeness after login, update avatar selection process, and enhance navigation between chapters based on backend data. Update API endpoints for user data synchronization and improve user experience with new UI elements for profile editing.

This commit is contained in:
Alex-larget
2026-03-12 11:36:50 +08:00
parent da6d2c0852
commit d3b67681d7
27 changed files with 1464 additions and 393 deletions

View File

@@ -37,6 +37,7 @@ Page({
showMbtiPicker: false,
saving: false,
loading: true,
showAvatarModal: false,
},
onLoad() {
@@ -95,6 +96,7 @@ Page({
goBack() { getApp().goBackOrToHome() },
onNicknameInput(e) { this.setData({ nickname: e.detail.value }) },
onNicknameChange(e) { this.setData({ nickname: e.detail.value }) },
onRegionInput(e) { this.setData({ region: e.detail.value }) },
onIndustryInput(e) { this.setData({ industry: e.detail.value }) },
onBusinessScaleInput(e) { this.setData({ businessScale: e.detail.value }) },
@@ -114,7 +116,26 @@ Page({
this.setData({ mbtiIndex: i, mbti: MBTI_OPTIONS[i] })
},
chooseAvatar() {
// 点击头像:选择微信头像或从相册选择
onAvatarTap() {
wx.showActionSheet({
itemList: ['使用微信头像', '从相册选择'],
success: (res) => {
if (res.tapIndex === 0) {
this.setData({ showAvatarModal: true })
} else if (res.tapIndex === 1) {
this.chooseAvatarFromAlbum()
}
},
})
},
closeAvatarModal() {
this.setData({ showAvatarModal: false })
},
// 从相册/相机选择头像
chooseAvatarFromAlbum() {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
@@ -160,6 +181,52 @@ Page({
})
},
// 微信原生 chooseAvatar 回调:使用当前微信头像
async onChooseAvatar(e) {
const tempAvatarUrl = e.detail?.avatarUrl
this.setData({ showAvatarModal: false })
if (!tempAvatarUrl) return
wx.showLoading({ title: '上传中...', mask: true })
try {
const uploadRes = await new Promise((resolve, reject) => {
wx.uploadFile({
url: app.globalData.baseUrl + '/api/miniprogram/upload',
filePath: tempAvatarUrl,
name: 'file',
formData: { folder: 'avatars' },
success: (r) => {
try {
const data = JSON.parse(r.data)
if (data.success) resolve(data)
else reject(new Error(data.error || '上传失败'))
} catch {
reject(new Error('解析失败'))
}
},
fail: reject,
})
})
const avatarUrl = app.globalData.baseUrl + uploadRes.data.url
this.setData({ avatar: avatarUrl })
await app.request({
url: '/api/miniprogram/user/profile',
method: 'POST',
data: { userId: app.globalData.userInfo?.id, avatar: avatarUrl },
})
if (app.globalData.userInfo) {
app.globalData.userInfo.avatar = avatarUrl
wx.setStorageSync('userInfo', app.globalData.userInfo)
}
wx.hideLoading()
wx.showToast({ title: '头像已更新', icon: 'success' })
} catch (err) {
wx.hideLoading()
wx.showToast({ title: err.message || '上传失败,请重试', icon: 'none' })
}
},
async saveProfile() {
const userId = app.globalData.userInfo?.id
if (!userId) {

View File

@@ -17,7 +17,7 @@
<!-- 头像 -->
<view class="avatar-section">
<view class="avatar-wrap" bindtap="chooseAvatar">
<view class="avatar-wrap" bindtap="onAvatarTap">
<view class="avatar-inner">
<image wx:if="{{avatar}}" class="avatar-img" src="{{avatar}}" mode="aspectFill"/>
<view wx:else class="avatar-placeholder">{{nickname ? nickname[0] : '?'}}</view>
@@ -31,7 +31,18 @@
<view class="section">
<view class="form-row">
<text class="form-label">昵称</text>
<view class="form-input-wrap"><input class="form-input-inner" placeholder="请输入昵称" value="{{nickname}}" bindinput="onNicknameInput"/></view>
<view class="form-input-wrap">
<input
class="form-input-inner"
type="nickname"
placeholder="请输入昵称"
value="{{nickname}}"
bindinput="onNicknameInput"
bindchange="onNicknameChange"
maxlength="20"
/>
</view>
<text class="input-tip">微信用户可点击自动填充昵称,或手动输入</text>
</view>
<view class="form-row form-row-2">
<view class="form-item">
@@ -134,4 +145,15 @@
</view>
<view class="bottom-space"></view>
</scroll-view>
<!-- 头像弹窗:通过 button 获取微信头像 -->
<view class="modal-overlay" wx:if="{{showAvatarModal}}" bindtap="closeAvatarModal">
<view class="modal-content avatar-modal" catchtap="stopPropagation">
<view class="modal-close" bindtap="closeAvatarModal">✕</view>
<text class="avatar-modal-title">使用微信头像</text>
<text class="avatar-modal-desc">点击下方按钮,一键同步当前微信头像</text>
<button class="btn-choose-avatar" open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">使用微信头像</button>
<view class="avatar-modal-cancel" bindtap="closeAvatarModal">取消</view>
</view>
</view>
</view>

View File

@@ -101,3 +101,83 @@
}
.save-btn[disabled] { opacity: 0.6; }
.bottom-space { height: 120rpx; }
/* 昵称提示文案 */
.input-tip {
margin-top: 8rpx;
font-size: 22rpx;
color: #94A3B8;
margin-left: 8rpx;
}
/* 头像弹窗样式,复用我的页风格 */
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.6);
backdrop-filter: blur(16rpx);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 48rpx;
box-sizing: border-box;
}
.modal-content {
width: 100%;
max-width: 640rpx;
background: #0b1220;
border-radius: 32rpx;
padding: 48rpx;
position: relative;
box-sizing: border-box;
}
.modal-close {
position: absolute;
top: 24rpx;
right: 24rpx;
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background: rgba(255,255,255,0.08);
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: rgba(255,255,255,0.7);
}
.avatar-modal-title {
display: block;
font-size: 36rpx;
font-weight: 700;
text-align: center;
margin-bottom: 12rpx;
}
.avatar-modal-desc {
display: block;
font-size: 26rpx;
color: #94A3B8;
text-align: center;
margin-bottom: 32rpx;
}
.btn-choose-avatar {
width: 100%;
height: 88rpx;
line-height: 88rpx;
text-align: center;
background: #5EEAD4;
color: #050B14;
font-size: 30rpx;
font-weight: 600;
border-radius: 44rpx;
border: none;
}
.btn-choose-avatar::after {
border: none;
}
.avatar-modal-cancel {
margin-top: 24rpx;
text-align: center;
font-size: 28rpx;
color: #9CA3AF;
}