Files
Mycontent/miniprogram/pages/avatar-nickname/avatar-nickname.js
乘风 2645212d47 feat: update API base URLs and enhance icon designs
- Updated the API base URLs in app.js to point to local development server for testing.
- Enhanced SVG icons with gradient fills for improved visual appeal across various components.
- Refactored the avatar upload functionality in avatar-nickname.js and profile-edit.js to utilize a new upload utility for better code maintainability.
- Improved the layout and styling of the my page and super article editor for a more user-friendly interface.

This update aims to streamline development processes and enhance the overall user experience in the application.
2026-05-09 16:00:16 +08:00

254 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 卡若创业派对 - 头像与昵称设置页
* 每次进入页面头像、昵称表单均为空,不回显服务端/本地资料;提交后再写入。
* 新用户from=new_user须上传头像 + 自填昵称后才能「完成」。
*/
const app = getApp()
const { trackClick } = require('../../utils/trackClick')
const { resolveChooseAvatarFilePath, pickLocalAvatarImagePath } = require('../../utils/util.js')
const { uploadByApi } = require('../../utils/miniprogramUpload.js')
function isPlaceholderNickname(n) {
const s = (n || '').trim()
if (!s) return true
return s === '微信用户' || s.indexOf('微信用户') === 0
}
Page({
data: {
statusBarHeight: 44,
avatar: '',
nickname: '',
saving: false,
nicknameInputFocus: false,
/** 规则引擎传入avatar | nickname用于高亮对应区块 */
uiFocus: '',
fromNewUser: false,
/** 新用户:头像+真实昵称都齐才可提交 */
canSubmit: true,
/** 延后挂载昵称 input避免微信原生层缓存/自动填充造成「假回显」 */
nickInputReady: false,
},
onLoad(options) {
const fromNewUser = String(options.from || '').toLowerCase() === 'new_user'
const focus = String(options.focus || '').toLowerCase()
this.setData({
statusBarHeight: app.globalData.statusBarHeight || 44,
fromNewUser,
nickInputReady: false,
})
if (focus === 'avatar' || focus === 'nickname') {
this.setData({ uiFocus: focus })
}
this.loadFromUser()
// 下一帧再挂载 input + 再清一次,打断原生昵称缓存(测试工程师等)
setTimeout(() => {
this.setData({
nickname: '',
avatar: '',
nickInputReady: true,
})
this._updateCanSubmit()
if (focus === 'nickname') {
setTimeout(() => {
if (typeof wx.requirePrivacyAuthorize === 'function') {
wx.requirePrivacyAuthorize({
success: () => this.setData({ nicknameInputFocus: true }),
fail: () => {},
})
} else {
this.setData({ nicknameInputFocus: true })
}
}, 400)
}
}, 50)
if (fromNewUser) {
trackClick('avatar_nickname', 'page_view', '新注册引导页')
}
},
loadFromUser() {
const user = app.globalData.userInfo
if (!app.globalData.isLoggedIn || !user?.id) {
wx.showToast({ title: '请先登录', icon: 'none' })
setTimeout(() => getApp().goBackOrToHome(), 1500)
return
}
// 任意用户进入本页均不回显已有头像/昵称,由用户在本页重新选择、填写后再保存
this.setData({
nickname: '',
avatar: '',
})
this._updateCanSubmit()
},
_updateCanSubmit() {
const { avatar, nickname, fromNewUser } = this.data
const nick = (nickname || '').trim()
if (!fromNewUser) {
this.setData({ canSubmit: true })
return
}
const ok = !!(avatar && nick && !isPlaceholderNickname(nick))
this.setData({ canSubmit: ok })
},
goBack() {
if (this.data.fromNewUser && this._isProfileIncomplete()) {
wx.showModal({
title: '提示',
content: '请先设置头像并填写昵称后再离开',
showCancel: false,
confirmText: '我知道了',
})
return
}
getApp().goBackOrToHome()
},
_isProfileIncomplete() {
const { avatar, nickname, fromNewUser } = this.data
if (!fromNewUser) return false
const nick = (nickname || '').trim()
const av = (avatar || '').trim()
return !av || !nick || isPlaceholderNickname(nick)
},
onNicknameInput(e) {
this.setData({ nickname: e.detail.value })
this._updateCanSubmit()
},
onNicknameChange(e) {
this.setData({ nickname: e.detail.value })
this._updateCanSubmit()
},
onNicknameBlur() {
this.setData({ nicknameInputFocus: false })
},
onNicknameAreaTouch() {
if (typeof wx.requirePrivacyAuthorize !== 'function') return
wx.requirePrivacyAuthorize({
success: () => {
this.setData({ nicknameInputFocus: true })
},
fail: () => {},
})
},
onTapPickAvatar() {
trackClick('avatar_nickname', 'btn_click', '选择头像')
const run = () => {
pickLocalAvatarImagePath()
.then((p) => this.uploadAndSaveAvatar(p))
.catch((err) => {
if (err && err.cancelled) return
wx.showToast({ title: (err && err.message) || '选择图片失败', icon: 'none' })
})
}
if (typeof wx.requirePrivacyAuthorize === 'function') {
wx.requirePrivacyAuthorize({
success: run,
fail: () => wx.showToast({ title: '需同意隐私指引后再换头像', icon: 'none' }),
})
} else {
run()
}
},
async uploadAndSaveAvatar(tempUrl) {
wx.showLoading({ title: '上传中...', mask: true })
try {
let filePath
try {
filePath = await resolveChooseAvatarFilePath(tempUrl)
} catch (readErr) {
wx.hideLoading()
wx.showToast({ title: readErr.message || '无法读取所选图片', icon: 'none' })
return
}
const uploadRes = await uploadByApi({ filePath, folder: 'avatars' })
let avatarUrl = uploadRes.data?.url || uploadRes.url
if (avatarUrl && !avatarUrl.startsWith('http')) {
avatarUrl = app.globalData.baseUrl + avatarUrl
}
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' })
this._updateCanSubmit()
if (this.data.fromNewUser) {
trackClick('avatar_nickname', 'form_step_done', '头像更新完成')
}
} catch (e) {
wx.hideLoading()
wx.showToast({ title: e.message || '上传失败', icon: 'none' })
}
},
async saveProfile() {
const userId = app.globalData.userInfo?.id
if (!userId) {
wx.showToast({ title: '请先登录', icon: 'none' })
return
}
if (this.data.fromNewUser && !this.data.canSubmit) {
wx.showToast({ title: '请先设置头像并填写昵称', icon: 'none' })
return
}
const nickname = (this.data.nickname || '').trim()
const avatar = (this.data.avatar || '').trim()
if (!nickname) {
wx.showToast({ title: '请输入昵称', icon: 'none' })
return
}
if (this.data.fromNewUser) {
if (!avatar) {
wx.showToast({ title: '请先选择头像', icon: 'none' })
return
}
if (isPlaceholderNickname(nickname)) {
wx.showToast({ title: '请修改昵称,不能使用系统默认占位词', icon: 'none' })
return
}
}
trackClick('avatar_nickname', 'btn_click', '完成保存')
this.setData({ saving: true })
try {
await app.request({
url: '/api/miniprogram/user/profile',
method: 'POST',
data: { userId, avatar: avatar || undefined, nickname },
})
if (app.globalData.userInfo) {
if (nickname) app.globalData.userInfo.nickname = nickname
if (avatar) app.globalData.userInfo.avatar = avatar
wx.setStorageSync('userInfo', app.globalData.userInfo)
}
if (this.data.fromNewUser) {
try {
wx.removeStorageSync('profile_guide_required')
} catch (_) {}
wx.setStorageSync('new_user_guide_done_at', Date.now())
trackClick('avatar_nickname', 'form_submit', '新注册引导完成', {
hasAvatar: !!avatar,
nicknameLen: nickname.length,
})
}
wx.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => getApp().goBackOrToHome(), 800)
} catch (e) {
wx.showToast({ title: e.message || '保存失败', icon: 'none' })
}
this.setData({ saving: false })
},
})