chore(frontend): introduce prettier + eslint and prune unused code
- 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:
@@ -1,60 +1,57 @@
|
||||
import type { DesktopAccountInfo, MediaPlatform } from "@geo/shared-types";
|
||||
import type { DesktopAccountInfo, MediaPlatform } from '@geo/shared-types'
|
||||
|
||||
import { resolveApiURL } from "@/lib/api";
|
||||
import { resolveAccountCheckedAt, resolveAccountHealth } from "@/lib/desktop-account-runtime";
|
||||
import { resolveApiURL } from '@/lib/api'
|
||||
import { resolveAccountCheckedAt, resolveAccountHealth } from '@/lib/desktop-account-runtime'
|
||||
import {
|
||||
getPublishPlatformMeta,
|
||||
isMediaPublishAccount,
|
||||
isPublishPlatformId,
|
||||
normalizePublishPlatformId,
|
||||
} from "@/lib/publish-platforms";
|
||||
} from '@/lib/publish-platforms'
|
||||
|
||||
export type PublishState = "immediate" | "queued" | "unavailable";
|
||||
export type PublishState = 'immediate' | 'queued' | 'unavailable'
|
||||
|
||||
export interface PublishAccountCard {
|
||||
id: string;
|
||||
platformId: string;
|
||||
platformName: string;
|
||||
platformShortName: string;
|
||||
platformAccent: string;
|
||||
platformLogoUrl: string | null;
|
||||
displayName: string;
|
||||
platformUid: string;
|
||||
avatarUrl: string | null;
|
||||
health: DesktopAccountInfo["health"];
|
||||
verifiedAt: string | null;
|
||||
clientId: string | null;
|
||||
clientOnline: boolean | null;
|
||||
clientDeviceName: string | null;
|
||||
clientLastSeenAt: string | null;
|
||||
publishState: PublishState;
|
||||
selectable: boolean;
|
||||
statusText: string;
|
||||
id: string
|
||||
platformId: string
|
||||
platformName: string
|
||||
platformShortName: string
|
||||
platformAccent: string
|
||||
platformLogoUrl: string | null
|
||||
displayName: string
|
||||
platformUid: string
|
||||
avatarUrl: string | null
|
||||
health: DesktopAccountInfo['health']
|
||||
verifiedAt: string | null
|
||||
clientId: string | null
|
||||
clientOnline: boolean | null
|
||||
clientDeviceName: string | null
|
||||
clientLastSeenAt: string | null
|
||||
publishState: PublishState
|
||||
selectable: boolean
|
||||
statusText: string
|
||||
}
|
||||
|
||||
const platformLogoCatalog: Record<string, string> = {
|
||||
toutiaohao: "/logos/logo_toutiao.png",
|
||||
baijiahao: "/logos/logo_baijiahao.png",
|
||||
sohuhao: "/logos/logo_souhu.png",
|
||||
qiehao: "/logos/logo_qiehao.png",
|
||||
zhihu: "/logos/logo_zhihu.png",
|
||||
wangyihao: "/logos/logo_wangyihao.png",
|
||||
jianshu: "/logos/logo_jianshu.svg",
|
||||
bilibili: "/logos/logo_bilibili.png",
|
||||
juejin: "/logos/logo_juejin.png",
|
||||
smzdm: "/logos/logo_smzdm.svg",
|
||||
weixin_gzh: "/logos/logo_weixin_gzh.svg",
|
||||
zol: "/logos/logo_zol.png",
|
||||
dongchedi: "/logos/logo_dongchedi.svg",
|
||||
};
|
||||
toutiaohao: '/logos/logo_toutiao.png',
|
||||
baijiahao: '/logos/logo_baijiahao.png',
|
||||
sohuhao: '/logos/logo_souhu.png',
|
||||
qiehao: '/logos/logo_qiehao.png',
|
||||
zhihu: '/logos/logo_zhihu.png',
|
||||
wangyihao: '/logos/logo_wangyihao.png',
|
||||
jianshu: '/logos/logo_jianshu.svg',
|
||||
bilibili: '/logos/logo_bilibili.png',
|
||||
juejin: '/logos/logo_juejin.png',
|
||||
smzdm: '/logos/logo_smzdm.svg',
|
||||
weixin_gzh: '/logos/logo_weixin_gzh.svg',
|
||||
zol: '/logos/logo_zol.png',
|
||||
dongchedi: '/logos/logo_dongchedi.svg',
|
||||
}
|
||||
|
||||
export function buildPublishPlatformMap(platforms: MediaPlatform[]): Map<string, MediaPlatform> {
|
||||
return new Map(
|
||||
platforms.map((platform) => [
|
||||
normalizePublishPlatformId(platform.platform_id),
|
||||
platform,
|
||||
]),
|
||||
);
|
||||
platforms.map((platform) => [normalizePublishPlatformId(platform.platform_id), platform]),
|
||||
)
|
||||
}
|
||||
|
||||
export function buildPublishAccountCards(
|
||||
@@ -62,44 +59,45 @@ export function buildPublishAccountCards(
|
||||
platformMap: Map<string, MediaPlatform>,
|
||||
preferredPlatformIds: string[] = [],
|
||||
): PublishAccountCard[] {
|
||||
const preferredPlatforms = new Set(preferredPlatformIds.map(normalizePublishPlatformId));
|
||||
const preferredPlatforms = new Set(preferredPlatformIds.map(normalizePublishPlatformId))
|
||||
|
||||
return accounts
|
||||
.filter((account) => {
|
||||
if (!isMediaPublishAccount(account)) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
const platformId = normalizePublishPlatformId(account.platform);
|
||||
return platformMap.has(platformId) || isPublishPlatformId(platformId);
|
||||
const platformId = normalizePublishPlatformId(account.platform)
|
||||
return platformMap.has(platformId) || isPublishPlatformId(platformId)
|
||||
})
|
||||
.map((account) => buildPublishAccountCard(account, platformMap))
|
||||
.sort((left, right) => {
|
||||
const preferredGap =
|
||||
Number(preferredPlatforms.has(right.platformId)) - Number(preferredPlatforms.has(left.platformId));
|
||||
Number(preferredPlatforms.has(right.platformId)) -
|
||||
Number(preferredPlatforms.has(left.platformId))
|
||||
if (preferredGap !== 0) {
|
||||
return preferredGap;
|
||||
return preferredGap
|
||||
}
|
||||
|
||||
const publishGap = publishRank(left.publishState) - publishRank(right.publishState);
|
||||
const publishGap = publishRank(left.publishState) - publishRank(right.publishState)
|
||||
if (publishGap !== 0) {
|
||||
return publishGap;
|
||||
return publishGap
|
||||
}
|
||||
|
||||
const leftVerifiedAt = Date.parse(left.verifiedAt ?? "") || 0;
|
||||
const rightVerifiedAt = Date.parse(right.verifiedAt ?? "") || 0;
|
||||
return rightVerifiedAt - leftVerifiedAt;
|
||||
});
|
||||
const leftVerifiedAt = Date.parse(left.verifiedAt ?? '') || 0
|
||||
const rightVerifiedAt = Date.parse(right.verifiedAt ?? '') || 0
|
||||
return rightVerifiedAt - leftVerifiedAt
|
||||
})
|
||||
}
|
||||
|
||||
export function buildPublishAccountCard(
|
||||
account: DesktopAccountInfo,
|
||||
platformMap: Map<string, MediaPlatform>,
|
||||
): PublishAccountCard {
|
||||
const platformId = normalizePublishPlatformId(account.platform);
|
||||
const platform = platformMap.get(platformId);
|
||||
const fallback = getPublishPlatformMeta(platformId);
|
||||
const publishState = resolvePublishState(account);
|
||||
const health = resolveAccountHealth(account);
|
||||
const platformId = normalizePublishPlatformId(account.platform)
|
||||
const platform = platformMap.get(platformId)
|
||||
const fallback = getPublishPlatformMeta(platformId)
|
||||
const publishState = resolvePublishState(account)
|
||||
const health = resolveAccountHealth(account)
|
||||
|
||||
return {
|
||||
id: account.id,
|
||||
@@ -118,125 +116,130 @@ export function buildPublishAccountCard(
|
||||
clientDeviceName: account.client_device_name,
|
||||
clientLastSeenAt: account.client_last_seen_at,
|
||||
publishState,
|
||||
selectable: publishState !== "unavailable",
|
||||
selectable: publishState !== 'unavailable',
|
||||
statusText: resolvePublishStatusText(account, publishState),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function resolvePublishState(account: DesktopAccountInfo): PublishState {
|
||||
if (resolveAccountHealth(account) !== "live") {
|
||||
return "unavailable";
|
||||
if (resolveAccountHealth(account) !== 'live') {
|
||||
return 'unavailable'
|
||||
}
|
||||
if (!account.client_id) {
|
||||
return "unavailable";
|
||||
return 'unavailable'
|
||||
}
|
||||
return account.client_online === true ? "immediate" : "queued";
|
||||
return account.client_online === true ? 'immediate' : 'queued'
|
||||
}
|
||||
|
||||
export function publishRank(state: PublishState): number {
|
||||
switch (state) {
|
||||
case "immediate":
|
||||
return 0;
|
||||
case "queued":
|
||||
return 1;
|
||||
case 'immediate':
|
||||
return 0
|
||||
case 'queued':
|
||||
return 1
|
||||
default:
|
||||
return 2;
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
export function publishStateLabel(state: PublishState): string {
|
||||
switch (state) {
|
||||
case "immediate":
|
||||
return "立即发布";
|
||||
case "queued":
|
||||
return "离线排队";
|
||||
case 'immediate':
|
||||
return '立即发布'
|
||||
case 'queued':
|
||||
return '离线排队'
|
||||
default:
|
||||
return "不可发布";
|
||||
return '不可发布'
|
||||
}
|
||||
}
|
||||
|
||||
export function publishStatusShortLabel(state: PublishState): string {
|
||||
switch (state) {
|
||||
case "immediate":
|
||||
return "客户端在线";
|
||||
case "queued":
|
||||
return "离线可排队";
|
||||
case 'immediate':
|
||||
return '客户端在线'
|
||||
case 'queued':
|
||||
return '离线可排队'
|
||||
default:
|
||||
return "不可发布";
|
||||
return '不可发布'
|
||||
}
|
||||
}
|
||||
|
||||
export function healthLabel(health: DesktopAccountInfo["health"]): string {
|
||||
export function healthLabel(health: DesktopAccountInfo['health']): string {
|
||||
switch (health) {
|
||||
case "live":
|
||||
return "授权正常";
|
||||
case "captcha":
|
||||
return "待处理";
|
||||
case "risk":
|
||||
return "风险观察";
|
||||
case 'live':
|
||||
return '授权正常'
|
||||
case 'captcha':
|
||||
return '待处理'
|
||||
case 'risk':
|
||||
return '风险观察'
|
||||
default:
|
||||
return "授权异常";
|
||||
return '授权异常'
|
||||
}
|
||||
}
|
||||
|
||||
export function healthColor(health: DesktopAccountInfo["health"]): string {
|
||||
export function healthColor(health: DesktopAccountInfo['health']): string {
|
||||
switch (health) {
|
||||
case "live":
|
||||
return "green";
|
||||
case "captcha":
|
||||
return "orange";
|
||||
case "risk":
|
||||
return "gold";
|
||||
case 'live':
|
||||
return 'green'
|
||||
case 'captcha':
|
||||
return 'orange'
|
||||
case 'risk':
|
||||
return 'gold'
|
||||
default:
|
||||
return "red";
|
||||
return 'red'
|
||||
}
|
||||
}
|
||||
|
||||
export function clientStatusLabel(card: PublishAccountCard): string {
|
||||
if (!card.clientId) {
|
||||
return "未绑定客户端";
|
||||
return '未绑定客户端'
|
||||
}
|
||||
return card.clientOnline ? "客户端在线" : "客户端离线";
|
||||
return card.clientOnline ? '客户端在线' : '客户端离线'
|
||||
}
|
||||
|
||||
export function clientStatusColor(card: PublishAccountCard): string {
|
||||
if (!card.clientId) {
|
||||
return "default";
|
||||
return 'default'
|
||||
}
|
||||
return card.clientOnline ? "green" : "gold";
|
||||
return card.clientOnline ? 'green' : 'gold'
|
||||
}
|
||||
|
||||
export function accountInitial(card: Pick<PublishAccountCard, "displayName" | "platformShortName">): string {
|
||||
const trimmed = card.displayName.trim();
|
||||
return trimmed ? trimmed.slice(0, 1).toUpperCase() : card.platformShortName;
|
||||
export function accountInitial(
|
||||
card: Pick<PublishAccountCard, 'displayName' | 'platformShortName'>,
|
||||
): string {
|
||||
const trimmed = card.displayName.trim()
|
||||
return trimmed ? trimmed.slice(0, 1).toUpperCase() : card.platformShortName
|
||||
}
|
||||
|
||||
export function resolvePlatformLogoUrl(platformId: string, remoteLogoUrl?: string | null): string | null {
|
||||
const localLogoUrl = platformLogoCatalog[platformId];
|
||||
export function resolvePlatformLogoUrl(
|
||||
platformId: string,
|
||||
remoteLogoUrl?: string | null,
|
||||
): string | null {
|
||||
const localLogoUrl = platformLogoCatalog[platformId]
|
||||
if (localLogoUrl) {
|
||||
return localLogoUrl;
|
||||
return localLogoUrl
|
||||
}
|
||||
const resolvedRemoteLogoUrl = resolveApiURL(remoteLogoUrl);
|
||||
return resolvedRemoteLogoUrl || null;
|
||||
const resolvedRemoteLogoUrl = resolveApiURL(remoteLogoUrl)
|
||||
return resolvedRemoteLogoUrl || null
|
||||
}
|
||||
|
||||
function resolvePublishStatusText(account: DesktopAccountInfo, publishState: PublishState): string {
|
||||
if (publishState === "immediate") {
|
||||
return "客户端在线,RabbitMQ 会立即唤醒桌面端开始发布。";
|
||||
if (publishState === 'immediate') {
|
||||
return '客户端在线,RabbitMQ 会立即唤醒桌面端开始发布。'
|
||||
}
|
||||
if (publishState === "queued") {
|
||||
return "客户端当前离线,任务会先落库排队,等桌面端上线后自动继续发布。";
|
||||
if (publishState === 'queued') {
|
||||
return '客户端当前离线,任务会先落库排队,等桌面端上线后自动继续发布。'
|
||||
}
|
||||
if (resolveAccountHealth(account) !== "live") {
|
||||
return "该账号授权状态异常,请先在桌面端重新校验或重新授权。";
|
||||
if (resolveAccountHealth(account) !== 'live') {
|
||||
return '该账号授权状态异常,请先在桌面端重新校验或重新授权。'
|
||||
}
|
||||
return "该账号还没有绑定桌面客户端,当前不能进入发布队列。";
|
||||
return '该账号还没有绑定桌面客户端,当前不能进入发布队列。'
|
||||
}
|
||||
|
||||
function normalizePlatformUid(value?: string | null): string {
|
||||
let normalized = String(value ?? "").trim();
|
||||
while (normalized.toLowerCase().startsWith("platform:")) {
|
||||
normalized = normalized.slice("platform:".length).trim();
|
||||
let normalized = String(value ?? '').trim()
|
||||
while (normalized.toLowerCase().startsWith('platform:')) {
|
||||
normalized = normalized.slice('platform:'.length).trim()
|
||||
}
|
||||
return normalized || "--";
|
||||
return normalized || '--'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user