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
+80 -73
View File
@@ -1,139 +1,146 @@
import dayjs from "dayjs";
import dayjs from 'dayjs'
import { i18n } from "@/i18n";
import { i18n } from '@/i18n'
const generateStatusMap: Record<string, { label: string; color: string }> = {
draft: { label: "status.generate.draft", color: "default" },
queued: { label: "status.generate.queued", color: "processing" },
generating: { label: "status.generate.generating", color: "processing" },
running: { label: "status.generate.running", color: "processing" },
completed: { label: "status.generate.completed", color: "success" },
failed: { label: "status.generate.failed", color: "error" },
};
draft: { label: 'status.generate.draft', color: 'default' },
queued: { label: 'status.generate.queued', color: 'processing' },
generating: { label: 'status.generate.generating', color: 'processing' },
running: { label: 'status.generate.running', color: 'processing' },
completed: { label: 'status.generate.completed', color: 'success' },
failed: { label: 'status.generate.failed', color: 'error' },
}
const publishStatusMap: Record<string, { label: string; color: string }> = {
unpublished: { label: "status.publish.unpublished", color: "default" },
publishing: { label: "status.publish.publishing", color: "processing" },
success: { label: "status.publish.success", color: "success" },
failed: { label: "status.publish.failed", color: "error" },
partial_success: { label: "status.publish.partial_success", color: "warning" },
published: { label: "status.publish.published", color: "success" },
publish_success: { label: "status.publish.publish_success", color: "success" },
publish_failed: { label: "status.publish.publish_failed", color: "error" },
pending_review: { label: "status.publish.failed", color: "error" },
};
unpublished: { label: 'status.publish.unpublished', color: 'default' },
publishing: { label: 'status.publish.publishing', color: 'processing' },
success: { label: 'status.publish.success', color: 'success' },
failed: { label: 'status.publish.failed', color: 'error' },
partial_success: { label: 'status.publish.partial_success', color: 'warning' },
published: { label: 'status.publish.published', color: 'success' },
publish_success: { label: 'status.publish.publish_success', color: 'success' },
publish_failed: { label: 'status.publish.publish_failed', color: 'error' },
pending_review: { label: 'status.publish.failed', color: 'error' },
}
export function formatDateTime(value?: string | null, pattern = "YYYY-MM-DD HH:mm"): string {
export function formatDateTime(value?: string | null, pattern = 'YYYY-MM-DD HH:mm'): string {
if (!value) {
return "--";
return '--'
}
const parsed = dayjs(value);
return parsed.isValid() ? parsed.format(pattern) : value;
const parsed = dayjs(value)
return parsed.isValid() ? parsed.format(pattern) : value
}
export function formatBytes(bytes: number, decimals = 2): string {
if (bytes === 0) return "0 B";
if (bytes === 0) return '0 B'
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const k = 1024
const dm = decimals < 0 ? 0 : decimals
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const i = Math.floor(Math.log(bytes) / Math.log(k));
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
}
export function formatPercentage(value?: number | null, decimals = 2): string {
if (typeof value !== "number" || Number.isNaN(value) || !Number.isFinite(value)) {
return "--";
if (typeof value !== 'number' || Number.isNaN(value) || !Number.isFinite(value)) {
return '--'
}
return value.toFixed(Math.max(0, decimals));
return value.toFixed(Math.max(0, decimals))
}
export function getGenerateStatusMeta(status?: string | null): { label: string; color: string } {
if (!status) {
return { label: "--", color: "default" };
return { label: '--', color: 'default' }
}
const meta = generateStatusMap[status];
return meta ? { label: i18n.global.t(meta.label), color: meta.color } : { label: status, color: "default" };
const meta = generateStatusMap[status]
return meta
? { label: i18n.global.t(meta.label), color: meta.color }
: { label: status, color: 'default' }
}
export function getPublishStatusMeta(status?: string | null): { label: string; color: string } {
if (!status) {
return { label: "--", color: "default" };
return { label: '--', color: 'default' }
}
const meta = publishStatusMap[status];
return meta ? { label: i18n.global.t(meta.label), color: meta.color } : { label: status, color: "default" };
const meta = publishStatusMap[status]
return meta
? { label: i18n.global.t(meta.label), color: meta.color }
: { label: status, color: 'default' }
}
export function getSourceTypeLabel(sourceType?: string | null, generationMode?: string | null): string {
export function getSourceTypeLabel(
sourceType?: string | null,
generationMode?: string | null,
): string {
if (!sourceType) {
return "--";
return '--'
}
if (sourceType === "template") {
return i18n.global.t("status.sourceType.template");
if (sourceType === 'template') {
return i18n.global.t('status.sourceType.template')
}
if (sourceType === "free_create") {
return i18n.global.t("status.sourceType.free_create");
if (sourceType === 'free_create') {
return i18n.global.t('status.sourceType.free_create')
}
if (sourceType === "imitation") {
return i18n.global.t("status.sourceType.imitation");
if (sourceType === 'imitation') {
return i18n.global.t('status.sourceType.imitation')
}
if (sourceType === "kol") {
return i18n.global.t("status.sourceType.kol");
if (sourceType === 'kol') {
return i18n.global.t('status.sourceType.kol')
}
if (sourceType === "custom_generation") {
if (generationMode === "schedule") {
return i18n.global.t("status.sourceType.schedule_task");
if (sourceType === 'custom_generation') {
if (generationMode === 'schedule') {
return i18n.global.t('status.sourceType.schedule_task')
}
if (generationMode === "instant") {
return i18n.global.t("status.sourceType.instant_task");
if (generationMode === 'instant') {
return i18n.global.t('status.sourceType.instant_task')
}
return i18n.global.t("status.sourceType.custom_generation");
return i18n.global.t('status.sourceType.custom_generation')
}
return sourceType;
return sourceType
}
export function formatCronExecutionTime(cronExpr?: string | null): string {
if (!cronExpr) {
return "--";
return '--'
}
const fiveFieldMatch = cronExpr.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/);
const fiveFieldMatch = cronExpr.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/)
if (fiveFieldMatch) {
const [, minute, hour] = fiveFieldMatch;
return `${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`;
const [, minute, hour] = fiveFieldMatch
return `${hour.padStart(2, '0')}:${minute.padStart(2, '0')}`
}
const sixFieldMatch = cronExpr.match(/^(\d{1,2})\s+(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/);
const sixFieldMatch = cronExpr.match(/^(\d{1,2})\s+(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/)
if (sixFieldMatch) {
const [, second, minute, hour] = sixFieldMatch;
return `${hour.padStart(2, "0")}:${minute.padStart(2, "0")}:${second.padStart(2, "0")}`;
const [, second, minute, hour] = sixFieldMatch
return `${hour.padStart(2, '0')}:${minute.padStart(2, '0')}:${second.padStart(2, '0')}`
}
return cronExpr;
return cronExpr
}
export function getTemplateMeta(templateKey: string): {
eyebrow: string;
helper: string;
accent: string;
action: string;
eyebrow: string
helper: string
accent: string
action: string
} {
const key = [
"top_x_article",
"product_review",
"research_report",
"brand_search_expansion",
'top_x_article',
'product_review',
'research_report',
'brand_search_expansion',
].includes(templateKey)
? templateKey
: "default";
: 'default'
return {
eyebrow: i18n.global.t(`templateMeta.${key}.eyebrow`),
helper: i18n.global.t(`templateMeta.${key}.helper`),
accent: i18n.global.t(`templateMeta.${key}.accent`),
action: i18n.global.t(`templateMeta.${key}.action`),
};
}
}