import { normalizeRateDisplay } from "../../shared/rate-normalizer"; import { escapeCsvCell } from "../../shared/csv"; import type { MarketRecord } from "./types"; type CsvColumn = { header: string; readValue: (record: MarketRecord) => string; }; const FALLBACK_BASE_COLUMNS: CsvColumn[] = [ { header: "达人ID", readValue: (record: MarketRecord) => record.authorId }, { header: "达人名称", readValue: (record: MarketRecord) => record.authorName }, { header: "地区", readValue: (record: MarketRecord) => record.location ?? "" }, { header: "21-60s报价", readValue: (record: MarketRecord) => record.price21To60s ?? "" } ]; const RATE_COLUMNS: CsvColumn[] = [ { header: "单视频看后搜率", readValue: (record: MarketRecord) => record.rates?.singleVideoAfterSearchRate ? normalizeRateDisplay(record.rates.singleVideoAfterSearchRate) : "" }, { header: "个人视频看后搜率", readValue: (record: MarketRecord) => record.rates?.personalVideoAfterSearchRate ? normalizeRateDisplay(record.rates.personalVideoAfterSearchRate) : "" } ]; export function buildMarketCsv(records: MarketRecord[]): string { const baseColumns = buildBaseColumns(records); const csvColumns = [...baseColumns, ...RATE_COLUMNS]; const headerLine = csvColumns.map((column) => column.header).join(","); const rowLines = records.map((record) => csvColumns.map((column) => escapeCsvCell(column.readValue(record))).join(",") ); return [headerLine, ...rowLines].join("\n"); } function buildBaseColumns(records: MarketRecord[]): CsvColumn[] { const orderedHeaders: string[] = []; const seenHeaders = new Set(); records.forEach((record) => { Object.keys(record.exportFields ?? {}).forEach((header) => { if (seenHeaders.has(header)) { return; } seenHeaders.add(header); orderedHeaders.push(header); }); }); if (orderedHeaders.length === 0) { return FALLBACK_BASE_COLUMNS; } return orderedHeaders.map((header) => ({ header, readValue: (record: MarketRecord) => record.exportFields?.[header] ?? "" })); }