From 7b6ae0f6d0ec654602fdf216a43c1905848f540e Mon Sep 17 00:00:00 2001 From: liangxu Date: Fri, 1 May 2026 10:21:54 +0800 Subject: [PATCH] feat(desktop-client): expand publisher error normalization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增登录态失效与微信公众号外链缺失两类发布错误归一化, 将原本散落在适配器里的中文提示集中到 shared/publisher-errors, 让渲染层与 main 进程共用同一份用户可读文案。 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/main/adapters/weixin-gzh.ts | 8 ++- .../src/shared/publisher-errors.test.ts | 31 +++++++++++ .../src/shared/publisher-errors.ts | 52 ++++++++++++++++++- 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/apps/desktop-client/src/main/adapters/weixin-gzh.ts b/apps/desktop-client/src/main/adapters/weixin-gzh.ts index 1c03083..8e61d9c 100644 --- a/apps/desktop-client/src/main/adapters/weixin-gzh.ts +++ b/apps/desktop-client/src/main/adapters/weixin-gzh.ts @@ -8,6 +8,10 @@ import { sessionFetchText, uploadHtmlImages, } from "./common"; +import { + WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE, + normalizeWeixinGzhPublishErrorMessage, +} from "../../shared/publisher-errors"; import { fetchImageAssetBlob, getCenteredCropRect, @@ -1932,10 +1936,10 @@ function failureResult(error: unknown): ReturnType ex if (message.startsWith("weixin_gzh_public_url_missing")) { return { status: "failed", - summary: "微信公众号已提交发布,但未能获取外部文章链接,请在公众号后台发表记录确认。", + summary: WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE, error: { code: "weixin_gzh_public_url_missing", - message, + message: normalizeWeixinGzhPublishErrorMessage(message) ?? WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE, }, }; } diff --git a/apps/desktop-client/src/shared/publisher-errors.test.ts b/apps/desktop-client/src/shared/publisher-errors.test.ts index 2114580..2ab93de 100644 --- a/apps/desktop-client/src/shared/publisher-errors.test.ts +++ b/apps/desktop-client/src/shared/publisher-errors.test.ts @@ -1,14 +1,18 @@ import { describe, expect, it } from "vitest"; import { + PUBLISH_ACCOUNT_NOT_LOGGED_IN_MESSAGE, QIEHAO_REAL_NAME_AUTH_MESSAGE, WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE, WANGYIHAO_PUBLISH_CLICK_MESSAGE, WANGYIHAO_TOKEN_MISSING_MESSAGE, + WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE, isQiehaoRealNameAuthError, normalizePublisherErrorMessage, + normalizePublisherLoginErrorMessage, normalizeQiehaoPublishErrorMessage, normalizeWangyihaoPublishErrorMessage, + normalizeWeixinGzhPublishErrorMessage, } from "./publisher-errors"; describe("publisher error normalization", () => { @@ -23,6 +27,24 @@ describe("publisher error normalization", () => { expect(normalizeQiehaoPublishErrorMessage("publish rejected", -5022)).toBe(QIEHAO_REAL_NAME_AUTH_MESSAGE); }); + it("normalizes publisher login-state failures", () => { + expect(normalizePublisherErrorMessage("wangyihao_not_logged_in")).toBe( + "网易号账号登录态已失效,请重新登录该平台后再重试。", + ); + expect(normalizePublisherErrorMessage("Error: weixin_gzh_not_logged_in")).toBe( + "微信公众号账号登录态已失效,请重新登录该平台后再重试。", + ); + expect(normalizePublisherErrorMessage("qiehao_cookie_missing")).toBe( + "企鹅号账号登录态已失效,请重新登录该平台后再重试。", + ); + }); + + it("uses a generic Chinese message for unknown publisher login-state failures", () => { + expect(normalizePublisherLoginErrorMessage("unknown_platform_not_logged_in")).toBe( + PUBLISH_ACCOUNT_NOT_LOGGED_IN_MESSAGE, + ); + }); + it("normalizes Wangyihao token missing failures", () => { expect(normalizePublisherErrorMessage("wangyihao_token_missing")).toBe(WANGYIHAO_TOKEN_MISSING_MESSAGE); expect(normalizeWangyihaoPublishErrorMessage("Error: wangyihao_token_missing")).toBe( @@ -48,6 +70,15 @@ describe("publisher error normalization", () => { ); }); + it("normalizes Weixin GZH missing public URL failures", () => { + expect(normalizePublisherErrorMessage("weixin_gzh_public_url_missing:100000093")).toBe( + WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE, + ); + expect(normalizeWeixinGzhPublishErrorMessage("Error: weixin_gzh_public_url_missing")).toBe( + WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE, + ); + }); + it("leaves unknown publisher errors unchanged", () => { expect(normalizePublisherErrorMessage("qiehao_publish_failed")).toBe("qiehao_publish_failed"); }); diff --git a/apps/desktop-client/src/shared/publisher-errors.ts b/apps/desktop-client/src/shared/publisher-errors.ts index ced0a2c..16600ad 100644 --- a/apps/desktop-client/src/shared/publisher-errors.ts +++ b/apps/desktop-client/src/shared/publisher-errors.ts @@ -1,9 +1,28 @@ export const QIEHAO_REAL_NAME_AUTH_MESSAGE = "企鹅号账号未完成实名认证,请先到企鹅号后台完成实名认证后再重试。"; +export const PUBLISH_ACCOUNT_NOT_LOGGED_IN_MESSAGE = "发布账号登录态已失效,请重新打开平台后台完成登录后再重试。"; export const WANGYIHAO_TOKEN_MISSING_MESSAGE = "网易号发布凭证获取失败,请重新打开网易号后台确认登录状态。"; export const WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE = "网易号草稿保存失败:参数错误。请检查标题、正文、封面或账号状态后重试。"; export const WANGYIHAO_PUBLISH_CLICK_MESSAGE = "网易号草稿已保存,但自动发布未完成。请打开网易号后台确认草稿状态后重试。"; +export const WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE = + "微信公众号可能已触发管理员/运营者授权发布,桌面端未能获取到文章外链。请打开公众号后台完成授权发布,并在发表记录中确认文章链接。"; + +const PUBLISH_PLATFORM_LABELS: Record = { + baijiahao: "百家号", + bilibili: "bilibili", + dongchedi: "懂车帝", + jianshu: "简书", + juejin: "稀土掘金", + qiehao: "企鹅号", + smzdm: "什么值得买", + sohuhao: "搜狐号", + toutiaohao: "头条号", + wangyihao: "网易号", + weixin_gzh: "微信公众号", + zhihu: "知乎", + zol: "中关村在线", +}; function normalizeErrorText(value: string | null | undefined): string | null { const trimmed = value?.trim(); @@ -42,6 +61,23 @@ export function normalizeQiehaoPublishErrorMessage( return isQiehaoRealNameAuthError(normalized, code) ? QIEHAO_REAL_NAME_AUTH_MESSAGE : normalized; } +export function normalizePublisherLoginErrorMessage(message: string | null | undefined): string | null { + const normalized = normalizeErrorText(message); + if (!normalized) { + return null; + } + + const match = normalized.match( + /\b([a-z0-9_]+?)_(not_logged_in|token_missing|cookie_missing|csrf_missing)\b/i, + ); + if (!match) { + return normalized; + } + + const platformLabel = PUBLISH_PLATFORM_LABELS[match[1]?.toLowerCase() ?? ""]; + return platformLabel ? `${platformLabel}账号登录态已失效,请重新登录该平台后再重试。` : PUBLISH_ACCOUNT_NOT_LOGGED_IN_MESSAGE; +} + export function normalizeWangyihaoPublishErrorMessage(message: string | null | undefined): string | null { const normalized = normalizeErrorText(message); if (!normalized) { @@ -63,7 +99,21 @@ export function normalizeWangyihaoPublishErrorMessage(message: string | null | u return normalized; } +export function normalizeWeixinGzhPublishErrorMessage(message: string | null | undefined): string | null { + const normalized = normalizeErrorText(message); + if (!normalized) { + return null; + } + + if (/\bweixin_gzh_public_url_missing\b/i.test(normalized)) { + return WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE; + } + return normalized; +} + export function normalizePublisherErrorMessage(message: string | null | undefined): string | null { const qiehaoMessage = normalizeQiehaoPublishErrorMessage(message); - return normalizeWangyihaoPublishErrorMessage(qiehaoMessage); + const wangyihaoMessage = normalizeWangyihaoPublishErrorMessage(qiehaoMessage); + const loginMessage = normalizePublisherLoginErrorMessage(wangyihaoMessage); + return normalizeWeixinGzhPublishErrorMessage(loginMessage); }