fix(frontend): route every user-center points label through the custom currency name

后台「积分配置 → 自定义货币名称」改名后,用户中心仍有大量硬编码
「积分」:做任务赚积分 / 购买积分 / 签到领积分、积分记录 / 积分任务、
每日可免费获取 XX 积分、我的积分、积分+1、创作中心积分收益等。

get_currency_name() 早已存在且可用,问题只是这些文案没有走它。
本PR 全部替换,无双路、无迁移:

服务端渲染(用户中心 renderers)
- credits-balance.php:购买/做任务赚/签到领 + 整个购买弹窗
- profile-credits.php:积分记录 / 积分任务 页签
- credits-points-tasks.php:每日上限三态与空态
- sidebar-creator.php / profile-creator.php:积分收益
- transfer-modal.php:积分转账提示
- Signin.php:签到详情弹窗(我的积分 / 奖励 tooltip / 积分+N)
- VipServiceModal.php:我的积分 / 积分兑换会员
- download-permission-card.php:购买价格

客户端渲染(JS 无法调用 PHP,注入 currencyName 到 aksrtData)
- signin.js:签到状态行「已签到 N 天 +1」
- credits.js:转账标题/金额标签 + 购买提示 toast
- cms-download.js:积分不足视图、我的积分 入口、余额不足文案
- pay-vip.js:积分兑换会员入口(优先 catalog.currency_name)
- order-center.js:订单行单位回退

契约测试同步改为断言模板构造而非死字符串,并新增两例:
改名后跟随、未注入时回退「积分」。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-11-01 15:09:49 +08:00
1 parent 1c95f94bca
commit 5c6b422866
19 files changed
+170 -59

No files matched your search

+31 -4
View File
@@ -64,7 +64,7 @@ function deferred() {
return { promise, resolve, reject };
}
function setup({ buttons = [makeButton('btn uc-header__signin-btn', '签到')], captchaSignin = false, today = Promise.resolve({ ok: true, status: 200, json: { enabled: true, signed: false, streak: 1, reward_if_signin: 2 } }), signin = Promise.resolve({ ok: true, status: 200, json: { message: '签到成功,积分 +2', balance: 12 } }), captchaRun } = {}) {
function setup({ buttons = [makeButton('btn uc-header__signin-btn', '签到')], captchaSignin = false, currencyName = '', today = Promise.resolve({ ok: true, status: 200, json: { enabled: true, signed: false, streak: 1, reward_if_signin: 2 } }), signin = Promise.resolve({ ok: true, status: 200, json: { message: '签到成功,积分 +2', balance: 12 } }), captchaRun } = {}) {
const calls = [];
const notices = [];
const balance = { textContent: '10', title: '10' };
@@ -84,7 +84,7 @@ function setup({ buttons = [makeButton('btn uc-header__signin-btn', '签到')],
};
const jq = { off() { return this; }, on(event, callback) { listeners[event] = callback; return this; } };
const window = {
aksrtData: { captchaSignin, signinDetailsUrl: '/wp-json/aksrt/v1/signin/details' },
aksrtData: { captchaSignin, signinDetailsUrl: '/wp-json/aksrt/v1/signin/details', currencyName },
AksrtModalRuntime: { open: (...args) => modals.push(args), openRemote: (...args) => modals.push(args) },
AksrtRequest: { request(endpoint, options) { calls.push({ endpoint, options }); return endpoint === '/signin/today' ? today : signin; } },
};
@@ -99,6 +99,32 @@ function setup({ buttons = [makeButton('btn uc-header__signin-btn', '签到')],
const settle = () => new Promise((resolve) => setImmediate(resolve));
test('status line follows the custom currency name instead of hardcoding 积分', async () => {
// 后台「积分配置 → 自定义货币名称」改名后,签到状态行必须跟着变,
// 否则这里仍显示「积分」。
const button = makeButton('btn', '签到');
const success = deferred();
const h = setup({ buttons: [button], currencyName: '金币', signin: success.promise });
await settle();
button.click();
await settle();
success.resolve({ ok: true, status: 200, json: { message: '签到成功', balance: 12, streak: 3, reward: 2 } });
await settle();
assert.equal(h.status.innerHTML, '已签到 <strong>3</strong> 天 +2 金币');
});
test('status line falls back to 积分 when no custom currency name is injected', async () => {
const button = makeButton('btn', '签到');
const success = deferred();
const h = setup({ buttons: [button], signin: success.promise });
await settle();
button.click();
await settle();
success.resolve({ ok: true, status: 200, json: { message: '签到成功', balance: 12, streak: 3, reward: 2 } });
await settle();
assert.equal(h.status.innerHTML, '已签到 <strong>3</strong> 天 +2 积分');
});
test('uses reference loading, success toast, and replaces all entry points with detail links', async () => {
const first = makeButton('img-badge jb-yellow', '签到', '<i class="fa far fa-calendar-check ml3 mr6"></i>');
const second = makeButton('btn uc-header__signin-btn', '签到', '<i class="fa fa-calendar-check"></i>', '今日已签到');
@@ -136,7 +162,8 @@ test('uses reference loading, success toast, and replaces all entry points with
assert.equal(h.calls.filter((call) => call.endpoint === '/signin/today').length, 1, 'success does not issue another status request');
assert.equal(h.modals.length, 0, 'success does not open a modal');
assert.equal(h.balance.textContent, '12');
assert.equal(h.status.innerHTML, '已签到 <strong>2</strong> 天 +2');
// 状态行在奖励数值后追加自定义货币名称(未注入时回退「积分」)。
assert.equal(h.status.innerHTML, '已签到 <strong>2</strong> 天 +2 积分');
});
test('keeps the profile done style on its replacement link', async () => {
@@ -228,7 +255,7 @@ test('ignores an old today response after successful sign-in', async () => {
await settle();
assert.ok(button.replaced, 'success replaced the action with the details link');
assert.match(button.replaced.innerHTML, /已签到/);
assert.equal(h.status.innerHTML, '已签到 <strong>3</strong> 天 +2');
assert.equal(h.status.innerHTML, '已签到 <strong>3</strong> 天 +2 积分');
});
test('leaves a disabled sign-in feature disabled without turning it into a signed state', async () => {