style(fe): 身份卡按参考图收拾 — 去标题/正反面标签/疫苗,卡高按内容自适应
- 去掉顶部「宠物身份卡」大标题和「· 正面 ·/· 背面 ·」灰字,只留两张卡 - 正面卡高度按性格/介绍有无动态算,消掉中间大块空白 - 性格标签为空时整段不画 - 照护卡去掉「疫苗情况」行 - 导出只裁到实际内容底部,卡片下面不再拖空白 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -69,6 +69,7 @@ Page({
|
||||
} catch (e) {
|
||||
dpr = 2;
|
||||
}
|
||||
this._dpr = dpr;
|
||||
node.width = W * dpr;
|
||||
node.height = H * dpr;
|
||||
const ctx = node.getContext('2d');
|
||||
@@ -93,18 +94,14 @@ Page({
|
||||
const cardW = W - pad * 2;
|
||||
|
||||
const fx = pad, cardW2 = cardW;
|
||||
|
||||
// 顶部标题
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillStyle = '#8A5A18';
|
||||
ctx.font = '700 40px sans-serif';
|
||||
ctx.fillText('🐾 宠物身份卡 🐾', W / 2, 66);
|
||||
const tags = (c.personality || '').split(',').filter(Boolean);
|
||||
|
||||
// ══════════ 正面卡(暖黄)══════════
|
||||
ctx.fillStyle = '#C7A36A';
|
||||
ctx.font = '22px sans-serif';
|
||||
ctx.fillText('· 正面 ·', W / 2, 116);
|
||||
const fY = 140, fH = 700;
|
||||
// 高度按内容算,避免留一大块空白
|
||||
let fH = 420;
|
||||
if (tags.length) fH += 90;
|
||||
if (c.intro) fH += 90;
|
||||
const fY = pad;
|
||||
const gf = ctx.createLinearGradient(fx, fY, fx, fY + fH);
|
||||
gf.addColorStop(0, '#FFF7E0');
|
||||
gf.addColorStop(1, '#FFE7AE');
|
||||
@@ -186,56 +183,53 @@ Page({
|
||||
kvF('毛色', c.color, avY + 168);
|
||||
kvF('年龄', c.age, avY + 206);
|
||||
|
||||
// 性格标签
|
||||
let ty = avY + avD + 34;
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillStyle = '#8A5A18';
|
||||
ctx.font = '600 24px sans-serif';
|
||||
ctx.fillText('🐾 性格标签', fx + 34, ty);
|
||||
const tags = (c.personality || '').split(',').filter(Boolean);
|
||||
const tagColors = [['#FFE7A8', '#8A5A18'], ['#D6E9FF', '#2E6DA8'], ['#FFD9DE', '#C24A63']];
|
||||
let tx = fx + 34;
|
||||
ty += 42;
|
||||
tags.forEach((t, i) => {
|
||||
ctx.font = '23px sans-serif';
|
||||
const tw = ctx.measureText(t).width + 32;
|
||||
const col = tagColors[i % tagColors.length];
|
||||
ctx.fillStyle = col[0];
|
||||
this.roundRect(ctx, tx, ty - 28, tw, 40, 20);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = col[1];
|
||||
// 性格标签(没有就不画,避免留空行)
|
||||
let ty = fY + 320;
|
||||
if (tags.length) {
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(t, tx + 16, ty);
|
||||
tx += tw + 14;
|
||||
});
|
||||
ctx.fillStyle = '#8A5A18';
|
||||
ctx.font = '600 24px sans-serif';
|
||||
ctx.fillText('🐾 性格标签', fx + 34, ty);
|
||||
ty += 44;
|
||||
const tagColors = [['#FFE7A8', '#8A5A18'], ['#D6E9FF', '#2E6DA8'], ['#FFD9DE', '#C24A63']];
|
||||
let tx = fx + 34;
|
||||
tags.forEach((t, i) => {
|
||||
ctx.font = '23px sans-serif';
|
||||
const tw = ctx.measureText(t).width + 32;
|
||||
const col = tagColors[i % tagColors.length];
|
||||
ctx.fillStyle = col[0];
|
||||
this.roundRect(ctx, tx, ty - 28, tw, 40, 20);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = col[1];
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(t, tx + 16, ty);
|
||||
tx += tw + 14;
|
||||
});
|
||||
ty += 46;
|
||||
}
|
||||
|
||||
// 介绍 quote
|
||||
if (c.intro) {
|
||||
const qy = ty + 30;
|
||||
ctx.fillStyle = 'rgba(255,255,255,.6)';
|
||||
this.roundRect(ctx, fx + 34, qy, cardW2 - 68, 60, 16);
|
||||
this.roundRect(ctx, fx + 34, ty, cardW2 - 68, 60, 16);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = '#7A5A2E';
|
||||
ctx.font = '25px sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('“ ' + c.intro + ' ”', fx + 54, qy + 40);
|
||||
ctx.fillText('“ ' + c.intro + ' ”', fx + 54, ty + 40);
|
||||
}
|
||||
|
||||
// 底部:身份ID + 一起生活天数
|
||||
// 底部:身份ID + 一起生活天数(贴卡片底边)
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillStyle = '#9C7A3E';
|
||||
ctx.font = '22px sans-serif';
|
||||
ctx.fillText('物ID ' + (c.id_no || ''), fx + 34, fY + fH - 60);
|
||||
ctx.fillText('物ID ' + (c.id_no || ''), fx + 34, fY + fH - 56);
|
||||
if (c.days > 0) {
|
||||
ctx.fillText('和主人一起生活的第 ' + c.days + ' 天', fx + 34, fY + fH - 26);
|
||||
ctx.fillText('和主人一起生活的第 ' + c.days + ' 天', fx + 34, fY + fH - 22);
|
||||
}
|
||||
|
||||
// ══════════ 背面卡(白 + 蓝)══════════
|
||||
const bY = fY + fH + 46, bH = 620;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillStyle = '#C7A36A';
|
||||
ctx.font = '22px sans-serif';
|
||||
ctx.fillText('· 背面 ·', W / 2, bY - 16);
|
||||
// ══════════ 照护卡(白 + 蓝)══════════
|
||||
const bY = fY + fH + 40, bH = 566;
|
||||
this.roundRect(ctx, fx, bY, cardW2, bH, 30);
|
||||
ctx.fillStyle = '#FFFFFF';
|
||||
ctx.fill();
|
||||
@@ -267,12 +261,11 @@ Page({
|
||||
ctx.fillText(value || '—', rowX + 170, yy);
|
||||
};
|
||||
let ry = bY + 140;
|
||||
kvB('👤', '主人', c.owner, ry); ry += 46;
|
||||
kvB('📞', '联系电话', c.phone || '未验证', ry); ry += 46;
|
||||
kvB('💉', '疫苗情况', c.vaccine_state, ry); ry += 46;
|
||||
kvB('📝', '备注', c.notes || '无', ry); ry += 46;
|
||||
kvB('🏛', '发证机构', c.org || '肉垫计划', ry); ry += 46;
|
||||
kvB('📅', '有效期', c.validity || '永久有效', ry); ry += 40;
|
||||
kvB('👤', '主人', c.owner, ry); ry += 48;
|
||||
kvB('📞', '联系电话', c.phone || '未验证', ry); ry += 48;
|
||||
kvB('📝', '备注', c.notes || '无', ry); ry += 48;
|
||||
kvB('🏛', '发证机构', c.org || '肉垫计划', ry); ry += 48;
|
||||
kvB('📅', '有效期', c.validity || '永久有效', ry); ry += 42;
|
||||
|
||||
// 走失联系框 + 小程序码
|
||||
const lostY = ry + 16, lostH = bY + bH - lostY - 30;
|
||||
@@ -302,9 +295,18 @@ Page({
|
||||
ctx.fillText('待发布', qrX + qrD / 2, qrY + qrD / 2 + 24);
|
||||
}
|
||||
|
||||
// 只导出到实际内容底部,避免卡片下面拖一条空白
|
||||
const dpr = this._dpr || 2;
|
||||
const contentH = bY + bH + pad;
|
||||
wx.canvasToTempFilePath(
|
||||
{
|
||||
canvas: node,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: W,
|
||||
height: contentH,
|
||||
destWidth: W * dpr,
|
||||
destHeight: contentH * dpr,
|
||||
fileType: 'png',
|
||||
success: (r) => this.setData({ cardImg: r.tempFilePath }),
|
||||
fail: () => wx.showToast({ title: '生成失败,稍后再试', icon: 'none' }),
|
||||
|
||||
Reference in New Issue
Block a user