chore(frontend): introduce prettier + eslint and prune unused code
Backend CI / Backend (push) Has been cancelled
Frontend CI / Frontend (push) Failing after 1m39s

- Add Prettier 3 with prettier-plugin-organize-imports (sorts/removes unused imports)
- Add ESLint 10 flat config with typescript-eslint + eslint-plugin-vue + eslint-config-prettier
- Add root scripts: format, format:check, lint, lint:fix
- Reformat 257 files across admin-web, ops-web, desktop-client, packages
- Remove unused locals/exports flagged by --noUnusedLocals/--noUnusedParameters
- Fix duplicate localTabLabel key, surrogate-pair regex u-flag, NBSP literal in regex
- Skip server/ (Go) and apps/browser-extension/ (deprecated per ADR)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 20:39:09 +08:00
parent 21c7892ee4
commit 162abdc97c
258 changed files with 42261 additions and 37556 deletions
@@ -1,35 +1,35 @@
function normalizeText(value: string | null | undefined): string {
return value?.trim() ?? "";
return value?.trim() ?? ''
}
export function normalizeAccountPlatformUid(value: string | null | undefined): string {
let normalized = normalizeText(value);
while (normalized.toLowerCase().startsWith("platform:")) {
normalized = normalized.slice("platform:".length).trim();
let normalized = normalizeText(value)
while (normalized.toLowerCase().startsWith('platform:')) {
normalized = normalized.slice('platform:'.length).trim()
}
return normalized;
return normalized
}
export function sameAccountPlatformUid(
left: string | null | undefined,
right: string | null | undefined,
): boolean {
const normalizedLeft = normalizeAccountPlatformUid(left);
const normalizedRight = normalizeAccountPlatformUid(right);
return Boolean(normalizedLeft) && normalizedLeft === normalizedRight;
const normalizedLeft = normalizeAccountPlatformUid(left)
const normalizedRight = normalizeAccountPlatformUid(right)
return Boolean(normalizedLeft) && normalizedLeft === normalizedRight
}
export function buildAccountIdentityKey(input: {
platform: string;
platformUid?: string | null;
displayName?: string | null;
platform: string
platformUid?: string | null
displayName?: string | null
}): string {
const platform = normalizeText(input.platform).toLowerCase() || "unknown";
const platformUid = normalizeAccountPlatformUid(input.platformUid);
const platform = normalizeText(input.platform).toLowerCase() || 'unknown'
const platformUid = normalizeAccountPlatformUid(input.platformUid)
if (platformUid) {
return `${platform}:${platformUid}`;
return `${platform}:${platformUid}`
}
const normalizedName = normalizeText(input.displayName).replace(/\s+/g, "").toLowerCase();
return `${platform}:name:${normalizedName || "unknown"}`;
const normalizedName = normalizeText(input.displayName).replace(/\s+/g, '').toLowerCase()
return `${platform}:name:${normalizedName || 'unknown'}`
}
+19 -19
View File
@@ -1,27 +1,27 @@
export type DesktopObservedRequestPhase = "request" | "response" | "close" | "error";
export type DesktopObservedRequestPhase = 'request' | 'response' | 'close' | 'error'
export type DesktopObservedRequestKind = "http" | "sse" | "ws";
export type DesktopObservedRequestKind = 'http' | 'sse' | 'ws'
export type DesktopObservedRequestSource = "session" | "main" | "transport";
export type DesktopObservedRequestSource = 'session' | 'main' | 'transport'
export interface DesktopObservedRequest {
id: string;
at: number;
phase: DesktopObservedRequestPhase;
kind: DesktopObservedRequestKind;
source: DesktopObservedRequestSource;
label: string;
method: string;
url: string;
partition: string | null;
resourceType: string | null;
status: number | null;
durationMs: number | null;
error: string | null;
id: string
at: number
phase: DesktopObservedRequestPhase
kind: DesktopObservedRequestKind
source: DesktopObservedRequestSource
label: string
method: string
url: string
partition: string | null
resourceType: string | null
status: number | null
durationMs: number | null
error: string | null
}
export interface DesktopObservedRequestSnapshot {
rendererAttached: boolean;
activeCount: number;
recent: DesktopObservedRequest[];
rendererAttached: boolean
activeCount: number
recent: DesktopObservedRequest[]
}
@@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest";
import { describe, expect, it } from 'vitest'
import {
PUBLISH_ACCOUNT_NOT_LOGGED_IN_MESSAGE,
@@ -13,73 +13,79 @@ import {
normalizeQiehaoPublishErrorMessage,
normalizeWangyihaoPublishErrorMessage,
normalizeWeixinGzhPublishErrorMessage,
} from "./publisher-errors";
} from './publisher-errors'
describe("publisher error normalization", () => {
it("normalizes Qiehao real-name authentication failures from raw platform text", () => {
describe('publisher error normalization', () => {
it('normalizes Qiehao real-name authentication failures from raw platform text', () => {
expect(
normalizePublisherErrorMessage("type:business, code:-5022, msg:user is not real name authentication"),
).toBe(QIEHAO_REAL_NAME_AUTH_MESSAGE);
});
normalizePublisherErrorMessage(
'type:business, code:-5022, msg:user is not real name authentication',
),
).toBe(QIEHAO_REAL_NAME_AUTH_MESSAGE)
})
it("recognizes Qiehao real-name authentication failures by business code", () => {
expect(isQiehaoRealNameAuthError("publish rejected", -5022)).toBe(true);
expect(normalizeQiehaoPublishErrorMessage("publish rejected", -5022)).toBe(QIEHAO_REAL_NAME_AUTH_MESSAGE);
});
it('recognizes Qiehao real-name authentication failures by business code', () => {
expect(isQiehaoRealNameAuthError('publish rejected', -5022)).toBe(true)
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('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(
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(
it('normalizes Wangyihao token missing failures', () => {
expect(normalizePublisherErrorMessage('wangyihao_token_missing')).toBe(
WANGYIHAO_TOKEN_MISSING_MESSAGE,
);
});
)
expect(normalizeWangyihaoPublishErrorMessage('Error: wangyihao_token_missing')).toBe(
WANGYIHAO_TOKEN_MISSING_MESSAGE,
)
})
it("normalizes Wangyihao draft parameter failures", () => {
expect(normalizePublisherErrorMessage("wangyihao_draft_save_failed:wangyihao_error_100002")).toBe(
it('normalizes Wangyihao draft parameter failures', () => {
expect(
normalizePublisherErrorMessage('wangyihao_draft_save_failed:wangyihao_error_100002'),
).toBe(WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE)
expect(normalizeWangyihaoPublishErrorMessage('wangyihao_draft_save_failed:参数错误')).toBe(
WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE,
);
expect(normalizeWangyihaoPublishErrorMessage("wangyihao_draft_save_failed:参数错误")).toBe(
WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE,
);
});
)
})
it("normalizes Wangyihao publish click failures", () => {
expect(normalizePublisherErrorMessage("wangyihao_publish_click_failed")).toBe(
it('normalizes Wangyihao publish click failures', () => {
expect(normalizePublisherErrorMessage('wangyihao_publish_click_failed')).toBe(
WANGYIHAO_PUBLISH_CLICK_MESSAGE,
);
expect(normalizeWangyihaoPublishErrorMessage("wangyihao_publish_click_failed:未找到发布按钮")).toBe(
WANGYIHAO_PUBLISH_CLICK_MESSAGE,
);
});
)
expect(
normalizeWangyihaoPublishErrorMessage('wangyihao_publish_click_failed:未找到发布按钮'),
).toBe(WANGYIHAO_PUBLISH_CLICK_MESSAGE)
})
it("normalizes Weixin GZH missing public URL failures", () => {
expect(normalizePublisherErrorMessage("weixin_gzh_public_url_missing:100000093")).toBe(
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(
)
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");
});
});
it('leaves unknown publisher errors unchanged', () => {
expect(normalizePublisherErrorMessage('qiehao_publish_failed')).toBe('qiehao_publish_failed')
})
})
@@ -1,119 +1,132 @@
export const QIEHAO_REAL_NAME_AUTH_MESSAGE = "企鹅号账号未完成实名认证,请先到企鹅号后台完成实名认证后再重试。";
export const PUBLISH_ACCOUNT_NOT_LOGGED_IN_MESSAGE = "发布账号登录态已失效,请重新打开平台后台完成登录后再重试。";
export const WANGYIHAO_TOKEN_MISSING_MESSAGE = "网易号发布凭证获取失败,请重新打开网易号后台确认登录状态。";
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<string, string> = {
baijiahao: "百家号",
bilibili: "bilibili",
dongchedi: "懂车帝",
jianshu: "简书",
juejin: "稀土掘金",
qiehao: "企鹅号",
smzdm: "什么值得买",
sohuhao: "搜狐号",
toutiaohao: "头条号",
wangyihao: "网易号",
weixin_gzh: "微信公众号",
zhihu: "知乎",
zol: "中关村在线",
};
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();
return trimmed ? trimmed : null;
const trimmed = value?.trim()
return trimmed ? trimmed : null
}
export function isQiehaoRealNameAuthError(
message: string | null | undefined,
code?: number | string | null,
): boolean {
const codeText = code == null ? "" : String(code).trim();
if (codeText === "-5022" || codeText === "5022") {
return true;
const codeText = code == null ? '' : String(code).trim()
if (codeText === '-5022' || codeText === '5022') {
return true
}
const normalized = normalizeErrorText(message);
const normalized = normalizeErrorText(message)
if (!normalized) {
return false;
return false
}
return /^qiehao_real_name_auth_required\b/i.test(normalized)
|| /\bcode\s*:\s*-?5022\b/i.test(normalized)
|| /user\s+is\s+not\s+real\s+name\s+authentication/i.test(normalized)
|| /(?:未|没有|尚未).{0,8}实名/.test(normalized)
|| /请.{0,8}实名认证/.test(normalized);
return (
/^qiehao_real_name_auth_required\b/i.test(normalized) ||
/\bcode\s*:\s*-?5022\b/i.test(normalized) ||
/user\s+is\s+not\s+real\s+name\s+authentication/i.test(normalized) ||
/(?:未|没有|尚未).{0,8}实名/.test(normalized) ||
/请.{0,8}实名认证/.test(normalized)
)
}
export function normalizeQiehaoPublishErrorMessage(
message: string | null | undefined,
code?: number | string | null,
): string | null {
const normalized = normalizeErrorText(message);
const normalized = normalizeErrorText(message)
if (!normalized) {
return null;
return null
}
return isQiehaoRealNameAuthError(normalized, code) ? QIEHAO_REAL_NAME_AUTH_MESSAGE : normalized;
return isQiehaoRealNameAuthError(normalized, code) ? QIEHAO_REAL_NAME_AUTH_MESSAGE : normalized
}
export function normalizePublisherLoginErrorMessage(message: string | null | undefined): string | null {
const normalized = normalizeErrorText(message);
export function normalizePublisherLoginErrorMessage(
message: string | null | undefined,
): string | null {
const normalized = normalizeErrorText(message)
if (!normalized) {
return null;
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;
return normalized
}
const platformLabel = PUBLISH_PLATFORM_LABELS[match[1]?.toLowerCase() ?? ""];
return platformLabel ? `${platformLabel}账号登录态已失效,请重新登录该平台后再重试。` : PUBLISH_ACCOUNT_NOT_LOGGED_IN_MESSAGE;
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);
export function normalizeWangyihaoPublishErrorMessage(
message: string | null | undefined,
): string | null {
const normalized = normalizeErrorText(message)
if (!normalized) {
return null;
return null
}
if (/\bwangyihao_token_missing\b/i.test(normalized)) {
return WANGYIHAO_TOKEN_MISSING_MESSAGE;
return WANGYIHAO_TOKEN_MISSING_MESSAGE
}
if (
/\bwangyihao_error_100002\b/i.test(normalized)
|| /\bwangyihao_draft_save_failed:.*参数错误/i.test(normalized)
/\bwangyihao_error_100002\b/i.test(normalized) ||
/\bwangyihao_draft_save_failed:.*参数错误/i.test(normalized)
) {
return WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE;
return WANGYIHAO_DRAFT_SAVE_PARAMETER_MESSAGE
}
if (/\bwangyihao_publish_click_failed\b/i.test(normalized)) {
return WANGYIHAO_PUBLISH_CLICK_MESSAGE;
return WANGYIHAO_PUBLISH_CLICK_MESSAGE
}
return normalized;
return normalized
}
export function normalizeWeixinGzhPublishErrorMessage(message: string | null | undefined): string | null {
const normalized = normalizeErrorText(message);
export function normalizeWeixinGzhPublishErrorMessage(
message: string | null | undefined,
): string | null {
const normalized = normalizeErrorText(message)
if (!normalized) {
return null;
return null
}
if (/\bweixin_gzh_public_url_missing\b/i.test(normalized)) {
return WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE;
return WEIXIN_GZH_PUBLIC_URL_MISSING_MESSAGE
}
return normalized;
return normalized
}
export function normalizePublisherErrorMessage(message: string | null | undefined): string | null {
const qiehaoMessage = normalizeQiehaoPublishErrorMessage(message);
const wangyihaoMessage = normalizeWangyihaoPublishErrorMessage(qiehaoMessage);
const loginMessage = normalizePublisherLoginErrorMessage(wangyihaoMessage);
return normalizeWeixinGzhPublishErrorMessage(loginMessage);
const qiehaoMessage = normalizeQiehaoPublishErrorMessage(message)
const wangyihaoMessage = normalizeWangyihaoPublishErrorMessage(qiehaoMessage)
const loginMessage = normalizePublisherLoginErrorMessage(wangyihaoMessage)
return normalizeWeixinGzhPublishErrorMessage(loginMessage)
}