import type { RawRecord } from "@/lib/api/types"; export function asRecord(value: unknown): RawRecord { return value && typeof value === "object" && !Array.isArray(value) ? (value as RawRecord) : {}; } export function asArray(value: unknown): unknown[] { return Array.isArray(value) ? value : []; } export function text(value: unknown, fallback = "未记录"): string { if (typeof value === "string" && value.trim()) return value; if (typeof value === "number" || typeof value === "boolean") return String(value); return fallback; } export function maybeText(value: unknown): string | undefined { if (typeof value === "string" && value.trim()) return value; if (typeof value === "number" || typeof value === "boolean") return String(value); return undefined; } export function textList(value: unknown): string[] { if (!Array.isArray(value)) return []; return value.map((item) => text(item, "")).filter(Boolean); } export function countBy(items: T[], getKey: (item: T) => string | undefined): Record { return items.reduce>((acc, item) => { const key = getKey(item); if (!key) return acc; acc[key] = (acc[key] || 0) + 1; return acc; }, {}); } export function compactCountMap(counts: Record, limit = 3): string { const entries = Object.entries(counts).sort((a, b) => b[1] - a[1]); if (!entries.length) return "无"; return entries.slice(0, limit).map(([key, value]) => `${label(key)} ${value}`).join(" · "); } // 首轮取词「来源类型」标签的唯一真相源。sourceLabel / methodLabel / label 都从这里取, // 改文案只改这一处(避免之前散在 3 份 map 里、改一个要改 3 处)。 export const SOURCE_TYPE_LABELS: Record = { seed_term: "从需求池直出", piaoquan_topic_point: "票圈帖子具体的点", query_seed_point: "票圈帖子具体的点", category_leaf_element: "分类叶子元素" }; export function label(value: string): string { const labels: Record = { ...SOURCE_TYPE_LABELS, item_single: "使用原始需求词", tag_query: "从视频标签继续游走", author_works: "从作者继续游走", query_next_page: "翻页", search_query_direct: "首轮搜索", pattern_itemset: "来自需求 Pattern", pattern_search_query: "来自需求 Pattern", ADD_TO_CONTENT_POOL: "入池", KEEP_CONTENT_FOR_REVIEW: "待复看", REJECT_CONTENT: "淘汰", success: "成功", skipped: "跳过", failed: "失败", rule_blocked: "规则阻断", pending: "待处理" }; return labels[value] || "系统原因待补充"; } export function scoreLabel(value: unknown): string { if (typeof value === "number" && Number.isFinite(value)) return `${Math.round(value)}`; if (typeof value === "string" && value.trim()) return value; return "未进入打分"; } export function shortId(value: unknown): string { const raw = text(value, ""); if (raw.length <= 18) return raw || "未记录"; return `${raw.slice(0, 8)}...${raw.slice(-6)}`; }