|
@@ -17,7 +17,6 @@ export default {
|
|
|
show: { type: Boolean, default: false },
|
|
show: { type: Boolean, default: false },
|
|
|
userAvatar: { type: String, default: '' },
|
|
userAvatar: { type: String, default: '' },
|
|
|
nickname: { type: String, default: '' },
|
|
nickname: { type: String, default: '' },
|
|
|
- referralCode: { type: String, default: '' },
|
|
|
|
|
familyName: { type: String, default: '' },
|
|
familyName: { type: String, default: '' },
|
|
|
qrCodeBase64: { type: String, default: '' }
|
|
qrCodeBase64: { type: String, default: '' }
|
|
|
},
|
|
},
|
|
@@ -37,10 +36,32 @@ export default {
|
|
|
// ENTRY POINT
|
|
// ENTRY POINT
|
|
|
// ============================================================
|
|
// ============================================================
|
|
|
drawPoster() {
|
|
drawPoster() {
|
|
|
|
|
+ var self = this
|
|
|
|
|
+ uni.createSelectorQuery().in(this)
|
|
|
|
|
+ .select('#sharePosterCanvas')
|
|
|
|
|
+ .boundingClientRect(function(rect) {
|
|
|
|
|
+ var scaleX = 1
|
|
|
|
|
+ var scaleY = 1
|
|
|
|
|
+ if (rect && rect.width && rect.height) {
|
|
|
|
|
+ scaleX = rect.width / 500
|
|
|
|
|
+ scaleY = rect.height / 750
|
|
|
|
|
+ }
|
|
|
|
|
+ self._renderPoster(scaleX, scaleY)
|
|
|
|
|
+ })
|
|
|
|
|
+ .exec()
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ _renderPoster(scaleX, scaleY) {
|
|
|
var ctx = uni.createCanvasContext('sharePosterCanvas', this)
|
|
var ctx = uni.createCanvasContext('sharePosterCanvas', this)
|
|
|
var w = 500
|
|
var w = 500
|
|
|
var h = 750
|
|
var h = 750
|
|
|
|
|
|
|
|
|
|
+ // 画布 CSS 用 rpx,实际像素随设备变化(375px 屏约 310x465),而绘制按 500x750 设计坐标;
|
|
|
|
|
+ // 不缩放坐标系时右侧/底部内容(含二维码)会被裁剪出画布,导致海报显示不全。
|
|
|
|
|
+ if (scaleX !== 1 || scaleY !== 1) {
|
|
|
|
|
+ ctx.scale(scaleX, scaleY)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 1. Background gradient — warm orange
|
|
// 1. Background gradient — warm orange
|
|
|
var gradient = ctx.createLinearGradient(0, 0, w * 0.3, h)
|
|
var gradient = ctx.createLinearGradient(0, 0, w * 0.3, h)
|
|
|
gradient.addColorStop(0, '#F97316')
|
|
gradient.addColorStop(0, '#F97316')
|
|
@@ -54,15 +75,15 @@ export default {
|
|
|
|
|
|
|
|
// 3. White/cream content card
|
|
// 3. White/cream content card
|
|
|
var cardX = 28
|
|
var cardX = 28
|
|
|
- var cardY = 112
|
|
|
|
|
|
|
+ var cardY = 108
|
|
|
var cardW = 444
|
|
var cardW = 444
|
|
|
- var cardH = 528
|
|
|
|
|
|
|
+ var cardH = 496
|
|
|
this._drawContentCard(ctx, cardX, cardY, cardW, cardH)
|
|
this._drawContentCard(ctx, cardX, cardY, cardW, cardH)
|
|
|
|
|
|
|
|
// 4. Avatar decorative frame (drawn before async avatar download)
|
|
// 4. Avatar decorative frame (drawn before async avatar download)
|
|
|
var avatarX = w / 2
|
|
var avatarX = w / 2
|
|
|
- var avatarY = cardY + 62
|
|
|
|
|
- var avatarR = 48
|
|
|
|
|
|
|
+ var avatarY = cardY + 72
|
|
|
|
|
+ var avatarR = 52
|
|
|
this._drawAvatarFrame(ctx, avatarX, avatarY, avatarR)
|
|
this._drawAvatarFrame(ctx, avatarX, avatarY, avatarR)
|
|
|
|
|
|
|
|
// 5. Download avatar (async) then draw remaining content
|
|
// 5. Download avatar (async) then draw remaining content
|
|
@@ -254,71 +275,61 @@ export default {
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
// ============================================================
|
|
// ============================================================
|
|
|
- // CONTENT AFTER AVATAR — nickname, referral code, QR code, CTA
|
|
|
|
|
|
|
+ // NICKNAME TRUNCATION — 昵称过长时截断,避免标题溢出海报
|
|
|
|
|
+ // ============================================================
|
|
|
|
|
+ _shortName(name, max) {
|
|
|
|
|
+ var s = (name || '').trim()
|
|
|
|
|
+ if (!s) return ''
|
|
|
|
|
+ if (s.length <= max) return s
|
|
|
|
|
+ return s.substring(0, max) + '…'
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // ============================================================
|
|
|
|
|
+ // HEADLINE + INTRO + QR — 邀请标题 + 简单介绍 + 二维码(不展示邀请码)
|
|
|
// ============================================================
|
|
// ============================================================
|
|
|
_drawContentAfterAvatar(ctx, w, h, _cardX, _cardW, _avatarX, avatarY) {
|
|
_drawContentAfterAvatar(ctx, w, h, _cardX, _cardW, _avatarX, avatarY) {
|
|
|
var self = this
|
|
var self = this
|
|
|
var base64Data, commaIdx, fs, filePath
|
|
var base64Data, commaIdx, fs, filePath
|
|
|
|
|
+ var centerX = w / 2
|
|
|
|
|
|
|
|
- // --- Nickname ---
|
|
|
|
|
- var nameY = avatarY + 70
|
|
|
|
|
|
|
+ // --- 邀请标题:XXX邀请你关注家庭健康 ---
|
|
|
|
|
+ var name = this._shortName(this.nickname, 8)
|
|
|
|
|
+ var headlineY = avatarY + 78
|
|
|
ctx.setFillStyle('#1C1917')
|
|
ctx.setFillStyle('#1C1917')
|
|
|
- ctx.setFontSize(22)
|
|
|
|
|
- ctx.setTextAlign('center')
|
|
|
|
|
- ctx.setTextBaseline('top')
|
|
|
|
|
- ctx.fillText(this.nickname || '好友', w / 2, nameY)
|
|
|
|
|
-
|
|
|
|
|
- // --- "我的邀请码" label ---
|
|
|
|
|
- var labelY = nameY + 42
|
|
|
|
|
- ctx.setFontSize(15)
|
|
|
|
|
- ctx.setFillStyle('#A8A29E')
|
|
|
|
|
- ctx.fillText('我的邀请码', w / 2, labelY)
|
|
|
|
|
-
|
|
|
|
|
- // --- Referral code (prominent, warm orange) ---
|
|
|
|
|
- var codeY = labelY + 38
|
|
|
|
|
- var codeText = this.referralCode || '------'
|
|
|
|
|
- ctx.setFontSize(44)
|
|
|
|
|
- ctx.setFillStyle('#F97316')
|
|
|
|
|
|
|
+ ctx.setFontSize(21)
|
|
|
ctx.setTextAlign('center')
|
|
ctx.setTextAlign('center')
|
|
|
ctx.setTextBaseline('top')
|
|
ctx.setTextBaseline('top')
|
|
|
|
|
+ ctx.fillText(name ? name + '邀请你关注家庭健康' : '邀请你关注家庭健康', centerX, headlineY)
|
|
|
|
|
|
|
|
- // Gentle underline accent
|
|
|
|
|
- var codeWidth = 0
|
|
|
|
|
- if (ctx.measureText) {
|
|
|
|
|
- try { codeWidth = ctx.measureText(codeText).width } catch (e) { codeWidth = codeText.length * 26 }
|
|
|
|
|
- } else {
|
|
|
|
|
- codeWidth = codeText.length * 26
|
|
|
|
|
- }
|
|
|
|
|
- var underlineY = codeY + 54
|
|
|
|
|
- ctx.setStrokeStyle('rgba(249,115,22,0.12)')
|
|
|
|
|
- ctx.setLineWidth(2)
|
|
|
|
|
|
|
+ // --- 标题下的短分隔线 ---
|
|
|
|
|
+ var dividerY = headlineY + 36
|
|
|
|
|
+ ctx.setStrokeStyle('rgba(249,115,22,0.35)')
|
|
|
|
|
+ ctx.setLineWidth(1.5)
|
|
|
ctx.beginPath()
|
|
ctx.beginPath()
|
|
|
- ctx.moveTo(w / 2 - codeWidth / 2 - 8, underlineY)
|
|
|
|
|
- ctx.lineTo(w / 2 + codeWidth / 2 + 8, underlineY)
|
|
|
|
|
|
|
+ ctx.moveTo(centerX - 22, dividerY)
|
|
|
|
|
+ ctx.lineTo(centerX + 22, dividerY)
|
|
|
ctx.stroke()
|
|
ctx.stroke()
|
|
|
|
|
|
|
|
- ctx.fillText(codeText, w / 2, codeY)
|
|
|
|
|
|
|
+ // --- 简单介绍:品牌 / 五维 / 定位 ---
|
|
|
|
|
+ var brandY = dividerY + 14
|
|
|
|
|
+ ctx.setFillStyle('#F97316')
|
|
|
|
|
+ ctx.setFontSize(14)
|
|
|
|
|
+ ctx.fillText(this.familyName ? this.familyName + ' · 家庭健康俱乐部' : '浠艾福 · 家庭健康俱乐部', centerX, brandY)
|
|
|
|
|
|
|
|
- // --- 邀请文案(二维码上方)---
|
|
|
|
|
- var hintY = codeY + 80
|
|
|
|
|
- ctx.setFontSize(12)
|
|
|
|
|
- ctx.setFillStyle('#D6D3D1')
|
|
|
|
|
- ctx.setTextAlign('center')
|
|
|
|
|
- ctx.setTextBaseline('top')
|
|
|
|
|
- var inviteText = ''
|
|
|
|
|
- if (this.nickname && this.familyName) {
|
|
|
|
|
- inviteText = this.nickname + '邀请你来' + this.familyName
|
|
|
|
|
- } else if (this.nickname) {
|
|
|
|
|
- inviteText = this.nickname + '邀请你加入浠艾福'
|
|
|
|
|
- } else {
|
|
|
|
|
- inviteText = '长按识别二维码 · 一起加入浠艾福'
|
|
|
|
|
- }
|
|
|
|
|
- ctx.fillText(inviteText, w / 2, hintY)
|
|
|
|
|
|
|
+ var dimY = brandY + 24
|
|
|
|
|
+ ctx.setFillStyle('#78716C')
|
|
|
|
|
+ ctx.setFontSize(13)
|
|
|
|
|
+ ctx.fillText('身体 · 心理 · 智慧 · 行动 · 财富', centerX, dimY)
|
|
|
|
|
+
|
|
|
|
|
+ var descY = dimY + 22
|
|
|
|
|
+ ctx.setFillStyle('#A8A29E')
|
|
|
|
|
+ ctx.setFontSize(13)
|
|
|
|
|
+ ctx.fillText('一家专注全家健康的成长平台', centerX, descY)
|
|
|
|
|
|
|
|
// --- QR code ---
|
|
// --- QR code ---
|
|
|
var qrSize = 180
|
|
var qrSize = 180
|
|
|
var qrX = (w - qrSize) / 2
|
|
var qrX = (w - qrSize) / 2
|
|
|
- var qrY = hintY + 26
|
|
|
|
|
|
|
+ var qrY = descY + 24
|
|
|
|
|
|
|
|
if (this.qrCodeBase64) {
|
|
if (this.qrCodeBase64) {
|
|
|
base64Data = this.qrCodeBase64
|
|
base64Data = this.qrCodeBase64
|
|
@@ -414,7 +425,7 @@ export default {
|
|
|
ctx.setFontSize(17)
|
|
ctx.setFontSize(17)
|
|
|
ctx.setTextAlign('center')
|
|
ctx.setTextAlign('center')
|
|
|
ctx.setTextBaseline('top')
|
|
ctx.setTextBaseline('top')
|
|
|
- ctx.fillText('扫码邀请好友加入', centerX, bottomY)
|
|
|
|
|
|
|
+ ctx.fillText('长按识别二维码,了解浠艾福', centerX, bottomY)
|
|
|
|
|
|
|
|
// 5 dimension dots in the bottom area (outside card)
|
|
// 5 dimension dots in the bottom area (outside card)
|
|
|
var dotColors = ['#FF8C42', '#6366F1', '#F59E0B', '#10B981', '#FF6B9D']
|
|
var dotColors = ['#FF8C42', '#6366F1', '#F59E0B', '#10B981', '#FF6B9D']
|
|
@@ -449,6 +460,8 @@ export default {
|
|
|
var self = this
|
|
var self = this
|
|
|
uni.canvasToTempFilePath({
|
|
uni.canvasToTempFilePath({
|
|
|
canvasId: 'sharePosterCanvas',
|
|
canvasId: 'sharePosterCanvas',
|
|
|
|
|
+ destWidth: 500,
|
|
|
|
|
+ destHeight: 750,
|
|
|
success: function(res) {
|
|
success: function(res) {
|
|
|
uni.saveImageToPhotosAlbum({
|
|
uni.saveImageToPhotosAlbum({
|
|
|
filePath: res.tempFilePath,
|
|
filePath: res.tempFilePath,
|
|
@@ -502,14 +515,14 @@ export default {
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
}
|
|
}
|
|
|
.poster-canvas {
|
|
.poster-canvas {
|
|
|
- width: 500px;
|
|
|
|
|
- height: 750px;
|
|
|
|
|
|
|
+ width: 620rpx;
|
|
|
|
|
+ height: 930rpx;
|
|
|
border-radius: 16rpx;
|
|
border-radius: 16rpx;
|
|
|
}
|
|
}
|
|
|
.poster-actions {
|
|
.poster-actions {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
|
- width: 500px;
|
|
|
|
|
|
|
+ width: 620rpx;
|
|
|
margin-top: 30rpx;
|
|
margin-top: 30rpx;
|
|
|
}
|
|
}
|
|
|
.poster-btn {
|
|
.poster-btn {
|