format.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import type { RawRecord } from "@/lib/api/types";
  2. export function asRecord(value: unknown): RawRecord {
  3. return value && typeof value === "object" && !Array.isArray(value) ? (value as RawRecord) : {};
  4. }
  5. export function asArray(value: unknown): unknown[] {
  6. return Array.isArray(value) ? value : [];
  7. }
  8. export function text(value: unknown, fallback = "未记录"): string {
  9. if (typeof value === "string" && value.trim()) return value;
  10. if (typeof value === "number" || typeof value === "boolean") return String(value);
  11. return fallback;
  12. }
  13. export function maybeText(value: unknown): string | undefined {
  14. if (typeof value === "string" && value.trim()) return value;
  15. if (typeof value === "number" || typeof value === "boolean") return String(value);
  16. return undefined;
  17. }
  18. export function textList(value: unknown): string[] {
  19. if (!Array.isArray(value)) return [];
  20. return value.map((item) => text(item, "")).filter(Boolean);
  21. }
  22. export function countBy<T>(items: T[], getKey: (item: T) => string | undefined): Record<string, number> {
  23. return items.reduce<Record<string, number>>((acc, item) => {
  24. const key = getKey(item);
  25. if (!key) return acc;
  26. acc[key] = (acc[key] || 0) + 1;
  27. return acc;
  28. }, {});
  29. }
  30. export function compactCountMap(counts: Record<string, number>, limit = 3): string {
  31. const entries = Object.entries(counts).sort((a, b) => b[1] - a[1]);
  32. if (!entries.length) return "无";
  33. return entries.slice(0, limit).map(([key, value]) => `${label(key)} ${value}`).join(" · ");
  34. }
  35. // 首轮取词「来源类型」标签的唯一真相源。sourceLabel / methodLabel / label 都从这里取,
  36. // 改文案只改这一处(避免之前散在 3 份 map 里、改一个要改 3 处)。
  37. export const SOURCE_TYPE_LABELS: Record<string, string> = {
  38. seed_term: "从需求池直出",
  39. piaoquan_topic_point: "票圈帖子具体的点",
  40. query_seed_point: "票圈帖子具体的点",
  41. category_leaf_element: "分类叶子元素"
  42. };
  43. export function label(value: string): string {
  44. const labels: Record<string, string> = {
  45. ...SOURCE_TYPE_LABELS,
  46. item_single: "使用原始需求词",
  47. tag_query: "从视频标签继续游走",
  48. author_works: "从作者继续游走",
  49. query_next_page: "翻页",
  50. search_query_direct: "首轮搜索",
  51. pattern_itemset: "来自需求 Pattern",
  52. pattern_search_query: "来自需求 Pattern",
  53. ADD_TO_CONTENT_POOL: "入池",
  54. KEEP_CONTENT_FOR_REVIEW: "待复看",
  55. REJECT_CONTENT: "淘汰",
  56. success: "成功",
  57. skipped: "跳过",
  58. failed: "失败",
  59. rule_blocked: "规则阻断",
  60. pending: "待处理"
  61. };
  62. return labels[value] || "系统原因待补充";
  63. }
  64. export function scoreLabel(value: unknown): string {
  65. if (typeof value === "number" && Number.isFinite(value)) return `${Math.round(value)}`;
  66. if (typeof value === "string" && value.trim()) return value;
  67. return "未进入打分";
  68. }
  69. export function shortId(value: unknown): string {
  70. const raw = text(value, "");
  71. if (raw.length <= 18) return raw || "未记录";
  72. return `${raw.slice(0, 8)}...${raw.slice(-6)}`;
  73. }