fix(revenue): align detail card, poster modal and copy feedback with reference
- detail-tab 累计佣金 row now shows 累计 + 已提现 (was 累计/可提现/已提现) - rebuild poster canvas to match reference layout (768×1168, top banner, date overlay, blue title bar, bottom bordered box with QR + link) - copy-link feedback moves from inline text to a toast (notyf), matching the reference; drop the now-unused data-affiliate-feedback element
This commit is contained in:
+80
-44
@@ -123,8 +123,6 @@
|
||||
root.dataset.affiliateBound = '1';
|
||||
var input = root.querySelector('[data-affiliate-link]');
|
||||
var copy = root.querySelector('[data-affiliate-copy]');
|
||||
var feedback = root.querySelector('[data-affiliate-feedback]');
|
||||
function setFeedback(text, error) { if (feedback) { feedback.textContent = text; feedback.classList.toggle('is-error', !!error); } }
|
||||
var url = input ? input.value : '';
|
||||
if (copy) copy.disabled = !url;
|
||||
api('/revenue/me').then(function (r) {
|
||||
@@ -135,9 +133,10 @@
|
||||
}).catch(function () { /* 海报与比例为增强项,静默失败即可。 */ });
|
||||
if (copy) copy.addEventListener('click', function () {
|
||||
if (!input || !input.value) return;
|
||||
var done = function () { setFeedback('推广链接已复制。'); };
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(input.value).then(done).catch(function () { input.focus(); input.select(); setFeedback('复制失败,请手动复制。', true); });
|
||||
else { input.focus(); input.select(); try { document.execCommand('copy'); done(); } catch (e) { setFeedback('复制失败,请手动复制。', true); } }
|
||||
var done = function () { notyf('推广链接已复制', 'success', 3, 'aksrt-affiliate-copy-toast'); };
|
||||
var fail = function () { input.focus(); input.select(); notyf('复制失败,请手动复制', 'danger', 3, 'aksrt-affiliate-copy-toast'); };
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(input.value).then(done).catch(fail);
|
||||
else { input.focus(); input.select(); try { document.execCommand('copy'); done(); } catch (e) { fail(); } }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -191,8 +190,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 参考主题 poster-share.js 布局 1:1:768×1168,顶部主图占上半屏,
|
||||
// 左上角日期,标题竖蓝线 + 标题,正文,底部带边框盒(logo/站名 + 二维码 + 链接)。
|
||||
function buildPosterCanvas(url, poster, siteName) {
|
||||
var width = 750, height = 1000;
|
||||
var width = 768, height = 1168;
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
@@ -212,69 +213,104 @@
|
||||
loadImage = Promise.resolve(null);
|
||||
}
|
||||
return loadImage.then(function (image) {
|
||||
// 顶部图(cover 裁切)或纯色占位。
|
||||
if (image) {
|
||||
var ratio = Math.max(width / image.width, 360 / image.height);
|
||||
var drawWidth = image.width * ratio;
|
||||
var drawHeight = image.height * ratio;
|
||||
ctx.drawImage(image, (width - drawWidth) / 2, 0, drawWidth, drawHeight, 0, 0, width, 360);
|
||||
var imgHeight = height / 2; // 参考主题 rebate(非 product):顶部主图占上半屏。
|
||||
// 顶部主图(cover 裁切)或纯色占位。
|
||||
if (image && image.width && image.height) {
|
||||
var rect = coverRect(width, imgHeight, image.width, image.height);
|
||||
ctx.drawImage(image, rect.sx, rect.sy, rect.sWidth, rect.sHeight, 0, 0, width, imgHeight);
|
||||
} else {
|
||||
ctx.fillStyle = '#0f172a';
|
||||
ctx.fillRect(0, 0, width, 200);
|
||||
ctx.fillRect(0, 0, width, imgHeight);
|
||||
}
|
||||
var cursorY = image ? 420 : 280;
|
||||
ctx.fillStyle = '#0f172a';
|
||||
ctx.font = 'bold 38px sans-serif';
|
||||
var title = String(poster.title || siteName || '');
|
||||
var titleLines = wrapText(ctx, title, width - 80).slice(0, 2);
|
||||
// 左上角日期(白字,覆盖在主图上)。
|
||||
var now = new Date();
|
||||
var week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.95)';
|
||||
ctx.font = 'bold 35px Arial, sans-serif';
|
||||
ctx.fillText(week[now.getDay()], 40, 35);
|
||||
ctx.font = '28px Arial, sans-serif';
|
||||
ctx.fillText((now.getMonth() + 1) + ' / ' + now.getDate(), 40, 88);
|
||||
// 标题竖蓝线。
|
||||
ctx.strokeStyle = '#00a1ff';
|
||||
ctx.lineWidth = 7;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(40, imgHeight + 38);
|
||||
ctx.lineTo(40, imgHeight + 74);
|
||||
ctx.stroke();
|
||||
// 标题(粗体,最多 2 行)。
|
||||
ctx.fillStyle = '#424242';
|
||||
ctx.font = 'bold 35px Arial, sans-serif';
|
||||
var titleLines = wrapText(ctx, String(poster.title || siteName || ''), width - 100).slice(0, 2);
|
||||
var cursorY = imgHeight + 40;
|
||||
for (var t = 0; t < titleLines.length; t++) {
|
||||
ctx.fillText(titleLines[t], 40, cursorY);
|
||||
cursorY += 56;
|
||||
ctx.fillText(titleLines[t], 60, cursorY);
|
||||
cursorY += 52;
|
||||
}
|
||||
cursorY += 8;
|
||||
// 正文(简介,最多 3 行)。
|
||||
var description = String(poster.description || '');
|
||||
if (description) {
|
||||
ctx.fillStyle = '#475569';
|
||||
ctx.font = '26px sans-serif';
|
||||
var lines = wrapText(ctx, description, width - 80, 26).slice(0, 3);
|
||||
ctx.fillStyle = '#585858';
|
||||
ctx.font = '25px Arial, sans-serif';
|
||||
var lines = wrapText(ctx, description, width - 80).slice(0, 3);
|
||||
var contentY = imgHeight + 160;
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
ctx.fillText(lines[i], 40, cursorY);
|
||||
cursorY += 40;
|
||||
ctx.fillText(lines[i], 40, contentY);
|
||||
contentY += 38;
|
||||
}
|
||||
}
|
||||
// 二维码 + 链接 + 站点名。
|
||||
// 底部带边框盒。
|
||||
ctx.strokeStyle = 'rgba(122,122,122,0.2)';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeRect(30, height - 230, width - 60, 200);
|
||||
// 站点名(logo 位,左侧)。
|
||||
ctx.fillStyle = '#424242';
|
||||
ctx.font = 'bold 30px Arial, sans-serif';
|
||||
ctx.fillText(String(siteName || ''), 80, height - 175);
|
||||
ctx.fillStyle = '#94a3b8';
|
||||
ctx.font = '20px Arial, sans-serif';
|
||||
ctx.fillText('长按识别二维码访问', 80, height - 130);
|
||||
// 二维码(右下)。
|
||||
var qr = window.qrcode(0, 'M');
|
||||
qr.addData(url);
|
||||
qr.make();
|
||||
var count = qr.getModuleCount();
|
||||
var cell = 6, margin = 4;
|
||||
var qrSize = (count + margin * 2) * cell;
|
||||
var qrY = height - qrSize - 130;
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fillRect(40 - 8, qrY - 8, qrSize + 16, qrSize + 16);
|
||||
ctx.strokeStyle = '#e2e8f0';
|
||||
ctx.strokeRect(40 - 8, qrY - 8, qrSize + 16, qrSize + 16);
|
||||
var qrBox = 120;
|
||||
var cell = qrBox / count;
|
||||
var qrX = width - 200, qrY = height - 200;
|
||||
ctx.fillStyle = '#0f172a';
|
||||
for (var r = 0; r < count; r++) {
|
||||
for (var c = 0; c < count; c++) {
|
||||
if (qr.isDark(r, c)) {
|
||||
ctx.fillRect(40 + (c + margin) * cell, qrY + (r + margin) * cell, cell, cell);
|
||||
ctx.fillRect(qrX + Math.floor(c * cell), qrY + Math.floor(r * cell), Math.ceil(cell), Math.ceil(cell));
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.fillStyle = '#475569';
|
||||
ctx.font = '24px sans-serif';
|
||||
ctx.fillText('扫描二维码访问', 40 + qrSize + 40, qrY + 40);
|
||||
ctx.fillStyle = '#0f172a';
|
||||
ctx.font = 'bold 28px sans-serif';
|
||||
ctx.fillText(String(siteName || ''), 40 + qrSize + 40, qrY + 90);
|
||||
ctx.fillStyle = '#94a3b8';
|
||||
ctx.font = '20px sans-serif';
|
||||
ctx.fillText(url.slice(0, 60), 40, height - 40);
|
||||
// 底部链接(居中)。
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillStyle = '#b4b4b4';
|
||||
ctx.font = '22px Arial, sans-serif';
|
||||
ctx.fillText(String(url).slice(0, 46), width / 2, height - 46);
|
||||
ctx.textAlign = 'left';
|
||||
return canvas;
|
||||
});
|
||||
}
|
||||
|
||||
// cover 裁切:把源图按短边铺满目标框并居中裁切。
|
||||
function coverRect(boxW, boxH, srcW, srcH) {
|
||||
var sx = 0, sy = 0, sWidth = srcW, sHeight = srcH;
|
||||
if (srcW / srcH > boxW / boxH) {
|
||||
sWidth = (boxW * srcH) / boxH;
|
||||
sx = (srcW - sWidth) / 2;
|
||||
} else {
|
||||
sHeight = (boxH * srcW) / boxW;
|
||||
sy = (srcH - sHeight) / 2;
|
||||
}
|
||||
return { sx: sx, sy: sy, sWidth: sWidth, sHeight: sHeight };
|
||||
}
|
||||
|
||||
function wrapText(ctx, text, maxWidth) {
|
||||
var lines = [];
|
||||
var current = '';
|
||||
|
||||
Reference in New Issue
Block a user