|
|
@@ -65,6 +65,19 @@ const DIMENSION_COLORS = {
|
|
|
wealth: { main: '#F59E0B', dark: '#D97706', light: '#FFFBEB' }
|
|
|
}
|
|
|
|
|
|
+/** 海报画布默认布局(500×800 设计坐标)。模板 layoutConfig 未提供的字段全部回退至此。 */
|
|
|
+const DEFAULT_LAYOUT = {
|
|
|
+ cover: { show: true, x: 28, y: 148, width: 444, height: 202, radius: 12 },
|
|
|
+ card: { show: true, x: 28, width: 444, top: 112, height: 620, radius: 16, bgLight: '#FFFFFF', topPad: 16 },
|
|
|
+ title: { show: true, fontSize: 22, color: '#1C1917', barColor: 'auto', barWidth: 4, lines: 2 },
|
|
|
+ meta: { show: true, columns: 3, gap: 28, labelFontSize: 12, valueFontSize: 14,
|
|
|
+ labelColor: '#A8A29E', valueColor: '#1C1917', rowGap: 28 },
|
|
|
+ intro: { show: true, fontSize: 13, color: '#78716C', lines: 2 },
|
|
|
+ qr: { show: true, size: 100, padding: 8, radius: 8 },
|
|
|
+ invite: { show: true, fontSize: 13, color: '#A8A29E', text: '长按识别二维码 · 立即报名' },
|
|
|
+ footer: { show: true, fontSize: 18, color: 'auto', text: '浠艾福 · 家庭健康俱乐部' }
|
|
|
+}
|
|
|
+
|
|
|
export default {
|
|
|
name: 'ActivityPoster',
|
|
|
props: {
|
|
|
@@ -185,6 +198,22 @@ export default {
|
|
|
var tpl = this.resolvedTemplate
|
|
|
if (tpl && tpl.qrSize && tpl.qrSize > 0) return tpl.qrSize
|
|
|
return this.qrSizeOverride || 100
|
|
|
+ },
|
|
|
+ /** 解析后的布局配置(模板 layoutConfig > 内置默认布局),元素位置/样式可配置 */
|
|
|
+ layout: function() {
|
|
|
+ var merged = this._deepClone(DEFAULT_LAYOUT)
|
|
|
+ var tpl = this.resolvedTemplate
|
|
|
+ if (tpl && tpl.layoutConfig) {
|
|
|
+ try {
|
|
|
+ var cfg = JSON.parse(tpl.layoutConfig)
|
|
|
+ if (cfg && typeof cfg === 'object') {
|
|
|
+ merged = this._mergeLayout(merged, cfg)
|
|
|
+ }
|
|
|
+ } catch (e) { /* 非法 JSON 使用默认布局 */ }
|
|
|
+ }
|
|
|
+ // 二维码尺寸兼容:模板 qrSize 列/override 优先,其次 layout.qr.size
|
|
|
+ if (this.effectiveQrSize > 0) merged.qr.size = this.effectiveQrSize
|
|
|
+ return merged
|
|
|
}
|
|
|
},
|
|
|
data: function() {
|
|
|
@@ -199,6 +228,26 @@ export default {
|
|
|
if (scale > 1.25) scale = 1.25
|
|
|
return Math.round(size * scale)
|
|
|
},
|
|
|
+ _deepClone: function(obj) {
|
|
|
+ return JSON.parse(JSON.stringify(obj || {}))
|
|
|
+ },
|
|
|
+ /** 浅层递归合并:cfg 命中同名字段时覆盖默认值(保留未配置字段) */
|
|
|
+ _mergeLayout: function(base, cfg) {
|
|
|
+ if (!cfg || typeof cfg !== 'object') return base
|
|
|
+ var out = this._deepClone(base)
|
|
|
+ var key
|
|
|
+ for (key in cfg) {
|
|
|
+ if (!Object.prototype.hasOwnProperty.call(cfg, key)) continue
|
|
|
+ var val = cfg[key]
|
|
|
+ if (out[key] && typeof out[key] === 'object' && !Array.isArray(out[key]) &&
|
|
|
+ val && typeof val === 'object' && !Array.isArray(val)) {
|
|
|
+ out[key] = this._mergeLayout(out[key], val)
|
|
|
+ } else if (val !== null && val !== undefined && val !== '') {
|
|
|
+ out[key] = val
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return out
|
|
|
+ },
|
|
|
getActiveTemplate: function() {
|
|
|
if (!this.activeTemplateId) return null
|
|
|
var list = this.serverTemplates
|
|
|
@@ -263,6 +312,7 @@ export default {
|
|
|
var w = 500
|
|
|
var h = 800
|
|
|
var colors = this.colors
|
|
|
+ var L = this.layout
|
|
|
|
|
|
if (scaleX !== 1 || scaleY !== 1) {
|
|
|
ctx.scale(scaleX, scaleY)
|
|
|
@@ -287,12 +337,17 @@ export default {
|
|
|
// 顶部品牌点 + 文字
|
|
|
this._drawBrandHeader(ctx, w, colors)
|
|
|
|
|
|
- // 封面图卡片
|
|
|
- var coverX = 28
|
|
|
- var coverY = 148
|
|
|
- var coverW = 444
|
|
|
- var coverH = 202
|
|
|
+ // 封面图卡片(位置/尺寸/圆角来自 layout.cover,模板可配置)
|
|
|
+ var coverX = L.cover.x
|
|
|
+ var coverY = L.cover.y
|
|
|
+ var coverW = L.cover.width
|
|
|
+ var coverH = L.cover.height
|
|
|
var self = this
|
|
|
+ if (!L.cover.show) {
|
|
|
+ // 模板关闭封面区:信息卡从 cover 起点开始绘制
|
|
|
+ self._drawInfoCard(ctx, coverY, w, colors)
|
|
|
+ return
|
|
|
+ }
|
|
|
if (this.coverImage) {
|
|
|
uni.downloadFile({
|
|
|
url: this.coverImage,
|
|
|
@@ -349,19 +404,31 @@ export default {
|
|
|
ctx.fill()
|
|
|
}
|
|
|
// 品牌文字
|
|
|
- ctx.setFillStyle('rgba(255,255,255,0.9)')
|
|
|
+ ctx.setFillStyle('rgba(255,255,255,0.92)')
|
|
|
ctx.setFontSize(this._fs(14))
|
|
|
ctx.setTextAlign('center')
|
|
|
ctx.setTextBaseline('top')
|
|
|
ctx.fillText('浠艾福 · 家庭健康俱乐部', centerX, dotY + 16)
|
|
|
+ // 品牌分隔细线
|
|
|
+ ctx.setStrokeStyle('rgba(255,255,255,0.28)')
|
|
|
+ ctx.setLineWidth(1)
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.moveTo(96, dotY + 42)
|
|
|
+ ctx.lineTo(w - 96, dotY + 42)
|
|
|
+ ctx.stroke()
|
|
|
+ // 品牌标语
|
|
|
+ ctx.setFillStyle('rgba(255,255,255,0.75)')
|
|
|
+ ctx.setFontSize(this._fs(11))
|
|
|
+ ctx.fillText('给全家的一站式幸福提案', centerX, dotY + 48)
|
|
|
},
|
|
|
|
|
|
_drawCoverPlaceholder: function(ctx, x, y, w, h, colors) {
|
|
|
+ var L = this.layout
|
|
|
var g = ctx.createLinearGradient(x, y, x + w, y + h)
|
|
|
g.addColorStop(0, colors.main)
|
|
|
g.addColorStop(1, colors.dark)
|
|
|
ctx.setFillStyle(g)
|
|
|
- this._roundRect(ctx, x, y, w, h, 12)
|
|
|
+ this._roundRect(ctx, x, y, w, h, L.cover.radius || 12)
|
|
|
ctx.fill()
|
|
|
var cx = x + w / 2
|
|
|
var cy = y + h / 2
|
|
|
@@ -381,138 +448,178 @@ export default {
|
|
|
*/
|
|
|
_drawInfoCard: function(ctx, infoCardY, w, colors) {
|
|
|
var self = this
|
|
|
- var cardX = 28
|
|
|
- var cardW = 444
|
|
|
- var rowGap = 28
|
|
|
- var labelFs = this._fs(12)
|
|
|
- var valueFs = this._fs(14)
|
|
|
- var titleFs = this._fs(22)
|
|
|
- var descFs = this._fs(13)
|
|
|
- var lineH = valueFs + 6
|
|
|
-
|
|
|
- // 白色卡片
|
|
|
- ctx.setFillStyle('#FFFFFF')
|
|
|
- this._roundRect(ctx, cardX, infoCardY, cardW, 210, 12)
|
|
|
- ctx.fill()
|
|
|
-
|
|
|
- var curY = infoCardY + 16
|
|
|
-
|
|
|
- // 类型 tag(用颜色条代替文字)
|
|
|
- ctx.setFillStyle(colors.main)
|
|
|
- ctx.beginPath()
|
|
|
- ctx.roundRect ? ctx.roundRect(cardX + 10, curY, 4, 18, 2) : ctx.rect(cardX + 10, curY, 4, 18)
|
|
|
+ var L = this.layout
|
|
|
+
|
|
|
+ // 卡片参数
|
|
|
+ var cardX = L.card.x || 28
|
|
|
+ var cardW = L.card.width || 444
|
|
|
+ var cardRadius = L.card.radius || 16
|
|
|
+ var cardBgLight = L.card.bgLight || '#FFFFFF'
|
|
|
+ var cardTopPad = L.card.topPad || 16
|
|
|
+
|
|
|
+ // 字号/颜色(按用户字体缩放)
|
|
|
+ var titleFs = this._fs(L.title.fontSize || 22)
|
|
|
+ var titleColor = L.title.color || '#1C1917'
|
|
|
+ var titleLines = L.title.lines || 2
|
|
|
+ var titleBarColor = L.title.barColor === 'auto' ? colors.main : (L.title.barColor || colors.main)
|
|
|
+ var titleBarWidth = L.title.barWidth || 4
|
|
|
+
|
|
|
+ var meta = L.meta
|
|
|
+ var metaCols = meta.columns || 3
|
|
|
+ var metaGap = meta.gap || 28
|
|
|
+ var labelFs = this._fs(meta.labelFontSize || 12)
|
|
|
+ var valueFs = this._fs(meta.valueFontSize || 14)
|
|
|
+ var labelColor = meta.labelColor || '#A8A29E'
|
|
|
+ var valueColor = meta.valueColor || '#1C1917'
|
|
|
+ var rowGap = meta.rowGap || 28
|
|
|
+ var metaLineH = valueFs + 6
|
|
|
+
|
|
|
+ var introFs = this._fs(L.intro.fontSize || 13)
|
|
|
+ var introColor = L.intro.color || '#78716C'
|
|
|
+ var introLines = L.intro.lines || 2
|
|
|
+ var introLineH = introFs + 4
|
|
|
+
|
|
|
+ // 白色卡片(高度由布局配置,默认与信息量匹配)
|
|
|
+ var cardH = L.card.height || 210
|
|
|
+ ctx.setFillStyle(cardBgLight)
|
|
|
+ this._roundRect(ctx, cardX, infoCardY, cardW, cardH, cardRadius)
|
|
|
ctx.fill()
|
|
|
- curY += 28
|
|
|
|
|
|
- // 标题(2行截断)
|
|
|
- ctx.setFillStyle('#1C1917')
|
|
|
- ctx.setFontSize(titleFs)
|
|
|
- ctx.setTextAlign('left')
|
|
|
- ctx.setTextBaseline('top')
|
|
|
- this._drawWrappedText(ctx, this.title || '精彩活动', cardX + 22, curY, cardW - 22, titleFs + 4, 2)
|
|
|
- curY += (titleFs + 4) * 2 + 12
|
|
|
+ var curY = infoCardY + cardTopPad
|
|
|
|
|
|
- // 元信息行:时间 / 地点 / 截止 / 人数 / 费用
|
|
|
- var rows = []
|
|
|
- if (this.startTime) {
|
|
|
- rows.push({ label: '时间', value: this._formatTimeRange() })
|
|
|
- }
|
|
|
- if (this.location) {
|
|
|
- rows.push({ label: '地点', value: this.location.substring(0, 30) })
|
|
|
- }
|
|
|
- if (this.registrationDeadline) {
|
|
|
- rows.push({ label: '截止', value: this._formatDate(this.registrationDeadline) })
|
|
|
- }
|
|
|
- if (this.maxParticipants > 0) {
|
|
|
- rows.push({ label: '人数', value: (this.currentParticipants || 0) + '/' + this.maxParticipants + '人' })
|
|
|
- }
|
|
|
- if (this.priceText) {
|
|
|
- rows.push({ label: '费用', value: this.priceText })
|
|
|
+ // 标题前 accent 竖条
|
|
|
+ if (L.title.show) {
|
|
|
+ ctx.setFillStyle(titleBarColor)
|
|
|
+ ctx.beginPath()
|
|
|
+ var barX = cardX + 10
|
|
|
+ ctx.roundRect ? ctx.roundRect(barX, curY, titleBarWidth, 18, 2) : ctx.rect(barX, curY, titleBarWidth, 18)
|
|
|
+ ctx.fill()
|
|
|
}
|
|
|
+ curY += 28
|
|
|
|
|
|
- var rowCount = rows.length
|
|
|
- var innerPad = 22
|
|
|
- var colW = (cardW - innerPad * 2) / (rowCount <= 2 ? 2 : 3)
|
|
|
- var x = cardX + innerPad
|
|
|
- var y = curY
|
|
|
- var colIndex = 0
|
|
|
- var i, row
|
|
|
- for (i = 0; i < rowCount; i++) {
|
|
|
- row = rows[i]
|
|
|
- if (colIndex >= (rowCount <= 2 ? 2 : 3)) { colIndex = 0; y += lineH + 4 }
|
|
|
- ctx.setFillStyle('#A8A29E')
|
|
|
- ctx.setFontSize(labelFs)
|
|
|
+ // 标题(可配行数/字号/颜色)
|
|
|
+ if (L.title.show) {
|
|
|
+ ctx.setFillStyle(titleColor)
|
|
|
+ ctx.setFontSize(titleFs)
|
|
|
ctx.setTextAlign('left')
|
|
|
ctx.setTextBaseline('top')
|
|
|
- ctx.fillText(row.label, x, y)
|
|
|
- ctx.setFillStyle('#1C1917')
|
|
|
- ctx.setFontSize(valueFs)
|
|
|
- ctx.fillText(row.value, x, y + labelFs + 4)
|
|
|
- x += colW
|
|
|
- colIndex++
|
|
|
+ var titleMaxW = cardW - 22
|
|
|
+ this._drawWrappedText(ctx, this.title || '精彩活动', cardX + 22, curY, titleMaxW, titleFs + 4, titleLines)
|
|
|
+ curY += (titleFs + 4) * titleLines + 12
|
|
|
}
|
|
|
- curY = y + lineH + 8
|
|
|
|
|
|
- // 简介(2行截断,仅当没有封面图或卡片内空间足够时绘制)
|
|
|
- var plainIntro = (this.intro || '').replace(/<[^>]+>/g, ' ').replace(/ /g, ' ').replace(/\s+/g, ' ').trim()
|
|
|
- if (plainIntro) {
|
|
|
- ctx.setFillStyle('#78716C')
|
|
|
- ctx.setFontSize(descFs)
|
|
|
- ctx.setTextAlign('left')
|
|
|
- ctx.setTextBaseline('top')
|
|
|
- this._drawWrappedText(ctx, plainIntro, cardX + innerPad, curY, cardW - innerPad * 2, descFs + 4, 2)
|
|
|
- curY += (descFs + 4) * 2 + 12
|
|
|
+ // 元信息行
|
|
|
+ if (L.meta.show) {
|
|
|
+ var rows = []
|
|
|
+ if (this.startTime) rows.push({ label: '时间', value: this._formatTimeRange() })
|
|
|
+ if (this.location) rows.push({ label: '地点', value: this.location.substring(0, 30) })
|
|
|
+ if (this.registrationDeadline) rows.push({ label: '截止', value: this._formatDate(this.registrationDeadline) })
|
|
|
+ if (this.maxParticipants > 0) rows.push({ label: '人数', value: (this.currentParticipants || 0) + '/' + this.maxParticipants + '人' })
|
|
|
+ if (this.priceText) rows.push({ label: '费用', value: this.priceText })
|
|
|
+
|
|
|
+ var rowCount = rows.length
|
|
|
+ var innerPad = 22
|
|
|
+ var colW = (cardW - innerPad * 2) / (rowCount <= 2 ? Math.min(2, metaCols) : Math.min(3, metaCols))
|
|
|
+ var x = cardX + innerPad
|
|
|
+ var y = curY
|
|
|
+ var colIndex = 0
|
|
|
+ var i, row
|
|
|
+ for (i = 0; i < rowCount; i++) {
|
|
|
+ row = rows[i]
|
|
|
+ if (colIndex >= (rowCount <= 2 ? Math.min(2, metaCols) : Math.min(3, metaCols))) { colIndex = 0; y += metaLineH + 4 }
|
|
|
+ ctx.setFillStyle(labelColor)
|
|
|
+ ctx.setFontSize(labelFs)
|
|
|
+ ctx.setTextAlign('left')
|
|
|
+ ctx.setTextBaseline('top')
|
|
|
+ ctx.fillText(row.label, x, y)
|
|
|
+ ctx.setFillStyle(valueColor)
|
|
|
+ ctx.setFontSize(valueFs)
|
|
|
+ ctx.fillText(row.value, x, y + labelFs + 4)
|
|
|
+ x += colW
|
|
|
+ colIndex++
|
|
|
+ }
|
|
|
+ curY = y + metaLineH + 8
|
|
|
+ }
|
|
|
+
|
|
|
+ // 简介
|
|
|
+ if (L.intro.show) {
|
|
|
+ var plainIntro = (this.intro || '').replace(/<[^>]+>/g, ' ').replace(/ /g, ' ').replace(/\s+/g, ' ').trim()
|
|
|
+ if (plainIntro) {
|
|
|
+ ctx.setFillStyle(introColor)
|
|
|
+ ctx.setFontSize(introFs)
|
|
|
+ ctx.setTextAlign('left')
|
|
|
+ ctx.setTextBaseline('top')
|
|
|
+ this._drawWrappedText(ctx, plainIntro, cardX + 22, curY, cardW - 44, introLineH, introLines)
|
|
|
+ curY += introLineH * introLines + 12
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 二维码区域(卡片下方)
|
|
|
- var qrSize = this.effectiveQrSize
|
|
|
+ var qrSize = L.qr.size || this.effectiveQrSize
|
|
|
+ var qrPadding = L.qr.padding || 8
|
|
|
+ var qrRadius = L.qr.radius || 8
|
|
|
var qrY = curY + 16
|
|
|
var qrX = (w - qrSize) / 2
|
|
|
|
|
|
- // 邀请语
|
|
|
- var inviteY = qrY - 22
|
|
|
- ctx.setFillStyle('#A8A29E')
|
|
|
- ctx.setFontSize(this._fs(13))
|
|
|
- ctx.setTextAlign('center')
|
|
|
- ctx.setTextBaseline('top')
|
|
|
- ctx.fillText(this.inviteText || '长按识别二维码 · 立即报名', w / 2, inviteY)
|
|
|
-
|
|
|
- // 二维码
|
|
|
- if (this.qrCodeBase64) {
|
|
|
- var base64Data = this.qrCodeBase64
|
|
|
- if (base64Data.indexOf('data:image') === 0) {
|
|
|
- var commaIdx = base64Data.indexOf(',')
|
|
|
- if (commaIdx > -1) base64Data = base64Data.substring(commaIdx + 1)
|
|
|
- }
|
|
|
- var fs = uni.getFileSystemManager()
|
|
|
- var filePath = wx.env.USER_DATA_PATH + '/activity_qr_tmp.png'
|
|
|
- fs.writeFile({
|
|
|
- filePath: filePath,
|
|
|
- data: base64Data,
|
|
|
- encoding: 'base64',
|
|
|
- success: function() {
|
|
|
- ctx.setFillStyle('BrandColors.white')
|
|
|
- self._roundRect(ctx, qrX - 8, qrY - 8, qrSize + 16, qrSize + 16, 8)
|
|
|
- ctx.fill()
|
|
|
- ctx.setStrokeStyle('#E7E5E4')
|
|
|
- ctx.setLineWidth(0.5)
|
|
|
- self._roundRect(ctx, qrX - 8, qrY - 8, qrSize + 16, qrSize + 16, 8)
|
|
|
- ctx.stroke()
|
|
|
- ctx.drawImage(filePath, qrX, qrY, qrSize, qrSize)
|
|
|
- self._drawFooter(ctx, w, qrY + qrSize + 16, colors)
|
|
|
- },
|
|
|
- fail: function() {
|
|
|
- self._drawQrPlaceholder(ctx, qrX, qrY, qrSize)
|
|
|
- self._drawFooter(ctx, w, qrY + qrSize + 16, colors)
|
|
|
+ // 邀请语(二维码上方)
|
|
|
+ if (L.invite.show) {
|
|
|
+ var inviteY = qrY - 22
|
|
|
+ ctx.setFillStyle(L.invite.color || '#A8A29E')
|
|
|
+ ctx.setFontSize(this._fs(L.invite.fontSize || 13))
|
|
|
+ ctx.setTextAlign('center')
|
|
|
+ ctx.setTextBaseline('top')
|
|
|
+ ctx.fillText(L.invite.text || this.inviteText || '长按识别二维码 · 立即报名', w / 2, inviteY)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 二维码(白底圆角卡片 + 绘制)
|
|
|
+ if (L.qr.show) {
|
|
|
+ if (this.qrCodeBase64) {
|
|
|
+ var base64Data = this.qrCodeBase64
|
|
|
+ if (base64Data.indexOf('data:image') === 0) {
|
|
|
+ var commaIdx = base64Data.indexOf(',')
|
|
|
+ if (commaIdx > -1) base64Data = base64Data.substring(commaIdx + 1)
|
|
|
}
|
|
|
- })
|
|
|
+ var fs = uni.getFileSystemManager()
|
|
|
+ var filePath = wx.env.USER_DATA_PATH + '/activity_qr_tmp.png'
|
|
|
+ fs.writeFile({
|
|
|
+ filePath: filePath,
|
|
|
+ data: base64Data,
|
|
|
+ encoding: 'base64',
|
|
|
+ success: function() {
|
|
|
+ // 白底圆角卡片
|
|
|
+ ctx.setFillStyle('#FFFFFF')
|
|
|
+ self._roundRect(ctx, qrX - qrPadding, qrY - qrPadding, qrSize + qrPadding * 2, qrSize + qrPadding * 2, qrRadius)
|
|
|
+ ctx.fill()
|
|
|
+ // 淡边框
|
|
|
+ ctx.setStrokeStyle('#E7E5E4')
|
|
|
+ ctx.setLineWidth(0.5)
|
|
|
+ self._roundRect(ctx, qrX - qrPadding, qrY - qrPadding, qrSize + qrPadding * 2, qrSize + qrPadding * 2, qrRadius)
|
|
|
+ ctx.stroke()
|
|
|
+ // 二维码
|
|
|
+ ctx.drawImage(filePath, qrX, qrY, qrSize, qrSize)
|
|
|
+ // CTA 胶囊按钮(二维码下方)
|
|
|
+ self._drawCtaCapsule(ctx, w, qrY + qrSize + qrPadding + 12, colors)
|
|
|
+ // Footer
|
|
|
+ self._drawFooter(ctx, w, qrY + qrSize + qrPadding + 60, colors)
|
|
|
+ },
|
|
|
+ fail: function() {
|
|
|
+ self._drawQrPlaceholder(ctx, qrX, qrY, qrSize, L)
|
|
|
+ self._drawFooter(ctx, w, qrY + qrSize + 16, colors)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ this._drawQrPlaceholder(ctx, qrX, qrY, qrSize, L)
|
|
|
+ this._drawFooter(ctx, w, qrY + qrSize + 16, colors)
|
|
|
+ }
|
|
|
} else {
|
|
|
- this._drawQrPlaceholder(ctx, qrX, qrY, qrSize)
|
|
|
- this._drawFooter(ctx, w, qrY + qrSize + 16, colors)
|
|
|
+ // 无二维码区直接画 footer
|
|
|
+ self._drawFooter(ctx, w, qrY + 8, colors)
|
|
|
}
|
|
|
},
|
|
|
|
|
|
_drawFooter: function(ctx, w, topY, colors) {
|
|
|
+ var L = this.layout
|
|
|
+ if (!L.footer.show) return
|
|
|
var brandY = topY + 8
|
|
|
ctx.setFillStyle('rgba(0,0,0,0.08)')
|
|
|
ctx.beginPath()
|
|
|
@@ -530,20 +637,50 @@ export default {
|
|
|
ctx.closePath()
|
|
|
ctx.fill()
|
|
|
|
|
|
- ctx.setFillStyle(colors.main)
|
|
|
- ctx.setFontSize(this._fs(18))
|
|
|
+ ctx.setFillStyle(L.footer.color === 'auto' ? colors.main : (L.footer.color || colors.main))
|
|
|
+ ctx.setFontSize(this._fs(L.footer.fontSize || 18))
|
|
|
ctx.setTextAlign('center')
|
|
|
ctx.setTextBaseline('top')
|
|
|
- ctx.fillText('浠艾福 · 家庭健康俱乐部', w / 2, brandY + 14)
|
|
|
+ ctx.fillText(L.footer.text || '浠艾福 · 家庭健康俱乐部', w / 2, brandY + 14)
|
|
|
+ },
|
|
|
+
|
|
|
+ /** CTA 胶囊按钮(二维码下方,品牌主色描边+白底小胶囊,比纯文字更有行动感) */
|
|
|
+ _drawCtaCapsule: function(ctx, w, topY, colors) {
|
|
|
+ var centerX = w / 2
|
|
|
+ var text = '立即报名'
|
|
|
+ ctx.setFontSize(this._fs(14))
|
|
|
+ var textW = this._textWidth(ctx, text)
|
|
|
+ if (textW > 70) textW = 70
|
|
|
+ var padX = 18
|
|
|
+ var btnW = textW + padX * 2
|
|
|
+ var btnH = 36
|
|
|
+ var x = centerX - btnW / 2
|
|
|
+ var y = topY
|
|
|
+ // 胶囊底(半透明白) + 主色描边
|
|
|
+ ctx.setFillStyle('rgba(255,255,255,0.9)')
|
|
|
+ this._roundRect(ctx, x, y, btnW, btnH, btnH / 2)
|
|
|
+ ctx.fill()
|
|
|
+ ctx.setStrokeStyle(colors.main)
|
|
|
+ ctx.setLineWidth(1)
|
|
|
+ this._roundRect(ctx, x, y, btnW, btnH, btnH / 2)
|
|
|
+ ctx.stroke()
|
|
|
+ // 文字
|
|
|
+ ctx.setFillStyle(colors.dark)
|
|
|
+ ctx.setFontSize(this._fs(14))
|
|
|
+ ctx.setTextAlign('center')
|
|
|
+ ctx.setTextBaseline('middle')
|
|
|
+ ctx.fillText(text, centerX, y + btnH / 2 + 1)
|
|
|
},
|
|
|
|
|
|
- _drawQrPlaceholder: function(ctx, x, y, size) {
|
|
|
+ _drawQrPlaceholder: function(ctx, x, y, size, L) {
|
|
|
+ var pad = (L && L.qr && L.qr.padding) || 8
|
|
|
+ var radius = (L && L.qr && L.qr.radius) || 8
|
|
|
ctx.setFillStyle('#FFFFFF')
|
|
|
- this._roundRect(ctx, x - 8, y - 8, size + 16, size + 16, 8)
|
|
|
+ this._roundRect(ctx, x - pad, y - pad, size + pad * 2, size + pad * 2, radius)
|
|
|
ctx.fill()
|
|
|
ctx.setStrokeStyle('#E7E5E4')
|
|
|
ctx.setLineWidth(0.5)
|
|
|
- this._roundRect(ctx, x - 8, y - 8, size + 16, size + 16, 8)
|
|
|
+ this._roundRect(ctx, x - pad, y - pad, size + pad * 2, size + pad * 2, radius)
|
|
|
ctx.stroke()
|
|
|
ctx.setFillStyle('#A8A29E')
|
|
|
ctx.setFontSize(this._fs(14))
|