feat: 同步管理端、用户端与后端业务,并接通线上 Web 接口

补齐平台订阅、外部登录、CRM 同步与用户端页面;Nginx 转发用户端接口,登录页使用 Google 与 Apple 标志。

Co-authored-by: Cursor <cursoragent@cursor.com>
这个提交包含在:
wikiboss
2026-09-23 18:01:47 +08:00
父节点 8ea9c25386
当前提交 62e0ae4435
共有 227 个文件被更改,包括 21855 次插入 和 5264 次删除

查看文件

@@ -184,5 +184,63 @@ test('8. 实时雷达数据专家重构:相对时间、本地环境优雅降
assert.ok(!/\bany\b/.test(content), '严禁使用 any');
});
test('9. P32: KPI 必须来自 workplace 统计接口,禁止演示假数,失败回退 0/空态', () => {
const content = fs.readFileSync(pagePath, 'utf-8');
const localeContent = fs.readFileSync(localePath, 'utf-8');
assert.ok(
content.includes('/api/admin/crm/radar/workplace'),
'KPI 必须请求 /api/admin/crm/radar/workplace'
);
assert.ok(content.includes('kpis.tapCount'), '触碰量必须绑定接口 kpis.tapCount');
assert.ok(content.includes('kpis.viewCount'), '浏览量必须绑定接口 kpis.viewCount');
assert.ok(content.includes('kpis.newLeadCount'), '新线索必须绑定接口 kpis.newLeadCount');
assert.ok(
content.includes('kpis.conversionRate'),
'转化率必须绑定接口 kpis.conversionRate'
);
// 禁止渠道/KPI 演示假数(空 feed 时不得回退 50/30/20)
assert.ok(
!/nfc:\s*50/.test(content) && !/qr:\s*30/.test(content) && !/link:\s*20/.test(content),
'渠道分布禁止硬编码 50/30/20 假数'
);
assert.ok(!content.includes('14500'), '禁止硬编码演示 KPI 数字');
assert.ok(!content.includes('Vanguard'), '禁止硬编码演示客户名');
assert.ok(!/\b210\b/.test(content), '页面禁止硬编码演示停留秒数');
assert.ok(
!localeContent.includes('210'),
'语言包禁止硬编码演示停留秒数假数'
);
assert.ok(
content.includes('code !== 1000') || content.includes('code === 1000'),
'必须按 Cool-Admin 约定校验 code === 1000'
);
// 失败或无数据时必须回退 EMPTY_KPI / 全 0,不得保留假数
assert.ok(content.includes('EMPTY_KPI'), '必须定义 EMPTY_KPI 作为空态/失败回退');
assert.ok(
content.includes('kpis: EMPTY_KPI, radarFeed: []'),
'接口失败或无效响应时必须 setOverview 回退 EMPTY_KPI'
);
// 漏斗 meta 与渠道/预警空态必须走 locale
const localeKeys = [
'workplace.funnel.metaBase',
'workplace.funnel.metaTapView',
'workplace.funnel.metaViewInteract',
'workplace.funnel.metaInteractLead',
'workplace.channel.empty',
'workplace.alerts.empty',
];
for (const key of localeKeys) {
assert.ok(localeContent.includes(key), `语言包必须包含: ${key}`);
assert.ok(content.includes(key), `页面必须引用 locale key: ${key}`);
}
assert.ok(!EMOJI_RE.test(content), '页面严禁 emoji');
assert.ok(!EMOJI_RE.test(localeContent), '语言包严禁 emoji');
assert.ok(!/\bany\b/.test(content), '严禁 any');
});