feat: 完善淘宝小程序拍照、报告与登录流程

接入本地实时识别和自动三连拍,调整报告裁切、商品跳转、分享标题及居中页眉;完善游客会话、后台渠道隔离、部署脚本与回归测试。
This commit is contained in:
xsl
2026-11-04 15:07:51 +08:00
parent 381da60ae4
commit 774376fa16
147 changed files with 17420 additions and 597 deletions
+26 -9
View File
@@ -11,6 +11,7 @@ module.exports = function ({ accounts, wrinkleJobs, readBody, sendJson, handleAn
try {
const raw = (await readBody(req, pathname === '/api/taobao/photo' ? 70 * 1024 : 4096)).toString('utf8');
const body = JSON.parse(raw);
if (!body || typeof body !== 'object' || Array.isArray(body)) return reply(400, { ok: false, message: '请求数据异常' });
if (pathname === '/api/taobao/challenge') {
const challenge = taobaoSessions.challenge(req.socket.remoteAddress);
return reply(challenge ? 200 : 429, challenge ? { ok: true, challenge } : { ok: false, message: '操作频繁,请稍后重试' });
@@ -21,29 +22,45 @@ module.exports = function ({ accounts, wrinkleJobs, readBody, sendJson, handleAn
if (!identity || !taobaoSessions.consume(body.challenge)) return reply(401, { ok: false, message: '淘宝身份校验失败,请重新授权登录' });
return reply(200, { ok: true, ...accounts.loginTaobao(identity.providerKey) });
}
if (pathname === '/api/taobao/guest-session') {
if (body.consent !== true) return reply(400, { ok: false, message: '请先阅读并同意隐私协议' });
if (!TaobaoAuth.verifyGateway(req.url, raw) || !taobaoSessions.consume(body.challenge)) {
return reply(401, { ok: false, message: '游客会话校验失败,请重新开始' });
}
const guest = accounts.loginTaobaoGuest();
return reply(guest ? 200 : 429, guest ? { ok: true, ...guest } : { ok: false, message: '操作频繁,请稍后再试' });
}
const owner = accounts.taobaoSession(req);
if (!owner) return reply(401, { ok: false, message: '检测会话已失效,请重新登录' });
if (pathname === '/api/taobao/me') return reply(200, { ok: true, user: { id: owner.id, kind: owner.kind } });
if (!owner) return reply(401, { ok: false, message: '检测会话已失效,请重新开始' });
if (pathname === '/api/taobao/me') {
// A cached Bearer must not restore the previous Taobao account after
// the host app switches accounts. Guests require a signed app gateway
// but intentionally have no dependency on userInfo/open_id authorization.
const identity = owner.kind === 'taobao_guest' ? null : TaobaoAuth.verify(req.url, raw);
const matches = owner.kind === 'taobao_guest' ? !!TaobaoAuth.verifyGateway(req.url, raw)
: !!identity && identity.providerKey === owner.provider_key;
return reply(matches ? 200 : 401, matches ? { ok: true, user: { id: owner.id, kind: owner.kind } }
: { ok: false, message: '淘宝账号状态已变化,请重新进入' });
}
if (pathname === '/api/taobao/photo') {
const { status, ...data } = taobaoSessions.upload(req, body);
return reply(status, { ok: status === 200, ...data });
}
if (pathname === '/api/taobao/skin-analyze') {
const photos = taobaoSessions.takePhotos(req, body.photo_refs);
if (!photos) return reply(409, { ok: false, message: '照片上传未完成或检测进行中,请重试' });
// Start once and poll: cloud gateway requests have a maximum 10s timeout.
const job = taobaoSessions.start(req, () => new Promise(resolve => {
const attempt = taobaoSessions.beginAnalysis(req, body, photos => new Promise(resolve => {
const response = { setHeader() {}, writeHead() {}, end(text, cb) { resolve(JSON.parse(text)); if (cb) cb(); } };
handleAnalyze(req, response, true, { ...body, ...photos }, owner).catch(() => resolve({ ok: false, message: '检测服务暂不可用,请重试' }));
}), true);
if (!job) { taobaoSessions.finish(req); return reply(429, { ok: false, message: '服务繁忙,请稍后再试' }); }
return reply(202, { ok: true, job });
}));
return reply(attempt.status, { ok: attempt.status === 202,
...(attempt.job ? { job: attempt.job } : { message: attempt.message }) });
}
if (pathname === '/api/taobao/analysis') {
const result = taobaoSessions.result(req, body.job);
return reply(result ? 200 : 404, result ? { ok: true, ...result } : { ok: false, message: '检测任务已失效,请查看历史报告或重新检测' });
return reply(result ? 200 : 404, result ? { ok: true, ...result } : { ok: false, message: owner.kind === 'taobao_guest' ? '本次检测任务已失效,请重新开始' : '检测任务已失效,请查看历史报告或重新检测' });
}
if (pathname === '/api/taobao/reports') {
if (owner.kind === 'taobao_guest') return reply(body.id ? 404 : 200, body.id ? { ok: false, message: '游客模式不保存历史报告' } : { ok: true, total: 0, items: [] });
if (!body.id) return reply(200, { ok: true, total: accounts.reports(owner.id).length, items: accounts.reports(owner.id) });
const report = accounts.ownedReport(owner.id, body.id);
return reply(report ? 200 : 404, report ? { ok: true, report } : { ok: false, message: '报告不存在' });