fix(revenue): replicate the reference rebate poster canvas layers
The poster modal shell already matched the reference theme, but the canvas drawing diverged from zibll's poster-share.js rebate branch in four places: - No 推荐人 tags layer. The reference paints a red #fc4e1f 24px line at img_height+160; AKSRT dropped the layer entirely, so the poster lost the referrer attribution that identifies whose link it is. - The logo slot painted text. The reference contains the real logo image into (80, height-190, 300, 100); AKSRT drew the site name as a 30px string plus a hardcoded 长按识别二维码访问 caption in that slot. - Bottom copy was hardcoded. The reference reads share_desc; now sourced from the new pay_rebate_poster_desc_bottom field with share_desc fallback. - No banner fallback. The reference walks banner → banner_default → banner_spare; a single broken URL left the top half of the poster black. Also aligns the week label to the reference's 周 prefix (was 星期日) and ports drawTextOverflow for wrapping/truncation, which retires the local wrapText. Adds pay_rebate_poster_banner and pay_rebate_poster_desc_bottom to both the Vue and PHP schemas; rest_me now returns logo, compatible and referrer_name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
ef15416ef7
commit
81b60eb427
7 files changed
+212
-95
No files matched your search
@@ -100,16 +100,73 @@ test('poster canvas is built from admin-configured copy and gated on the poster
|
||||
assert.match(runtime, /pay_rebate_poster_desc/)
|
||||
|
||||
const attribution = read('src', 'Payment', 'ReferralAttribution.php')
|
||||
assert.match(attribution, /'poster' => \(array\) \(\$affiliate\['poster'\] \?\? \['enabled' => false\]\)/)
|
||||
// 推广海报 payload:开关 / 主图 / 标题 / 简介 / 两级备用横幅 / 底部文案。
|
||||
assert.match(attribution, /\$poster = \(array\) \(\$affiliate\['poster'\] \?\? \['enabled' => false\]\)/)
|
||||
assert.match(attribution, /'poster' => \$poster/)
|
||||
// 参考主题 rebate 的 logo 与底部文案取自分享设置,不在推广字段里重复配置。
|
||||
assert.match(attribution, /\$poster\['logo'\] = esc_url_raw/)
|
||||
assert.match(attribution, /\$poster\['compatible'\] = !empty\(\$share\['compatible_s'\]\)/)
|
||||
assert.match(attribution, /\$poster\['bottom'\] = sanitize_text_field/)
|
||||
// 参考主题 tags 层:`推荐人: {昵称}`。
|
||||
assert.match(attribution, /'referrer_name' => \$user instanceof WP_User \? \$user->display_name/)
|
||||
assert.match(attribution, /'site_name' => get_bloginfo\('name'\)/)
|
||||
|
||||
const script = read('assets', 'js', 'credits.js')
|
||||
// 海报仅在开关开启时暴露按钮;绘制含顶部图、文案换行、二维码与站点名。
|
||||
assert.match(script, /initAffiliatePoster\(root, url \|\| j\.url \|\| '', j\.poster \|\| \{\}, j\.site_name \|\| document\.title\)/)
|
||||
// 海报仅在开关开启时暴露按钮;推荐人昵称也由 REST 下发。
|
||||
assert.match(script, /initAffiliatePoster\(root, url \|\| j\.url \|\| '', j\.poster \|\| \{\}, j\.site_name \|\| document\.title, j\.referrer_name \|\| ''\)/)
|
||||
assert.match(script, /poster\.enabled !== true\) return/)
|
||||
assert.match(script, /function buildPosterCanvas/)
|
||||
assert.match(script, /function wrapText\(ctx, text, maxWidth\)/)
|
||||
assert.match(script, /image\.crossOrigin = 'anonymous'/)
|
||||
|
||||
// 顶部主图三级回退,对齐参考主题 banner → banner_default → banner_spare。
|
||||
const posterRuntime = read('src', 'Settings', 'PaymentRuntime.php')
|
||||
assert.match(posterRuntime, /'banner_default' => esc_url_raw\(\(string\) \(\$settings\['pay_rebate_poster_banner'\] \?\? ''\)\)/)
|
||||
assert.match(posterRuntime, /'banner_spare' => get_template_directory_uri\(\) \. '\/assets\/img\/share_img\.jpg'/)
|
||||
assert.match(posterRuntime, /'bottom' => sanitize_text_field\(\(string\) \(\$settings\['pay_rebate_poster_desc_bottom'\] \?\? ''\)\)/)
|
||||
// 备用图必须是真实存在的资源,否则回退到 404 等于没回退。
|
||||
assert.ok(fs.existsSync(path.join(root, 'assets', 'img', 'share_img.jpg')), 'assets/img/share_img.jpg must be committed')
|
||||
|
||||
// 新增的后台字段必须在 SPA schema 与 PHP schema 双侧注册,否则 contract audit 会红。
|
||||
const vue = read('assets', 'admin', 'src', 'schema', 'sections', 'payment', 'affiliate.js')
|
||||
const php = read('src', 'Admin', 'Schema', 'SchemaPayment.php')
|
||||
for (const key of ['pay_rebate_poster_banner', 'pay_rebate_poster_desc_bottom']) {
|
||||
assert.match(vue, new RegExp("key: '" + key + "'"), 'vue schema ' + key)
|
||||
assert.match(php, new RegExp("'key' => '" + key + "'"), 'php schema ' + key)
|
||||
}
|
||||
})
|
||||
|
||||
test('poster canvas layers match the reference rebate branch 1:1', () => {
|
||||
const script = read('assets', 'js', 'credits.js')
|
||||
const body = script.slice(script.indexOf('function buildPosterCanvas'), script.indexOf('// cover 裁切'))
|
||||
|
||||
// 参考主题 rebate 分支用 drawTextOverflow 的换行/截断,不是自研 wrapText。
|
||||
assert.match(script, /function drawTextOverflow\(ctx, text, maxWidth, maxRow, font, color, lineHeight, x, y\)/)
|
||||
assert.doesNotMatch(script, /function wrapText\(/, 'wrapText is dead once drawTextOverflow lands')
|
||||
assert.doesNotMatch(script, /wrapText\(/)
|
||||
|
||||
// logo 用 contain 裁切画真实图片,不再把站名当文本画在 logo 位。
|
||||
assert.match(script, /function containRect\(sx, sy, boxW, boxH, srcW, srcH\)/)
|
||||
assert.match(body, /containRect\(80, height - 190, 300, 100, logo\.width, logo\.height\)/)
|
||||
assert.doesNotMatch(body, /长按识别二维码访问/, 'hardcoded bottom copy must come from config')
|
||||
assert.doesNotMatch(body, /ctx\.fillText\(String\(siteName/)
|
||||
assert.match(body, /poster\.bottom \|\| '扫描二维码阅读全文'/)
|
||||
|
||||
// 推荐人标签层:参考主题 img_height+172 的红色 24px 层。
|
||||
assert.match(body, /'推荐人: ' \+ String\(referrerName\)/)
|
||||
assert.match(body, /drawTextOverflow\(ctx, tags, width, 1, '24px Arial', '#fc4e1f', 36, 2, imgHeight \+ 162\)/)
|
||||
|
||||
// 站点名走「周」前缀(参考主题 zib__('week_prefix'))。
|
||||
assert.match(body, /'周' \+ '日一二三四五六'\.charAt\(new Date\(\)\.getDay\(\)\)/)
|
||||
assert.doesNotMatch(body, /\['星期日', '星期一'/)
|
||||
|
||||
// 层叠坐标必须与参考主题 rebate 分支一致:$title 于 (20, img+40)、
|
||||
// $tags 于 (0, img+160)、$content 于 (0, img+220);子画布左对齐 x=40、基线偏移 2,
|
||||
// drawTextOverflow 内部 +38,故 x 参数传 2。
|
||||
assert.match(body, /drawTextOverflow\(ctx, title, width, 2, 'bold 35px Arial', '#424242', 52, 2, imgHeight \+ 42\)/)
|
||||
assert.match(body, /drawTextOverflow\(ctx, tags, width, 1, '24px Arial', '#fc4e1f', 36, 2, imgHeight \+ 162\)/)
|
||||
assert.match(body, /drawTextOverflow\(ctx, description, width, 4, '25px Arial', 'rgba\(88,88,88,1\)', 39, 2, imgHeight \+ 222\)/)
|
||||
// 底部文案基线:参考主题 $description 子画布置于 height-60,内部基线偏移 2。
|
||||
assert.match(body, /height - 58/)
|
||||
})
|
||||
|
||||
test('poster modal markup is a 1:1 replica of the reference poster-share dialog', () => {
|
||||
|
||||
Reference in new issue
Block a user