fix: lucky page
This commit is contained in:
@@ -135,7 +135,7 @@
|
||||
|
||||
<!-- 画布用于生成图片 -->
|
||||
<canvas
|
||||
canvas-id="luckyCanvas"
|
||||
type="2d"
|
||||
id="luckyCanvas"
|
||||
class="lucky-canvas"
|
||||
:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
|
||||
@@ -232,284 +232,311 @@ const startAnimation = () => {
|
||||
const onSaveImage = async () => {
|
||||
uni.showLoading({ title: "生成图片中..." });
|
||||
|
||||
let avatarPath = "/static/images/default-avatar.png"; // Default or fallback
|
||||
if (userInfo.value && userInfo.value.avatarUrl) {
|
||||
// Basic check for remote URL
|
||||
if (
|
||||
userInfo.value.avatarUrl.startsWith("http") ||
|
||||
userInfo.value.avatarUrl.startsWith("//")
|
||||
) {
|
||||
try {
|
||||
const [err, res] = await uni.downloadFile({
|
||||
url: userInfo.value.avatarUrl,
|
||||
});
|
||||
if (!err && res.statusCode === 200) {
|
||||
avatarPath = res.tempFilePath;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Avatar download failed", e);
|
||||
const query = uni.createSelectorQuery().in(proxy);
|
||||
query
|
||||
.select("#luckyCanvas")
|
||||
.fields({ node: true, size: true })
|
||||
.exec(async (res) => {
|
||||
if (!res[0] || !res[0].node) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: "Canvas not found", icon: "none" });
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
avatarPath = userInfo.value.avatarUrl;
|
||||
}
|
||||
}
|
||||
|
||||
const ctx = uni.createCanvasContext("luckyCanvas", proxy);
|
||||
const W = canvasWidth.value;
|
||||
const H = canvasHeight.value;
|
||||
const canvas = res[0].node;
|
||||
const ctx = canvas.getContext("2d");
|
||||
const dpr = uni.getSystemInfoSync().pixelRatio || 2;
|
||||
|
||||
// 1. 绘制背景
|
||||
ctx.setFillStyle("#ffffff");
|
||||
ctx.fillRect(0, 0, W, H);
|
||||
// Set canvas size (physical pixels)
|
||||
canvas.width = res[0].width * dpr;
|
||||
canvas.height = res[0].height * dpr;
|
||||
|
||||
// 2. 绘制卡片头部渐变
|
||||
const headerH = 460;
|
||||
const grd = ctx.createLinearGradient(0, 0, 0, headerH);
|
||||
grd.addColorStop(0, "#d84315");
|
||||
grd.addColorStop(1, "#ffca28");
|
||||
ctx.setFillStyle(grd);
|
||||
ctx.fillRect(0, 0, W, headerH);
|
||||
// Reset transform
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// --- Top Bar ---
|
||||
const topY = 40;
|
||||
const avatarSize = 64;
|
||||
// Scale context
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
// 绘制用户头像 (Top Left)
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
40 + avatarSize / 2,
|
||||
topY + avatarSize / 2,
|
||||
avatarSize / 2,
|
||||
0,
|
||||
2 * Math.PI,
|
||||
);
|
||||
ctx.clip();
|
||||
ctx.drawImage(avatarPath, 40, topY, avatarSize, avatarSize);
|
||||
ctx.restore();
|
||||
const W = res[0].width;
|
||||
const H = res[0].height;
|
||||
|
||||
// 绘制用户昵称
|
||||
ctx.setTextAlign("left");
|
||||
ctx.setFillStyle("#ffffff");
|
||||
ctx.setFontSize(26);
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillText(
|
||||
userInfo.value?.nickName || "好运用户",
|
||||
40 + avatarSize + 16,
|
||||
topY + 42,
|
||||
);
|
||||
// Helper function to load image
|
||||
const loadCanvasImage = (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = canvas.createImage();
|
||||
img.onload = () => resolve(img);
|
||||
img.onerror = (e) => reject(e);
|
||||
img.src = url;
|
||||
});
|
||||
};
|
||||
|
||||
// 绘制日期 (Top Right)
|
||||
const dateStr = currentDateStr.value || "2026 CNY SPECIAL";
|
||||
ctx.setFontSize(22);
|
||||
ctx.font = "normal 22px sans-serif";
|
||||
const dateWidth = ctx.measureText(dateStr).width + 30;
|
||||
const dateX = W - 40 - dateWidth;
|
||||
const dateY = topY + 12; // box top
|
||||
// date bg
|
||||
ctx.setFillStyle("rgba(255, 255, 255, 0.2)");
|
||||
roundRect(ctx, dateX, dateY, dateWidth, 40, 20);
|
||||
ctx.fill();
|
||||
// date text
|
||||
ctx.setFillStyle("#ffffff");
|
||||
ctx.fillText(dateStr, dateX + 15, dateY + 28);
|
||||
try {
|
||||
// Load images
|
||||
let avatarUrl = "/static/images/default-avatar.png";
|
||||
if (userInfo.value && userInfo.value.avatarUrl) {
|
||||
avatarUrl = userInfo.value.avatarUrl;
|
||||
}
|
||||
|
||||
// --- Main Content (Centered) ---
|
||||
const centerX = W / 2;
|
||||
const [avatarImg, qrCodeImg] = await Promise.all([
|
||||
loadCanvasImage(avatarUrl).catch(() =>
|
||||
loadCanvasImage("/static/images/default-avatar.png"),
|
||||
),
|
||||
loadCanvasImage("/static/images/qrcode.jpg").catch(() => null),
|
||||
]);
|
||||
|
||||
// Label
|
||||
ctx.setTextAlign("center");
|
||||
ctx.setFillStyle("rgba(255, 255, 255, 0.9)");
|
||||
ctx.setFontSize(24);
|
||||
ctx.font = "normal 24px sans-serif";
|
||||
ctx.fillText("今日好运指数", centerX, 180);
|
||||
// 1. 绘制背景
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.fillRect(0, 0, W, H);
|
||||
|
||||
// Score
|
||||
ctx.setFillStyle("#ffffff");
|
||||
ctx.setFontSize(140);
|
||||
ctx.font = "bold 140px sans-serif";
|
||||
ctx.fillText(resultData.value.score + "%", centerX, 310);
|
||||
// 2. 绘制卡片头部渐变
|
||||
const headerH = 460;
|
||||
const grd = ctx.createLinearGradient(0, 0, 0, headerH);
|
||||
grd.addColorStop(0, "#d84315");
|
||||
grd.addColorStop(1, "#ffca28");
|
||||
ctx.fillStyle = grd;
|
||||
ctx.fillRect(0, 0, W, headerH);
|
||||
|
||||
// Lucky Word
|
||||
ctx.setFontSize(52);
|
||||
ctx.font = "bold 52px sans-serif";
|
||||
ctx.fillText(resultData.value.luckyWord, centerX, 390);
|
||||
// --- Top Bar ---
|
||||
const topY = 40;
|
||||
const avatarSize = 64;
|
||||
|
||||
// Decorators (Bottom Corners)
|
||||
ctx.setFillStyle("rgba(255, 255, 255, 0.4)");
|
||||
ctx.setFontSize(24);
|
||||
ctx.font = "normal 24px sans-serif";
|
||||
ctx.setTextAlign("left");
|
||||
ctx.fillText("福", 40, headerH - 20);
|
||||
ctx.setTextAlign("right");
|
||||
ctx.fillText("禧", W - 40, headerH - 20);
|
||||
// 绘制用户头像 (Top Left)
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
40 + avatarSize / 2,
|
||||
topY + avatarSize / 2,
|
||||
avatarSize / 2,
|
||||
0,
|
||||
2 * Math.PI,
|
||||
);
|
||||
ctx.clip();
|
||||
if (avatarImg) {
|
||||
ctx.drawImage(avatarImg, 40, topY, avatarSize, avatarSize);
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
// 5. 绘制内容区 (宜/忌)
|
||||
const gridY = 500;
|
||||
const boxW = (W - 64 - 24) / 2;
|
||||
const gridH = 140;
|
||||
// 绘制用户昵称
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillText(
|
||||
userInfo.value?.nickName || "好运用户",
|
||||
40 + avatarSize + 16,
|
||||
topY + 42,
|
||||
);
|
||||
|
||||
// 宜
|
||||
drawBox(ctx, 32, gridY, boxW, gridH, "#fbfbfb", "#f5f5f5");
|
||||
ctx.setTextAlign("left");
|
||||
ctx.setFontSize(24);
|
||||
ctx.setFillStyle("#d81e06");
|
||||
ctx.font = "bold 24px sans-serif";
|
||||
ctx.fillText("✔ 今日宜", 56, gridY + 44);
|
||||
// 绘制日期 (Top Right)
|
||||
const dateStr = currentDateStr.value || "2026 CNY SPECIAL";
|
||||
ctx.font = "normal 22px sans-serif";
|
||||
const dateWidth = ctx.measureText(dateStr).width + 30;
|
||||
const dateX = W - 40 - dateWidth;
|
||||
const dateY = topY + 12; // box top
|
||||
// date bg
|
||||
ctx.fillStyle = "rgba(255, 255, 255, 0.2)";
|
||||
roundRect(ctx, dateX, dateY, dateWidth, 40, 20);
|
||||
ctx.fill();
|
||||
// date text
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.fillText(dateStr, dateX + 15, dateY + 28);
|
||||
|
||||
ctx.setFontSize(22);
|
||||
ctx.setFillStyle("#666666");
|
||||
ctx.font = "normal 22px sans-serif";
|
||||
wrapText(ctx, resultData.value.yi, 56, gridY + 80, boxW - 48, 30);
|
||||
// --- Main Content (Centered) ---
|
||||
const centerX = W / 2;
|
||||
|
||||
// 忌
|
||||
drawBox(ctx, 32 + boxW + 24, gridY, boxW, gridH, "#fbfbfb", "#f5f5f5");
|
||||
ctx.setFontSize(24);
|
||||
ctx.setFillStyle("#666666");
|
||||
ctx.font = "bold 24px sans-serif";
|
||||
ctx.fillText("✖ 今日忌", 32 + boxW + 24 + 24, gridY + 44);
|
||||
// Label
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillStyle = "rgba(255, 255, 255, 0.9)";
|
||||
ctx.font = "normal 24px sans-serif";
|
||||
ctx.fillText("今日好运指数", centerX, 180);
|
||||
|
||||
ctx.setFontSize(22);
|
||||
ctx.font = "normal 22px sans-serif";
|
||||
wrapText(
|
||||
ctx,
|
||||
resultData.value.ji,
|
||||
32 + boxW + 24 + 24,
|
||||
gridY + 80,
|
||||
boxW - 48,
|
||||
30,
|
||||
);
|
||||
// Score
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.font = "bold 140px sans-serif";
|
||||
ctx.fillText(resultData.value.score + "%", centerX, 310);
|
||||
|
||||
// 6. 幸运元素
|
||||
const elY = 670;
|
||||
const elH = 160;
|
||||
drawBox(ctx, 32, elY, W - 64, elH, "#fbfbfb", "#f5f5f5");
|
||||
// Lucky Word
|
||||
ctx.font = "bold 52px sans-serif";
|
||||
ctx.fillText(resultData.value.luckyWord, centerX, 390);
|
||||
|
||||
// 标题
|
||||
ctx.setFontSize(26);
|
||||
ctx.setFillStyle("#333333");
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillText("★ 幸运元素", 56, elY + 46);
|
||||
// Decorators (Bottom Corners)
|
||||
ctx.fillStyle = "rgba(255, 255, 255, 0.4)";
|
||||
ctx.font = "normal 24px sans-serif";
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText("福", 40, headerH - 20);
|
||||
ctx.textAlign = "right";
|
||||
ctx.fillText("禧", W - 40, headerH - 20);
|
||||
|
||||
// 元素内容
|
||||
const contentW = W - 64;
|
||||
const colW = contentW / 3;
|
||||
const startX = 32;
|
||||
// 5. 绘制内容区 (宜/忌)
|
||||
const gridY = 500;
|
||||
const boxW = (W - 64 - 24) / 2;
|
||||
const gridH = 140;
|
||||
|
||||
const labelY = elY + 90;
|
||||
const valY = elY + 126;
|
||||
// 宜
|
||||
drawBox(ctx, 32, gridY, boxW, gridH, "#fbfbfb", "#f5f5f5");
|
||||
ctx.textAlign = "left";
|
||||
ctx.font = "bold 24px sans-serif";
|
||||
ctx.fillStyle = "#d81e06";
|
||||
ctx.fillText("✔ 今日宜", 56, gridY + 44);
|
||||
|
||||
// 颜色
|
||||
ctx.setTextAlign("center");
|
||||
ctx.setFontSize(20);
|
||||
ctx.setFillStyle("#999999");
|
||||
ctx.font = "normal 20px sans-serif";
|
||||
ctx.fillText("颜色", startX + colW * 0.5, labelY);
|
||||
ctx.font = "normal 22px sans-serif";
|
||||
ctx.fillStyle = "#666666";
|
||||
wrapText(ctx, resultData.value.yi, 56, gridY + 80, boxW - 48, 30);
|
||||
|
||||
ctx.setFontSize(26);
|
||||
ctx.setFillStyle("#d84315");
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillText(resultData.value.luckyColor, startX + colW * 0.5, valY);
|
||||
// 忌
|
||||
drawBox(ctx, 32 + boxW + 24, gridY, boxW, gridH, "#fbfbfb", "#f5f5f5");
|
||||
ctx.font = "bold 24px sans-serif";
|
||||
ctx.fillStyle = "#666666";
|
||||
ctx.fillText("✖ 今日忌", 32 + boxW + 24 + 24, gridY + 44);
|
||||
|
||||
// 数字
|
||||
ctx.setFontSize(20);
|
||||
ctx.setFillStyle("#999999");
|
||||
ctx.font = "normal 20px sans-serif";
|
||||
ctx.fillText("数字", startX + colW * 1.5, labelY);
|
||||
ctx.font = "normal 22px sans-serif";
|
||||
wrapText(
|
||||
ctx,
|
||||
resultData.value.ji,
|
||||
32 + boxW + 24 + 24,
|
||||
gridY + 80,
|
||||
boxW - 48,
|
||||
30,
|
||||
);
|
||||
|
||||
ctx.setFontSize(26);
|
||||
ctx.setFillStyle("#333333");
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillText(resultData.value.luckyNumber, startX + colW * 1.5, valY);
|
||||
// 6. 幸运元素
|
||||
const elY = 670;
|
||||
const elH = 160;
|
||||
drawBox(ctx, 32, elY, W - 64, elH, "#fbfbfb", "#f5f5f5");
|
||||
|
||||
// 方向
|
||||
ctx.setFontSize(20);
|
||||
ctx.setFillStyle("#999999");
|
||||
ctx.font = "normal 20px sans-serif";
|
||||
ctx.fillText("方向", startX + colW * 2.5, labelY);
|
||||
// 标题
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillStyle = "#333333";
|
||||
ctx.fillText("★ 幸运元素", 56, elY + 46);
|
||||
|
||||
ctx.setFontSize(26);
|
||||
ctx.setFillStyle("#333333");
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillText(resultData.value.luckyDirection, startX + colW * 2.5, valY);
|
||||
// 元素内容
|
||||
const contentW = W - 64;
|
||||
const colW = contentW / 3;
|
||||
const startX = 32;
|
||||
|
||||
// 分隔线
|
||||
ctx.setStrokeStyle("#eeeeee");
|
||||
ctx.setLineWidth(2);
|
||||
ctx.beginPath();
|
||||
const lineTop = elY + 70;
|
||||
const lineBottom = elY + 130;
|
||||
ctx.moveTo(startX + colW, lineTop);
|
||||
ctx.lineTo(startX + colW, lineBottom);
|
||||
ctx.stroke();
|
||||
const labelY = elY + 90;
|
||||
const valY = elY + 126;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startX + colW * 2, lineTop);
|
||||
ctx.lineTo(startX + colW * 2, lineBottom);
|
||||
ctx.stroke();
|
||||
// 颜色
|
||||
ctx.textAlign = "center";
|
||||
ctx.font = "normal 20px sans-serif";
|
||||
ctx.fillStyle = "#999999";
|
||||
ctx.fillText("颜色", startX + colW * 0.5, labelY);
|
||||
|
||||
// 7. 语录
|
||||
ctx.setTextAlign("center");
|
||||
ctx.setFontSize(22);
|
||||
ctx.setFillStyle("#999999");
|
||||
ctx.font = "italic 22px sans-serif";
|
||||
wrapTextCentered(ctx, `“${resultData.value.quote}”`, W / 2, 880, W - 80, 30);
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillStyle = "#d84315";
|
||||
ctx.fillText(resultData.value.luckyColor, startX + colW * 0.5, valY);
|
||||
|
||||
// 8. 底部区域 (Footer)
|
||||
const footerY = 960;
|
||||
// 数字
|
||||
ctx.font = "normal 20px sans-serif";
|
||||
ctx.fillStyle = "#999999";
|
||||
ctx.fillText("数字", startX + colW * 1.5, labelY);
|
||||
|
||||
// 分隔线
|
||||
ctx.setStrokeStyle("#f0f0f0");
|
||||
ctx.setLineWidth(1);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(40, footerY);
|
||||
ctx.lineTo(W - 40, footerY);
|
||||
ctx.stroke();
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillStyle = "#333333";
|
||||
ctx.fillText(resultData.value.luckyNumber, startX + colW * 1.5, valY);
|
||||
|
||||
// 底部左侧文字
|
||||
ctx.setTextAlign("left");
|
||||
ctx.setFontSize(32);
|
||||
ctx.setFillStyle("#333333");
|
||||
ctx.font = "bold 32px sans-serif";
|
||||
ctx.fillText("扫码开启今日好运", 40, footerY + 60);
|
||||
// 方向
|
||||
ctx.font = "normal 20px sans-serif";
|
||||
ctx.fillStyle = "#999999";
|
||||
ctx.fillText("方向", startX + colW * 2.5, labelY);
|
||||
|
||||
ctx.setFontSize(20);
|
||||
ctx.setFillStyle("#999999");
|
||||
ctx.font = "normal 20px sans-serif";
|
||||
ctx.fillText("2026 CNY SPECIAL · 新春助手", 40, footerY + 100);
|
||||
ctx.font = "bold 26px sans-serif";
|
||||
ctx.fillStyle = "#333333";
|
||||
ctx.fillText(
|
||||
resultData.value.luckyDirection,
|
||||
startX + colW * 2.5,
|
||||
valY,
|
||||
);
|
||||
|
||||
// 底部右侧二维码
|
||||
ctx.drawImage("/static/logo.png", W - 140, footerY + 25, 100, 100);
|
||||
// 分隔线
|
||||
ctx.strokeStyle = "#eeeeee";
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
const lineTop = elY + 70;
|
||||
const lineBottom = elY + 130;
|
||||
ctx.moveTo(startX + colW, lineTop);
|
||||
ctx.lineTo(startX + colW, lineBottom);
|
||||
ctx.stroke();
|
||||
|
||||
// 绘制
|
||||
ctx.draw(false, () => {
|
||||
setTimeout(() => {
|
||||
uni.canvasToTempFilePath(
|
||||
{
|
||||
canvasId: "luckyCanvas",
|
||||
success: (res) => {
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: "已保存到相册", icon: "success" });
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: "保存失败,请授权", icon: "none" });
|
||||
},
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: "生成图片失败", icon: "none" });
|
||||
console.error(err);
|
||||
},
|
||||
},
|
||||
proxy,
|
||||
);
|
||||
}, 200);
|
||||
});
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startX + colW * 2, lineTop);
|
||||
ctx.lineTo(startX + colW * 2, lineBottom);
|
||||
ctx.stroke();
|
||||
|
||||
// 7. 语录
|
||||
ctx.textAlign = "center";
|
||||
ctx.font = "italic 22px sans-serif";
|
||||
ctx.fillStyle = "#999999";
|
||||
wrapTextCentered(
|
||||
ctx,
|
||||
`“${resultData.value.quote}”`,
|
||||
W / 2,
|
||||
880,
|
||||
W - 80,
|
||||
30,
|
||||
);
|
||||
|
||||
// 8. 底部区域 (Footer)
|
||||
const footerY = 960;
|
||||
|
||||
// 分隔线
|
||||
ctx.strokeStyle = "#f0f0f0";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(40, footerY);
|
||||
ctx.lineTo(W - 40, footerY);
|
||||
ctx.stroke();
|
||||
|
||||
// 底部左侧文字
|
||||
ctx.textAlign = "left";
|
||||
ctx.font = "bold 32px sans-serif";
|
||||
ctx.fillStyle = "#333333";
|
||||
ctx.fillText("扫码开启今日好运", 40, footerY + 60);
|
||||
|
||||
ctx.font = "normal 20px sans-serif";
|
||||
ctx.fillStyle = "#999999";
|
||||
ctx.fillText("2026 CNY SPECIAL · 新春助手", 40, footerY + 100);
|
||||
|
||||
// 底部右侧二维码
|
||||
if (qrCodeImg) {
|
||||
ctx.drawImage(qrCodeImg, W - 140, footerY + 25, 100, 100);
|
||||
}
|
||||
|
||||
// 生成图片
|
||||
setTimeout(() => {
|
||||
uni.canvasToTempFilePath({
|
||||
canvas: canvas,
|
||||
width: W,
|
||||
height: H,
|
||||
destWidth: W * dpr,
|
||||
destHeight: H * dpr,
|
||||
success: (res) => {
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: "已保存到相册", icon: "success" });
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: "保存失败,请授权", icon: "none" });
|
||||
},
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: "生成图片失败", icon: "none" });
|
||||
console.error(err);
|
||||
},
|
||||
});
|
||||
}, 200);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: "生成图片失败", icon: "none" });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 辅助函数:绘制圆角矩形
|
||||
@@ -529,9 +556,9 @@ function roundRect(ctx, x, y, w, h, r) {
|
||||
|
||||
// 辅助函数:绘制带背景边框的盒子
|
||||
function drawBox(ctx, x, y, w, h, bg, border) {
|
||||
ctx.setFillStyle(bg);
|
||||
ctx.setStrokeStyle(border);
|
||||
ctx.setLineWidth(2);
|
||||
ctx.fillStyle = bg;
|
||||
ctx.strokeStyle = border;
|
||||
ctx.lineWidth = 2;
|
||||
roundRect(ctx, x, y, w, h, 20);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
Reference in New Issue
Block a user