feat: add reportPosterDraw utility
This commit is contained in:
parent
ebaae1a929
commit
a332e6204b
173
src/utils/reportPosterDraw.js
Normal file
173
src/utils/reportPosterDraw.js
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user