/** * AI Settings 数据变换工具(ARCHITECTURE.md §11.3 DoD - 纯函数单测) * * 所有格式化/映射函数均为纯函数,便于 vitest 单测。 * 关联:ARCHITECTURE.md §11.3 DoD "数据变换/权限判断等纯函数有 vitest 单测" */ /** AI Provider 类型标签映射(对齐 CICD:zhipu/openai/gemini/ollama/custom) */ export const PROVIDER_TYPE_LABEL: Record = { zhipu: "智谱 AI", openai: "OpenAI", gemini: "Google Gemini", ollama: "Ollama(本地)", custom: "自定义", }; /** AI Provider 类型支持的取值列表 */ export const PROVIDER_TYPES: readonly string[] = [ "zhipu", "openai", "gemini", "ollama", "custom", ] as const; /** AI Provider 可见性枚举值列表(@contract-pending,MSW 兜底) */ export const PROVIDER_VISIBILITY_OPTIONS: readonly string[] = [ "private", "shared", "public", ] as const; /** AI Provider 可见性标签映射 */ export const PROVIDER_VISIBILITY_LABEL: Record = { private: "仅自己可见", shared: "组织共享", public: "全员可见", }; /** * 将 Provider 类型代码映射为展示标签。未知值回退为原始值。 */ export function formatProviderType(type: string): string { return PROVIDER_TYPE_LABEL[type] ?? type; } /** * 判断字符串是否为受支持的 Provider 类型。 */ export function isValidProviderType(type: string): boolean { return PROVIDER_TYPES.includes(type); } /** * 将 Provider 可见性代码映射为展示标签。未知值回退为原始值。 */ export function formatProviderVisibility(visibility: string): string { return PROVIDER_VISIBILITY_LABEL[visibility] ?? visibility; } /** * 根据 isActive 返回 Tailwind 徽章语义类名。 */ export function activeToBadgeClass(isActive: boolean): string { return isActive ? "bg-success/10 text-success" : "bg-muted text-muted-foreground"; } /** * 根据 isActive 返回展示标签。 */ export function formatActiveLabel(isActive: boolean): string { return isActive ? "active" : "inactive"; } /** * 格式化 AI 用量费用(分)为元展示字符串。 * 输入无效返回 "¥0.00"。 */ export function formatCostCents(costCents: number): string { if (!Number.isFinite(costCents) || costCents < 0) return "¥0.00"; const yuan = costCents / 100; return `¥${yuan.toFixed(2)}`; } /** * 格式化数字为千分位展示字符串。 * 输入无效返回 "0"。 */ export function formatNumber(value: number): string { if (!Number.isFinite(value) || value < 0) return "0"; return value.toLocaleString("zh-CN"); } /** * 截断 API Key 用于列表展示(仅保留前 4 + 后 4 字符,中间以 ... 占位)。 * 输入为空返回占位符 "--"。 */ export function maskApiKey(apiKey: string | null | undefined): string { if (!apiKey || apiKey.trim().length === 0) return "--"; const text = apiKey.trim(); if (text.length <= 8) return text; return `${text.slice(0, 4)}...${text.slice(-4)}`; } /** * 截断 BaseUrl 用于列表展示(超过 maxLen 字符时截断并加省略号)。 * maxLen 默认 40。 */ export function truncateBaseUrl( url: string | null | undefined, maxLen = 40, ): string { if (!url) return "--"; const text = url.trim(); if (text.length <= maxLen) return text; return `${text.slice(0, maxLen)}...`; } /** * 格式化 ISO 日期字符串为本地化展示(zh-CN,仅年月日)。 * 输入无效时返回占位符。 */ export function formatAiDate(isoDate: string | null | undefined): string { if (!isoDate) return "--"; const d = new Date(isoDate); if (Number.isNaN(d.getTime())) return "--"; return d.toLocaleDateString("zh-CN", { year: "numeric", month: "2-digit", day: "2-digit", }); }