feat(miniprogram): 用 karuo-316 替换小程序目录

- 从 github/karuo-316 覆盖 miniprogram/
- 排除 project.private.config.json 与 *.backup

Made-with: Cursor
This commit is contained in:
卡若
2026-03-17 18:25:24 +08:00
parent 982622368a
commit 34f7c7bbdc
34 changed files with 450 additions and 891 deletions

View File

@@ -18,7 +18,6 @@ Page({
isVip: false,
avatar: '',
nickname: '',
shareCardPath: '', // 分享名片封面图(预生成)
mbti: '',
mbtiIndex: 0,
region: '',
@@ -41,15 +40,8 @@ Page({
showAvatarModal: false,
},
onLoad(options) {
onLoad() {
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 44 })
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
}
this.loadProfile()
},
@@ -93,7 +85,6 @@ Page({
projectIntro: v('projectIntro'),
loading: false,
})
setTimeout(() => this.generateShareCard(), 200)
} else {
this.setData({ loading: false })
}
@@ -104,167 +95,6 @@ Page({
goBack() { getApp().goBackOrToHome() },
// 生成分享名片封面图(参考:头像左+昵称右,分隔线,四栏信息 5:4
async generateShareCard() {
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
const pad = 32
// 背景(深灰卡片感)
const grd = ctx.createLinearGradient(0, 0, w, h)
grd.addColorStop(0, '#1E293B')
grd.addColorStop(1, '#0F172A')
ctx.setFillStyle(grd)
ctx.fillRect(0, 0, w, h)
// 顶部区域:左头像 + 右昵称
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({
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()
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(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',
destWidth: 500,
destHeight: 400,
success: (res) => {
this.setData({ shareCardPath: res.tempFilePath })
},
}, this)
})
} catch (e) {
console.warn('[ShareCard] 生成失败:', e)
}
},
drawAvatarPlaceholder(ctx, x, y, size, nickname) {
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.42)
ctx.setTextAlign('center')
ctx.fillText((nickname || '?')[0], x + size / 2, y + size / 2 + size * 0.14)
},
onShareAppMessage() {
const ref = app.getMyReferralCode()
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,
}
if (this.data.shareCardPath) result.imageUrl = this.data.shareCardPath
return result
},
onShareTimeline() {
const ref = app.getMyReferralCode()
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
},
onNicknameInput(e) { this.setData({ nickname: e.detail.value }) },
onNicknameChange(e) { this.setData({ nickname: e.detail.value }) },
onRegionInput(e) { this.setData({ region: e.detail.value }) },
@@ -344,7 +174,6 @@ Page({
}
wx.hideLoading()
wx.showToast({ title: '头像已更新', icon: 'success' })
setTimeout(() => this.generateShareCard(), 200)
} catch (e) {
wx.hideLoading()
wx.showToast({ title: e.message || '上传失败', icon: 'none' })
@@ -394,7 +223,6 @@ Page({
}
wx.hideLoading()
wx.showToast({ title: '头像已更新', icon: 'success' })
setTimeout(() => this.generateShareCard(), 200)
} catch (err) {
wx.hideLoading()
wx.showToast({ title: err.message || '上传失败,请重试', icon: 'none' })

View File

@@ -146,9 +146,6 @@
<view class="bottom-space"></view>
</scroll-view>
<!-- 分享名片 canvas隐藏用于生成分享图 5:4 -->
<canvas canvas-id="shareCardCanvas" class="share-card-canvas" style="width: 500px; height: 400px;"></canvas>
<!-- 头像弹窗:通过 button 获取微信头像 -->
<view class="modal-overlay" wx:if="{{showAvatarModal}}" bindtap="closeAvatarModal">
<view class="modal-content avatar-modal" catchtap="stopPropagation">

View File

@@ -1,9 +1,4 @@
/* 资料编辑 - comprehensive_profile_editor_v1_1 | 配色 enhancedinput/textarea 用 view 包裹 */
/* 分享名片 canvas隐藏仅用于生成图片 */
.share-card-canvas {
position: fixed; left: -9999px; top: 0; width: 500px; height: 400px;
}
.page {
background: #050B14; min-height: 100vh; color: #fff;
width: 100%; box-sizing: border-box; overflow-x: hidden;
@@ -168,11 +163,8 @@
.btn-choose-avatar {
width: 100%;
height: 88rpx;
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
line-height: 88rpx;
text-align: center;
background: #5EEAD4;
color: #050B14;
font-size: 30rpx;