Enhance profile editing and sharing functionality
- Added a new feature for sharing profile cards, including special handling for forwarding to friends and displaying a canvas cover with user information. - Updated the mini program's profile-edit page to generate a shareable card with a structured layout, including user avatar, nickname, and additional information. - Improved the documentation to reflect the new sharing capabilities and updated the last modified date for relevant entries.
This commit is contained in:
@@ -104,30 +104,28 @@ Page({
|
||||
|
||||
goBack() { getApp().goBackOrToHome() },
|
||||
|
||||
// 生成分享名片封面图(头像+昵称,5:4 比例)
|
||||
// 生成分享名片封面图(参考:头像左+昵称右,分隔线,四栏信息 5:4)
|
||||
async generateShareCard() {
|
||||
const { avatar, nickname } = this.data
|
||||
const { avatar, nickname, region, mbti, industry, position } = this.data
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId) return
|
||||
try {
|
||||
const ctx = wx.createCanvasContext('shareCardCanvas', this)
|
||||
const w = 500
|
||||
const h = 400
|
||||
// 背景渐变(Soul 深色风格)
|
||||
const pad = 32
|
||||
// 背景(深灰卡片感)
|
||||
const grd = ctx.createLinearGradient(0, 0, w, h)
|
||||
grd.addColorStop(0, '#0F172A')
|
||||
grd.addColorStop(0.5, '#050B14')
|
||||
grd.addColorStop(0, '#1E293B')
|
||||
grd.addColorStop(1, '#0F172A')
|
||||
ctx.setFillStyle(grd)
|
||||
ctx.fillRect(0, 0, w, h)
|
||||
// 顶部装饰条
|
||||
ctx.setFillStyle('#5EEAD4')
|
||||
ctx.fillRect(0, 0, w, 4)
|
||||
// 头像:居中偏上,圆形 120px
|
||||
const avatarSize = 120
|
||||
const avatarX = (w - avatarSize) / 2
|
||||
const avatarY = 80
|
||||
// 顶部区域:左头像 + 右昵称
|
||||
const avatarSize = 100
|
||||
const avatarX = pad + 10
|
||||
const avatarY = 50
|
||||
const avatarRadius = avatarSize / 2
|
||||
const rightStart = avatarX + avatarSize + 28
|
||||
const drawAvatar = () => new Promise((resolve) => {
|
||||
if (avatar && avatar.startsWith('http')) {
|
||||
wx.downloadFile({
|
||||
@@ -156,22 +154,61 @@ Page({
|
||||
}
|
||||
})
|
||||
await drawAvatar()
|
||||
// 头像外圈描边
|
||||
ctx.setStrokeStyle('#5EEAD4')
|
||||
ctx.setLineWidth(3)
|
||||
ctx.setStrokeStyle('rgba(94,234,212,0.5)')
|
||||
ctx.setLineWidth(2)
|
||||
ctx.beginPath()
|
||||
ctx.arc(avatarX + avatarRadius, avatarY + avatarRadius, avatarRadius, 0, Math.PI * 2)
|
||||
ctx.stroke()
|
||||
// 昵称
|
||||
// 右侧:昵称 + 个人名片
|
||||
const displayName = (nickname || '').trim() || '创业者'
|
||||
ctx.setFillStyle('#ffffff')
|
||||
ctx.setFontSize(24)
|
||||
ctx.setTextAlign('center')
|
||||
ctx.fillText(displayName, w / 2, avatarY + avatarSize + 50)
|
||||
// 副标题
|
||||
ctx.setFillStyle('rgba(94,234,212,0.9)')
|
||||
ctx.setFontSize(14)
|
||||
ctx.fillText('Soul创业派对 · 名片', w / 2, avatarY + avatarSize + 78)
|
||||
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)
|
||||
})
|
||||
ctx.draw(true, () => {
|
||||
wx.canvasToTempFilePath({
|
||||
canvasId: 'shareCardCanvas',
|
||||
@@ -188,14 +225,14 @@ Page({
|
||||
},
|
||||
|
||||
drawAvatarPlaceholder(ctx, x, y, size, nickname) {
|
||||
ctx.setFillStyle('rgba(94,234,212,0.25)')
|
||||
ctx.setFillStyle('rgba(94,234,212,0.2)')
|
||||
ctx.beginPath()
|
||||
ctx.arc(x + size / 2, y + size / 2, size / 2, 0, Math.PI * 2)
|
||||
ctx.fill()
|
||||
ctx.setFillStyle('#5EEAD4')
|
||||
ctx.setFontSize(size * 0.45)
|
||||
ctx.setFontSize(size * 0.42)
|
||||
ctx.setTextAlign('center')
|
||||
ctx.fillText((nickname || '?')[0], x + size / 2, y + size / 2 + size * 0.15)
|
||||
ctx.fillText((nickname || '?')[0], x + size / 2, y + size / 2 + size * 0.14)
|
||||
},
|
||||
|
||||
onShareAppMessage() {
|
||||
|
||||
Reference in New Issue
Block a user