From 026652e4e3775908232d56529c0c7043b979746e Mon Sep 17 00:00:00 2001 From: freedakgmail Date: Sun, 14 Jun 2026 09:44:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=8D=89=E7=A8=BF=E4=BF=9D?= =?UTF-8?q?=E5=AD=98500=EF=BC=9AJSONB=20=E4=B8=8D=E6=94=AF=E6=8C=81=20\u00?= =?UTF-8?q?00=EF=BC=8C=E6=8C=87=E6=A0=87=E5=A4=8D=E5=90=88=E9=94=AE?= =?UTF-8?q?=E5=88=86=E9=9A=94=E7=AC=A6=E5=9C=A8=E8=8D=89=E7=A8=BF=E6=8C=81?= =?UTF-8?q?=E4=B9=85=E5=8C=96=E6=97=B6=E7=BC=96=E7=A0=81/=E8=BF=98?= =?UTF-8?q?=E5=8E=9F=EF=BC=9Brun=20=E5=A4=B1=E8=B4=A5=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/persistence/drafts.ts | 30 +++++++++++++++++++++++++++--- src/server/index.ts | 1 + 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/persistence/drafts.ts b/src/persistence/drafts.ts index 77db34d..a08eeb5 100644 --- a/src/persistence/drafts.ts +++ b/src/persistence/drafts.ts @@ -28,6 +28,30 @@ function isoOf(v: unknown): string { return v instanceof Date ? v.toISOString() : String(v); } +/** JSONB 不能存 \u0000(空字符),而指标复合键用其作分隔符。存储时编码为私有区字符,读取时还原。 */ +const NUL = '\u0000'; +const NUL_SENTINEL = '\uE000'; +function deepReplace(value: unknown, from: string, to: string): unknown { + if (typeof value === 'string') return value.split(from).join(to); + if (Array.isArray(value)) return value.map((v) => deepReplace(v, from, to)); + if (value !== null && typeof value === 'object') { + const out: Record = {}; + for (const [k, v] of Object.entries(value as Record)) { + out[k.split(from).join(to)] = deepReplace(v, from, to); + } + return out; + } + return value; +} +/** 存库前编码(去除 \u0000)。 */ +function encodeForm(form: unknown): unknown { + return deepReplace(form ?? null, NUL, NUL_SENTINEL); +} +/** 读出后还原。 */ +function decodeForm(form: unknown): unknown { + return deepReplace(form ?? null, NUL_SENTINEL, NUL); +} + /** 列出草稿(可按 assessorId 过滤),不返回 form 大字段。 */ export async function listDrafts(pool: pg.Pool, assessorId?: string): Promise { const where = assessorId ? 'WHERE assessor_id = $1' : ''; @@ -60,7 +84,7 @@ export async function getDraft(pool: pg.Pool, id: string): Promise>)[0]!; @@ -99,7 +123,7 @@ export async function upsertDraft(pool: pg.Pool, input: UpsertDraftInput): Promi assessorId: r.assessor_id != null ? String(r.assessor_id) : null, sourceAssessmentId: r.source_assessment_id != null ? String(r.source_assessment_id) : null, projectName: r.project_name != null ? String(r.project_name) : null, - form: r.form, + form: decodeForm(r.form), updatedAt: isoOf(r.updated_at), }; } diff --git a/src/server/index.ts b/src/server/index.ts index 83960e9..72e1428 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -799,6 +799,7 @@ app.post('/api/assessments/run', async (c) => { }); } catch (err) { const message = err instanceof Error ? err.message : '未知错误'; + console.error('[run] 评估运行失败:', err instanceof Error ? err.stack ?? err.message : err); return c.json({ error: message }, 400); } });