feat: add reportPosterDraw utility

This commit is contained in:
MaDaLei 2026-04-13 18:51:35 +08:00
parent ebaae1a929
commit a332e6204b

View File

@ -0,0 +1,173 @@
/** 洗美报告分享海报绘制H5 / 小程序 canvas 2d 共用逻辑) */
export const POSTER_W = 750
export const POSTER_H = 1100
export function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath()
ctx.moveTo(x + r, y)
ctx.lineTo(x + w - r, y)
ctx.quadraticCurveTo(x + w, y, x + w, y + r)
ctx.lineTo(x + w, y + h - r)
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h)
ctx.lineTo(x + r, y + h)
ctx.quadraticCurveTo(x, y + h, x, y + h - r)
ctx.lineTo(x, y + r)
ctx.quadraticCurveTo(x, y, x + r, y)
ctx.closePath()
}
/**
* @param {CanvasRenderingContext2D} ctx
* @param {{
* storeName: string
* storePhone: string
* storeAddr: string
* petName: string
* serviceType: string
* timeStr: string
* staffName: string
* remark: string
* beforeImg: any | null
* afterImg: any | null
* }} data
*/
export function drawReportPoster(ctx, data) {
const {
storeName,
storePhone,
storeAddr,
petName,
serviceType,
timeStr,
staffName,
remark,
beforeImg,
afterImg
} = data
ctx.fillStyle = '#ffffff'
ctx.fillRect(0, 0, POSTER_W, POSTER_H)
const gradient = ctx.createLinearGradient(0, 0, POSTER_W, 300)
gradient.addColorStop(0, '#07c160')
gradient.addColorStop(1, '#10b76f')
ctx.fillStyle = gradient
ctx.fillRect(0, 0, POSTER_W, 300)
const name = storeName || '宠伴生活馆'
ctx.fillStyle = '#ffffff'
ctx.font = 'bold 36px sans-serif'
ctx.textAlign = 'center'
ctx.fillText(name, POSTER_W / 2, 70)
ctx.font = '20px sans-serif'
ctx.globalAlpha = 0.7
ctx.fillText('宠物服务,让爱更专业', POSTER_W / 2, 105)
ctx.globalAlpha = 1
if (storePhone || storeAddr) {
ctx.font = '18px sans-serif'
ctx.globalAlpha = 0.85
const contactLine = [storePhone, storeAddr].filter(Boolean).join(' | ')
ctx.fillText(contactLine, POSTER_W / 2, 138)
ctx.globalAlpha = 1
}
ctx.fillStyle = '#333333'
ctx.font = 'bold 36px sans-serif'
ctx.fillText('服务报告', POSTER_W / 2, 220)
ctx.fillStyle = '#f8f6f3'
ctx.beginPath()
roundRect(ctx, 40, 260, 670, 220, 20)
ctx.fill()
const infoItems = [
['宠物名字', petName || '-'],
['服务项目', serviceType || '-'],
['服务时间', timeStr || '-'],
['服务技师', staffName || '-']
]
let y = 310
ctx.textAlign = 'left'
infoItems.forEach(([label, val]) => {
ctx.fillStyle = '#999999'
ctx.font = '22px sans-serif'
ctx.fillText(label, 80, y)
ctx.fillStyle = '#333333'
ctx.font = 'bold 24px sans-serif'
ctx.fillText(String(val), 220, y)
y += 48
})
ctx.fillStyle = '#f8f6f3'
ctx.beginPath()
roundRect(ctx, 40, 500, 670, 360, 20)
ctx.fill()
ctx.fillStyle = '#333333'
ctx.font = 'bold 24px sans-serif'
ctx.textAlign = 'center'
ctx.fillText('服务前后对比', POSTER_W / 2, 545)
const imgY = 575
const imgH = 260
const imgW = 300
ctx.fillStyle = '#e0e0e0'
ctx.beginPath()
roundRect(ctx, 60, imgY, imgW, imgH, 16)
ctx.fill()
ctx.fillStyle = '#999999'
ctx.font = '20px sans-serif'
ctx.fillText('服务前', 210, imgY + imgH / 2)
ctx.fillStyle = '#e0e0e0'
ctx.beginPath()
roundRect(ctx, 390, imgY, imgW, imgH, 16)
ctx.fill()
ctx.fillStyle = '#999999'
ctx.fillText('服务后', 540, imgY + imgH / 2)
if (remark) {
ctx.fillStyle = '#f8f6f3'
ctx.beginPath()
roundRect(ctx, 40, 880, 670, 100, 20)
ctx.fill()
ctx.fillStyle = '#666666'
ctx.font = '22px sans-serif'
ctx.textAlign = 'left'
if (remark.length > 30) {
ctx.fillText(remark.substring(0, 30), 70, 920)
ctx.fillText(remark.substring(30), 70, 955)
} else {
ctx.fillText(remark, 70, 930)
}
}
ctx.fillStyle = '#0f172a'
ctx.font = '20px sans-serif'
ctx.textAlign = 'center'
ctx.fillText('长按识别小程序 · 欢迎再次预约', POSTER_W / 2, 1020)
ctx.fillStyle = '#07c160'
ctx.font = 'bold 22px sans-serif'
ctx.fillText(`${name}`, POSTER_W / 2, 1055)
if (beforeImg) {
ctx.save()
ctx.beginPath()
roundRect(ctx, 60, imgY, imgW, imgH, 16)
ctx.clip()
ctx.drawImage(beforeImg, 60, imgY, imgW, imgH)
ctx.restore()
}
if (afterImg) {
ctx.save()
ctx.beginPath()
roundRect(ctx, 390, imgY, imgW, imgH, 16)
ctx.clip()
ctx.drawImage(afterImg, 390, imgY, imgW, imgH)
ctx.restore()
}
}