diff --git a/scripts/admin-web-fake-api.mjs b/scripts/admin-web-fake-api.mjs index 2ebb1b7b5..7e3b21909 100644 --- a/scripts/admin-web-fake-api.mjs +++ b/scripts/admin-web-fake-api.mjs @@ -4,6 +4,9 @@ import http from 'node:http'; const port = Number(process.argv[2] ?? 8099); +/** 与后端 `MEMBERSHIP_UNLIMITED_CONCURRENCY` 一致的假数据哨兵。 */ +const UNLIMITED_CONCURRENCY_THRESHOLD = 128; + const admin = { subject: 'admin:local', username: 'owner', @@ -473,7 +476,15 @@ const userDetail = { tags: ['vip', '内测'], }; -function route(pathname, method, url) { +function parseJsonBody(requestBody) { + try { + return JSON.parse(requestBody); + } catch { + return null; + } +} + +function route(pathname, method, url, requestBody = '') { if (pathname === '/admin/api/login' && method === 'POST') { return { token: 'local-fake-token', admin }; } @@ -756,7 +767,8 @@ function route(pathname, method, url) { periodPoints, modelAccess, concurrentJobLimit, - unlimitedConcurrency: concurrentJobLimit >= 128, + unlimitedConcurrency: + concurrentJobLimit >= UNLIMITED_CONCURRENCY_THRESHOLD, enabled, }); const plans = [ @@ -766,10 +778,22 @@ function route(pathname, method, url) { plan('pro', '专业会员', 3, 29_900, 299_000, 3_650, 'full', 5, true), plan('max', '旗舰会员', 4, 69_900, 699_000, 8_650, 'full', 128, true), ]; - // 本地预览不解析请求体:POST 统一回显 starter,仅用于页面回填。 - return method === 'POST' - ? plans[1] - : { entries: plans, unlimitedConcurrencyThreshold: 128 }; + // 本地预览按请求体回显被保存的档位:把提交字段覆盖到对应档位行,避免保存非 starter 档后表单被回填成 starter。 + if (method === 'POST') { + const submitted = parseJsonBody(requestBody); + const target = + plans.find((entry) => entry.plan === submitted?.plan) ?? plans[1]; + const merged = { ...target, ...(submitted ?? {}) }; + return { + ...merged, + unlimitedConcurrency: + Number(merged.concurrentJobLimit) >= UNLIMITED_CONCURRENCY_THRESHOLD, + }; + } + return { + entries: plans, + unlimitedConcurrencyThreshold: UNLIMITED_CONCURRENCY_THRESHOLD, + }; } if (pathname === '/admin/api/profile/recharge-products') { const product = ( @@ -1152,13 +1176,25 @@ function route(pathname, method, url) { const server = http.createServer((request, response) => { const url = new URL(request.url ?? '/', `http://127.0.0.1:${port}`); - const payload = route(url.pathname, request.method ?? 'GET', url); - const body = JSON.stringify({ data: payload }); - response.writeHead(200, { - 'Content-Type': 'application/json; charset=utf-8', - 'x-genarrative-response-envelope': 'v1', + const chunks = []; + request.on('data', (chunk) => { + chunks.push(chunk); + }); + request.on('end', () => { + const requestBody = Buffer.concat(chunks).toString('utf8'); + const payload = route( + url.pathname, + request.method ?? 'GET', + url, + requestBody, + ); + const body = JSON.stringify({ data: payload }); + response.writeHead(200, { + 'Content-Type': 'application/json; charset=utf-8', + 'x-genarrative-response-envelope': 'v1', + }); + response.end(body); }); - response.end(body); }); server.listen(port, '127.0.0.1', () => {