2026-03-07 22:58:43 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* Soul创业派对 - 资料编辑完整版(comprehensive_profile_editor_v1_1)
|
|
|
|
|
|
* 温馨提示、头像、基本信息、核心联系方式、个人故事、互助需求、项目介绍
|
|
|
|
|
|
*
|
|
|
|
|
|
* 接口约定(/api/miniprogram/user/profile):
|
|
|
|
|
|
* - GET ?userId= 返回 data: { avatar, nickname, mbti, region, industry, businessScale, position, skills, phone, wechatId, ... },空值统一为 ""
|
|
|
|
|
|
* - POST body:普通用户提交基础字段;VIP 提交全部字段(含 skills、个人故事、互助需求、项目介绍)
|
|
|
|
|
|
*
|
|
|
|
|
|
* 表单展示:普通用户仅展示 温馨提示、头像、昵称、MBTI、地区、行业、业务体量、职位、核心联系方式;VIP 展示全部
|
|
|
|
|
|
*/
|
|
|
|
|
|
const app = getApp()
|
|
|
|
|
|
|
|
|
|
|
|
const MBTI_OPTIONS = ['INTJ', 'INFP', 'INTP', 'ENTP', 'ENFP', 'ENTJ', 'ENFJ', 'INFJ', 'ISTJ', 'ISFJ', 'ESTJ', 'ESFJ', 'ISTP', 'ISFP', 'ESTP', 'ESFP']
|
|
|
|
|
|
|
|
|
|
|
|
Page({
|
|
|
|
|
|
data: {
|
|
|
|
|
|
statusBarHeight: 44,
|
|
|
|
|
|
isVip: false,
|
|
|
|
|
|
avatar: '',
|
|
|
|
|
|
nickname: '',
|
2026-03-16 16:10:30 +08:00
|
|
|
|
shareCardPath: '', // 分享名片封面图(预生成)
|
2026-03-07 22:58:43 +08:00
|
|
|
|
mbti: '',
|
|
|
|
|
|
mbtiIndex: 0,
|
|
|
|
|
|
region: '',
|
|
|
|
|
|
industry: '',
|
|
|
|
|
|
businessScale: '',
|
|
|
|
|
|
position: '',
|
|
|
|
|
|
skills: '',
|
|
|
|
|
|
phone: '',
|
|
|
|
|
|
wechatId: '',
|
|
|
|
|
|
storyBestMonth: '',
|
|
|
|
|
|
storyAchievement: '',
|
|
|
|
|
|
storyTurning: '',
|
|
|
|
|
|
helpOffer: '',
|
|
|
|
|
|
helpNeed: '',
|
|
|
|
|
|
projectIntro: '',
|
|
|
|
|
|
mbtiOptions: MBTI_OPTIONS,
|
|
|
|
|
|
showMbtiPicker: false,
|
|
|
|
|
|
saving: false,
|
|
|
|
|
|
loading: true,
|
2026-03-12 11:36:50 +08:00
|
|
|
|
showAvatarModal: false,
|
2026-03-07 22:58:43 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-16 16:10:30 +08:00
|
|
|
|
onLoad(options) {
|
2026-03-07 22:58:43 +08:00
|
|
|
|
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 44 })
|
2026-03-16 16:10:30 +08:00
|
|
|
|
wx.showShareMenu({ withShareTimeline: true })
|
|
|
|
|
|
// 从朋友圈/分享打开且带 id:跳转到名片详情(member-detail)
|
|
|
|
|
|
if (options?.id) {
|
|
|
|
|
|
const ref = options.ref ? `&ref=${options.ref}` : ''
|
|
|
|
|
|
wx.redirectTo({ url: `/pages/member-detail/member-detail?id=${options.id}${ref}` })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-03-07 22:58:43 +08:00
|
|
|
|
this.loadProfile()
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
async loadProfile() {
|
|
|
|
|
|
const userInfo = app.globalData.userInfo
|
|
|
|
|
|
if (!app.globalData.isLoggedIn || !userInfo?.id) {
|
|
|
|
|
|
this.setData({ loading: false })
|
|
|
|
|
|
wx.showToast({ title: '请先登录', icon: 'none' })
|
|
|
|
|
|
setTimeout(() => getApp().goBackOrToHome(), 1500)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
const userId = userInfo.id
|
|
|
|
|
|
const [profileRes, vipRes] = await Promise.all([
|
|
|
|
|
|
app.request({ url: `/api/miniprogram/user/profile?userId=${userId}`, silent: true }),
|
|
|
|
|
|
app.request({ url: `/api/miniprogram/vip/status?userId=${userId}`, silent: true }),
|
|
|
|
|
|
])
|
|
|
|
|
|
this.setData({ isVip: vipRes?.data?.isVip || false })
|
|
|
|
|
|
const res = profileRes
|
|
|
|
|
|
if (res?.success && res.data) {
|
|
|
|
|
|
const d = res.data
|
|
|
|
|
|
const v = (k) => (d[k] != null && d[k] !== '') ? String(d[k]) : ''
|
|
|
|
|
|
const mbtiIndex = MBTI_OPTIONS.indexOf(v('mbti')) >= 0 ? MBTI_OPTIONS.indexOf(v('mbti')) : 0
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
avatar: v('avatar'),
|
|
|
|
|
|
nickname: v('nickname'),
|
|
|
|
|
|
mbti: v('mbti'),
|
|
|
|
|
|
mbtiIndex,
|
|
|
|
|
|
region: v('region'),
|
|
|
|
|
|
industry: v('industry'),
|
|
|
|
|
|
businessScale: v('businessScale'),
|
|
|
|
|
|
position: v('position'),
|
|
|
|
|
|
skills: v('skills'),
|
|
|
|
|
|
phone: v('phone'),
|
|
|
|
|
|
wechatId: v('wechatId') || wx.getStorageSync('user_wechat') || '',
|
|
|
|
|
|
storyBestMonth: v('storyBestMonth'),
|
|
|
|
|
|
storyAchievement: v('storyAchievement'),
|
|
|
|
|
|
storyTurning: v('storyTurning'),
|
|
|
|
|
|
helpOffer: v('helpOffer'),
|
|
|
|
|
|
helpNeed: v('helpNeed'),
|
|
|
|
|
|
projectIntro: v('projectIntro'),
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
})
|
2026-03-16 16:10:30 +08:00
|
|
|
|
setTimeout(() => this.generateShareCard(), 200)
|
2026-03-07 22:58:43 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
this.setData({ loading: false })
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
this.setData({ loading: false })
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
goBack() { getApp().goBackOrToHome() },
|
|
|
|
|
|
|
2026-03-16 17:18:49 +08:00
|
|
|
|
// 生成分享名片封面图(参考:头像左+昵称右,分隔线,四栏信息 5:4)
|
2026-03-16 16:10:30 +08:00
|
|
|
|
async generateShareCard() {
|
2026-03-16 17:18:49 +08:00
|
|
|
|
const { avatar, nickname, region, mbti, industry, position } = this.data
|
2026-03-16 16:10:30 +08:00
|
|
|
|
const userId = app.globalData.userInfo?.id
|
|
|
|
|
|
if (!userId) return
|
|
|
|
|
|
try {
|
|
|
|
|
|
const ctx = wx.createCanvasContext('shareCardCanvas', this)
|
|
|
|
|
|
const w = 500
|
|
|
|
|
|
const h = 400
|
2026-03-16 17:18:49 +08:00
|
|
|
|
const pad = 32
|
|
|
|
|
|
// 背景(深灰卡片感)
|
2026-03-16 16:10:30 +08:00
|
|
|
|
const grd = ctx.createLinearGradient(0, 0, w, h)
|
2026-03-16 17:18:49 +08:00
|
|
|
|
grd.addColorStop(0, '#1E293B')
|
2026-03-16 16:10:30 +08:00
|
|
|
|
grd.addColorStop(1, '#0F172A')
|
|
|
|
|
|
ctx.setFillStyle(grd)
|
|
|
|
|
|
ctx.fillRect(0, 0, w, h)
|
2026-03-16 17:18:49 +08:00
|
|
|
|
// 顶部区域:左头像 + 右昵称
|
|
|
|
|
|
const avatarSize = 100
|
|
|
|
|
|
const avatarX = pad + 10
|
|
|
|
|
|
const avatarY = 50
|
2026-03-16 16:10:30 +08:00
|
|
|
|
const avatarRadius = avatarSize / 2
|
2026-03-16 17:18:49 +08:00
|
|
|
|
const rightStart = avatarX + avatarSize + 28
|
2026-03-16 16:10:30 +08:00
|
|
|
|
const drawAvatar = () => new Promise((resolve) => {
|
|
|
|
|
|
if (avatar && avatar.startsWith('http')) {
|
|
|
|
|
|
wx.downloadFile({
|
|
|
|
|
|
url: avatar,
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
if (res.statusCode === 200) {
|
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
|
ctx.arc(avatarX + avatarRadius, avatarY + avatarRadius, avatarRadius, 0, Math.PI * 2)
|
|
|
|
|
|
ctx.clip()
|
|
|
|
|
|
ctx.drawImage(res.tempFilePath, avatarX, avatarY, avatarSize, avatarSize)
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.drawAvatarPlaceholder(ctx, avatarX, avatarY, avatarSize, nickname)
|
|
|
|
|
|
}
|
|
|
|
|
|
resolve()
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: () => {
|
|
|
|
|
|
this.drawAvatarPlaceholder(ctx, avatarX, avatarY, avatarSize, nickname)
|
|
|
|
|
|
resolve()
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.drawAvatarPlaceholder(ctx, avatarX, avatarY, avatarSize, nickname)
|
|
|
|
|
|
resolve()
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
await drawAvatar()
|
2026-03-16 17:18:49 +08:00
|
|
|
|
ctx.setStrokeStyle('rgba(94,234,212,0.5)')
|
|
|
|
|
|
ctx.setLineWidth(2)
|
2026-03-16 16:10:30 +08:00
|
|
|
|
ctx.beginPath()
|
|
|
|
|
|
ctx.arc(avatarX + avatarRadius, avatarY + avatarRadius, avatarRadius, 0, Math.PI * 2)
|
|
|
|
|
|
ctx.stroke()
|
2026-03-16 17:18:49 +08:00
|
|
|
|
// 右侧:昵称 + 个人名片
|
2026-03-16 16:10:30 +08:00
|
|
|
|
const displayName = (nickname || '').trim() || '创业者'
|
|
|
|
|
|
ctx.setFillStyle('#ffffff')
|
2026-03-16 17:18:49 +08:00
|
|
|
|
ctx.setFontSize(26)
|
|
|
|
|
|
ctx.setTextAlign('left')
|
|
|
|
|
|
ctx.fillText(displayName, rightStart, avatarY + 36)
|
|
|
|
|
|
ctx.setFillStyle('#94A3B8')
|
|
|
|
|
|
ctx.setFontSize(13)
|
|
|
|
|
|
ctx.fillText('个人名片', rightStart, avatarY + 62)
|
|
|
|
|
|
// 分隔线
|
|
|
|
|
|
const divY = 168
|
|
|
|
|
|
ctx.setStrokeStyle('rgba(255,255,255,0.08)')
|
|
|
|
|
|
ctx.setLineWidth(1)
|
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
|
ctx.moveTo(pad, divY)
|
|
|
|
|
|
ctx.lineTo(w - pad, divY)
|
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
|
// 底部四栏:地区 | MBTI,行业 | 职位
|
|
|
|
|
|
const labelGray = '#64748B'
|
|
|
|
|
|
const valueWhite = '#F1F5F9'
|
|
|
|
|
|
const rowH = 52
|
|
|
|
|
|
const colW = (w - pad * 2) / 2
|
|
|
|
|
|
const truncate = (text, maxW) => {
|
|
|
|
|
|
if (!text) return ''
|
|
|
|
|
|
ctx.setFontSize(15)
|
|
|
|
|
|
let m = ctx.measureText(text)
|
|
|
|
|
|
if (m.width <= maxW) return text
|
|
|
|
|
|
for (let i = text.length - 1; i > 0; i--) {
|
|
|
|
|
|
const t = text.slice(0, i) + '…'
|
|
|
|
|
|
if (ctx.measureText(t).width <= maxW) return t
|
|
|
|
|
|
}
|
|
|
|
|
|
return text[0] + '…'
|
|
|
|
|
|
}
|
|
|
|
|
|
const maxValW = colW - 16
|
|
|
|
|
|
const items = [
|
|
|
|
|
|
{ label: '地区', value: truncate((region || '').trim() || '未填写', maxValW), x: pad },
|
|
|
|
|
|
{ label: 'MBTI', value: (mbti || '').trim() || '未填写', x: pad + colW },
|
|
|
|
|
|
{ label: '行业', value: truncate((industry || '').trim() || '未填写', maxValW), x: pad },
|
|
|
|
|
|
{ label: '职位', value: truncate((position || '').trim() || '未填写', maxValW), x: pad + colW },
|
|
|
|
|
|
]
|
|
|
|
|
|
items.forEach((item, i) => {
|
|
|
|
|
|
const row = Math.floor(i / 2)
|
|
|
|
|
|
const baseY = divY + 36 + row * rowH
|
|
|
|
|
|
ctx.setFillStyle(labelGray)
|
|
|
|
|
|
ctx.setFontSize(12)
|
|
|
|
|
|
ctx.fillText(item.label, item.x, baseY - 8)
|
|
|
|
|
|
ctx.setFillStyle(valueWhite)
|
|
|
|
|
|
ctx.setFontSize(15)
|
|
|
|
|
|
ctx.fillText(item.value, item.x, baseY + 14)
|
|
|
|
|
|
})
|
2026-03-16 16:10:30 +08:00
|
|
|
|
ctx.draw(true, () => {
|
|
|
|
|
|
wx.canvasToTempFilePath({
|
|
|
|
|
|
canvasId: 'shareCardCanvas',
|
|
|
|
|
|
destWidth: 500,
|
|
|
|
|
|
destHeight: 400,
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
this.setData({ shareCardPath: res.tempFilePath })
|
|
|
|
|
|
},
|
|
|
|
|
|
}, this)
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.warn('[ShareCard] 生成失败:', e)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
drawAvatarPlaceholder(ctx, x, y, size, nickname) {
|
2026-03-16 17:18:49 +08:00
|
|
|
|
ctx.setFillStyle('rgba(94,234,212,0.2)')
|
2026-03-16 16:10:30 +08:00
|
|
|
|
ctx.beginPath()
|
|
|
|
|
|
ctx.arc(x + size / 2, y + size / 2, size / 2, 0, Math.PI * 2)
|
|
|
|
|
|
ctx.fill()
|
|
|
|
|
|
ctx.setFillStyle('#5EEAD4')
|
2026-03-16 17:18:49 +08:00
|
|
|
|
ctx.setFontSize(size * 0.42)
|
2026-03-16 16:10:30 +08:00
|
|
|
|
ctx.setTextAlign('center')
|
2026-03-16 17:18:49 +08:00
|
|
|
|
ctx.fillText((nickname || '?')[0], x + size / 2, y + size / 2 + size * 0.14)
|
2026-03-16 16:10:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-14 17:13:06 +08:00
|
|
|
|
onShareAppMessage() {
|
|
|
|
|
|
const ref = app.getMyReferralCode()
|
2026-03-16 16:10:30 +08:00
|
|
|
|
const userId = app.globalData.userInfo?.id
|
|
|
|
|
|
const nickname = (this.data.nickname || '').trim() || '我'
|
|
|
|
|
|
const path = userId
|
|
|
|
|
|
? (ref ? `/pages/member-detail/member-detail?id=${userId}&ref=${ref}` : `/pages/member-detail/member-detail?id=${userId}`)
|
|
|
|
|
|
: (ref ? `/pages/profile-edit/profile-edit?ref=${ref}` : '/pages/profile-edit/profile-edit')
|
|
|
|
|
|
const result = {
|
|
|
|
|
|
title: `${nickname}为您分享名片`,
|
|
|
|
|
|
path,
|
2026-03-14 17:13:06 +08:00
|
|
|
|
}
|
2026-03-16 16:10:30 +08:00
|
|
|
|
if (this.data.shareCardPath) result.imageUrl = this.data.shareCardPath
|
|
|
|
|
|
return result
|
2026-03-14 17:13:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onShareTimeline() {
|
|
|
|
|
|
const ref = app.getMyReferralCode()
|
2026-03-16 16:10:30 +08:00
|
|
|
|
const userId = app.globalData.userInfo?.id
|
|
|
|
|
|
const nickname = (this.data.nickname || '').trim() || '我'
|
|
|
|
|
|
const query = userId
|
|
|
|
|
|
? (ref ? `id=${userId}&ref=${ref}` : `id=${userId}`)
|
|
|
|
|
|
: (ref ? `ref=${ref}` : '')
|
|
|
|
|
|
const result = {
|
|
|
|
|
|
title: `${nickname}为您分享名片`,
|
|
|
|
|
|
query: query || '',
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.data.shareCardPath) result.imageUrl = this.data.shareCardPath
|
|
|
|
|
|
return result
|
2026-03-14 17:13:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-07 22:58:43 +08:00
|
|
|
|
onNicknameInput(e) { this.setData({ nickname: e.detail.value }) },
|
2026-03-12 11:36:50 +08:00
|
|
|
|
onNicknameChange(e) { this.setData({ nickname: e.detail.value }) },
|
2026-03-07 22:58:43 +08:00
|
|
|
|
onRegionInput(e) { this.setData({ region: e.detail.value }) },
|
|
|
|
|
|
onIndustryInput(e) { this.setData({ industry: e.detail.value }) },
|
|
|
|
|
|
onBusinessScaleInput(e) { this.setData({ businessScale: e.detail.value }) },
|
|
|
|
|
|
onPositionInput(e) { this.setData({ position: e.detail.value }) },
|
|
|
|
|
|
onSkillsInput(e) { this.setData({ skills: e.detail.value }) },
|
|
|
|
|
|
onPhoneInput(e) { this.setData({ phone: e.detail.value }) },
|
|
|
|
|
|
onWechatInput(e) { this.setData({ wechatId: e.detail.value }) },
|
|
|
|
|
|
onStoryBestMonthInput(e) { this.setData({ storyBestMonth: e.detail.value }) },
|
|
|
|
|
|
onStoryAchievementInput(e) { this.setData({ storyAchievement: e.detail.value }) },
|
|
|
|
|
|
onStoryTurningInput(e) { this.setData({ storyTurning: e.detail.value }) },
|
|
|
|
|
|
onHelpOfferInput(e) { this.setData({ helpOffer: e.detail.value }) },
|
|
|
|
|
|
onHelpNeedInput(e) { this.setData({ helpNeed: e.detail.value }) },
|
|
|
|
|
|
onProjectIntroInput(e) { this.setData({ projectIntro: e.detail.value }) },
|
|
|
|
|
|
|
|
|
|
|
|
onMbtiPickerChange(e) {
|
|
|
|
|
|
const i = parseInt(e.detail.value, 10)
|
|
|
|
|
|
this.setData({ mbtiIndex: i, mbti: MBTI_OPTIONS[i] })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-12 11:36:50 +08:00
|
|
|
|
// 点击头像:选择微信头像或从相册选择
|
|
|
|
|
|
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() {
|
2026-03-07 22:58:43 +08:00
|
|
|
|
wx.chooseMedia({
|
|
|
|
|
|
count: 1,
|
|
|
|
|
|
mediaType: ['image'],
|
|
|
|
|
|
sourceType: ['album', 'camera'],
|
|
|
|
|
|
success: async (res) => {
|
|
|
|
|
|
const tempPath = res.tempFiles[0].tempFilePath
|
|
|
|
|
|
wx.showLoading({ title: '上传中...', mask: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
const uploadRes = await new Promise((resolve, reject) => {
|
|
|
|
|
|
wx.uploadFile({
|
|
|
|
|
|
url: app.globalData.baseUrl + '/api/miniprogram/upload',
|
|
|
|
|
|
filePath: tempPath,
|
|
|
|
|
|
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' })
|
2026-03-16 16:10:30 +08:00
|
|
|
|
setTimeout(() => this.generateShareCard(), 200)
|
2026-03-07 22:58:43 +08:00
|
|
|
|
} catch (e) {
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: e.message || '上传失败', icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-12 11:36:50 +08:00
|
|
|
|
// 微信原生 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' })
|
2026-03-16 16:10:30 +08:00
|
|
|
|
setTimeout(() => this.generateShareCard(), 200)
|
2026-03-12 11:36:50 +08:00
|
|
|
|
} catch (err) {
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: err.message || '上传失败,请重试', icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-07 22:58:43 +08:00
|
|
|
|
async saveProfile() {
|
|
|
|
|
|
const userId = app.globalData.userInfo?.id
|
|
|
|
|
|
if (!userId) {
|
|
|
|
|
|
wx.showToast({ title: '请先登录', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
this.setData({ saving: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
const s = (v) => (v || '').toString().trim()
|
|
|
|
|
|
const isVip = this.data.isVip
|
|
|
|
|
|
const payload = {
|
|
|
|
|
|
userId,
|
|
|
|
|
|
avatar: s(this.data.avatar),
|
|
|
|
|
|
nickname: s(this.data.nickname),
|
|
|
|
|
|
mbti: s(this.data.mbti),
|
|
|
|
|
|
region: s(this.data.region),
|
|
|
|
|
|
industry: s(this.data.industry),
|
|
|
|
|
|
businessScale: s(this.data.businessScale),
|
|
|
|
|
|
position: s(this.data.position),
|
|
|
|
|
|
phone: s(this.data.phone),
|
|
|
|
|
|
wechatId: s(this.data.wechatId),
|
|
|
|
|
|
}
|
|
|
|
|
|
const showHelp = isVip || this.data.helpOffer || this.data.helpNeed
|
|
|
|
|
|
if (isVip) {
|
|
|
|
|
|
payload.skills = s(this.data.skills)
|
|
|
|
|
|
payload.storyBestMonth = s(this.data.storyBestMonth)
|
|
|
|
|
|
payload.storyAchievement = s(this.data.storyAchievement)
|
|
|
|
|
|
payload.storyTurning = s(this.data.storyTurning)
|
|
|
|
|
|
payload.projectIntro = s(this.data.projectIntro)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (showHelp) {
|
|
|
|
|
|
payload.helpOffer = s(this.data.helpOffer)
|
|
|
|
|
|
payload.helpNeed = s(this.data.helpNeed)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (payload.wechatId) wx.setStorageSync('user_wechat', payload.wechatId)
|
|
|
|
|
|
if (payload.phone) wx.setStorageSync('user_phone', payload.phone)
|
|
|
|
|
|
const hasUpdate = Object.keys(payload).some(k => k !== 'userId' && payload[k] !== '')
|
|
|
|
|
|
if (!hasUpdate) {
|
|
|
|
|
|
wx.showToast({ title: '无变更', icon: 'none' })
|
|
|
|
|
|
this.setData({ saving: false })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
await app.request({
|
|
|
|
|
|
url: '/api/miniprogram/user/profile',
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
data: payload,
|
|
|
|
|
|
})
|
|
|
|
|
|
wx.showToast({ title: '保存成功', icon: 'success' })
|
|
|
|
|
|
if (app.globalData.userInfo) {
|
|
|
|
|
|
if (payload.nickname) app.globalData.userInfo.nickname = payload.nickname
|
|
|
|
|
|
if (payload.avatar) app.globalData.userInfo.avatar = payload.avatar
|
|
|
|
|
|
wx.setStorageSync('userInfo', app.globalData.userInfo)
|
|
|
|
|
|
}
|
|
|
|
|
|
setTimeout(() => getApp().goBackOrToHome(), 800)
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
wx.showToast({ title: e.message || '保存失败', icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
this.setData({ saving: false })
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|