fix: preserve legacy admin URLs across H5 channels

Keep local record and download paths compatible while retaining explicit external source selection. Record Taobao, H5, WeChat and rednote compatibility verification and baseline test failures.
This commit is contained in:
xsl
2026-11-04 15:17:56 +08:00
parent 774376fa16
commit 873b45d3a5
4 changed files with 42 additions and 2 deletions
+39
View File
@@ -0,0 +1,39 @@
# 淘宝适配合入主分支的兼容性验证
日期:2026-11-04。主分支及 origin/main 基线为 381da60,淘宝适配提交为 774376f。
## 兼容边界
- H5 的 index.html、js/app.js、js/accounts.js、js/skin-score.js、js/report-ui.js 与 CSS 相对主分支没有改动。淘宝专用裁切、倒计时、商品链接与页眉位于 taobao/,未替换 H5 版本。
- 共享 accounts.js 仅新增临时淘宝游客 Bearer 会话;微信 Cookie/OAuth 及用户报告接口保留。淘宝登录与游客入口仍校验网关,游客不持久化账号和历史报告。
- 后台汇总按数据来源区分同 ID 记录,外部淘宝数据只读;实际检测及身份写入仍使用各实例自己的数据目录。
- 本次发现并修正本地后台 URL 的兼容差异:local 数据的详情、下载、重试、照片链接不追加 source=local,沿用旧路径;外部淘宝来源保留 source=taobao。
## 已通过验证
- node --test --test-reporter=dot taobao/test/*.test.cjs rednote/test/*.test.cjs
- node taobao/test/h5-compatibility.cjs:H5 游客隐私、HTTPS /state/ 下模拟微信 OAuth、同账号跨设备报告、不同账号隔离、Cookie 丢失及失败处理、注销和重新登录、旧报告不变、异步皱纹加载。
- node rednote/test/browser.cjs:/state/ 和 /rednote/ 双实例隔离、浏览器身份恢复、历史报告、后台照片和原始 JSON 路径、独立注销;红书操作不改变原 H5 数据。
- JUZI_ADMIN_BROWSER_QA=1 下 admin-channels、backend、rednote backend 测试:后台渠道筛选、详情、照片来源、导出、同 ID 隔离、外部只读保护、目录边界。
- 本地链接修正后,重新运行 H5 report-persistence 浏览器测试及上列红书/后台检查,均通过。
- node taobao/scripts/sync-shared.cjs --check:评分、报告文案和共享拍摄规则与 H5 一致。
- git diff --check 通过。
测试使用隔离数据目录、模拟微信上游和检测结果,不写线上用户数据、不调用收费检测。
## 主分支已有的旧测试问题
对当前候选与 git archive main 导出的隔离基线执行同一组 31 个 h5/test/*.js 脚本,两者均为 27 通过、4 失败,失败集合和原因一致,无新增失败:
- factual-copy.js:旧轮廓文案预期与当前主分支文案不同。
- tone-dark-circle.js:旧预期 9.1,当前主分支计算值为 9.25。
- scan-wait-timeout.js:抽取代码的 VM 测试上下文缺 savedAccount,导致测试未进入报告页。
- report-copy-cases.js:需要通过 H5_COPY_CASE_FILE 提供仓库外的私有案例;当前未配置。
未为通过这些旧测试而改动 H5 业务文案或评分。原始运行日志保存在 temp/merge-compatibility-20261104/,不入库。
## 验证限制与合并方式
微信真实平台授权、淘宝真机相机/页眉/分享最终效果仍需发布前手机验收,本地模拟不等同实际平台验收。本次仅合并本地 Git,不部署服务器、不发布小程序、不推送远程。
合并前主分支备份:codex/main-before-taobao-20261104(381da60)。主分支可快进到适配分支,不需覆盖已有提交或改写历史。
+1 -1
View File
@@ -54,7 +54,7 @@ function selectedChannelQuery(url) {
var channel = $('#f-channel').value;
return channel ? url + (url.indexOf('?') < 0 ? '?' : '&') + 'channel=' + encodeURIComponent(channel) : url;
}
function sourceQuery(source) { return '?source=' + encodeURIComponent(source || 'local'); }
function sourceQuery(source) { return source && source !== 'local' ? '?source=' + encodeURIComponent(source) : ''; }
function renderSources(data) {
var sources = data.sources || [];
$('#channel-summary').textContent = sources.length > 1
+1 -1
View File
@@ -581,7 +581,7 @@ function sendJson(res, status, obj) {
function photoUrls(rec) {
const urls = {};
const prefix = entry.rednote ? '/rednote' : '';
const source = rec.admin_source ? '?source=' + encodeURIComponent(rec.admin_source) : '';
const source = rec.admin_source && rec.admin_source !== 'local' ? '?source=' + encodeURIComponent(rec.admin_source) : '';
if (rec.img_front) urls.front = `${prefix}/api/admin/photos/${rec.record_id}/front${source}`;
if (rec.img_left) urls.left = `${prefix}/api/admin/photos/${rec.record_id}/left${source}`;
if (rec.img_right) urls.right = `${prefix}/api/admin/photos/${rec.record_id}/right${source}`;
+1
View File
@@ -62,6 +62,7 @@ test('admin aggregates separate stores with channel filters, collision-safe deta
const detail = await json('/api/admin/records/RCOLLIDE?source=' + source);
assert.equal(detail.raw_json.marker, expected); assert.equal(detail.record.presentation.marker, expected);
assert.equal(detail.readonly, source === 'taobao');
assert.equal(new URL(detail.photos.front, base).search, source === 'local' ? '' : '?source=taobao', 'local photo URLs retain their legacy shape; external sources remain explicit');
assert.match(detail.raw_json.result.face_maps.sample, /base64 图层已省略/);
assert.equal(await (await fetch(base + detail.photos.front)).text(), expected + '-photo');
assert.equal((await json('/api/admin/records/RCOLLIDE/raw?source=' + source)).marker, expected);