import type { KeywordAnalysisRow, ProductPlanningCompetitorAnalysisRecord, ProductPlanningKeywordInsightGroup, ProductPlanningKeywordInsightSuggestion, ProductPlanningTaobaoItem, } from "./types"; function formatPlatform(value: ProductPlanningTaobaoItem["platform"], isTmall: boolean) { if (value === "jd") return "京东"; return isTmall ? "天猫" : "淘宝"; } function formatDataSource(value: ProductPlanningTaobaoItem["dataSource"]) { if (value === "detail-plus") return "详情增强"; if (value === "legacy") return "旧接口兜底"; if (value === "jd") return "京东接口"; return "未标记"; } function formatPropertySummary(row: ProductPlanningTaobaoItem, limit = 10) { return row.properties .slice(0, limit) .map((entry) => `${entry.name}:${entry.value}`) .join(" | "); } function formatConversionRate(value?: number) { if (typeof value !== "number") return ""; return `${(value * 100).toFixed(2)}%`; } function triggerBlobDownload(blob: Blob, fileName: string) { const url = URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = fileName; document.body.appendChild(anchor); anchor.click(); document.body.removeChild(anchor); URL.revokeObjectURL(url); } export async function downloadKeywordAnalysisWorkbook( rows: KeywordAnalysisRow[], baseFileName = "商品策划工具_关键词分析" ) { const { Workbook } = await import("exceljs"); const workbook = new Workbook(); const sheet = workbook.addWorksheet("关键词拆词结果"); sheet.columns = [ { header: "词语", key: "keyword", width: 24 }, { header: "拆分片段", key: "segments", width: 28 }, { header: "标签分类", key: "category", width: 16 }, { header: "出现次数", key: "occurrenceCount", width: 12 }, { header: "搜索人气", key: "searchPopularity", width: 14 }, { header: "支付转化率", key: "conversionRate", width: 14 }, ]; sheet.getRow(1).font = { bold: true }; sheet.views = [{ state: "frozen", ySplit: 1 }]; for (const row of rows) { sheet.addRow({ keyword: row.keyword, segments: row.segments.join(" / "), category: row.category, occurrenceCount: row.occurrenceCount, searchPopularity: row.searchPopularity ?? "", conversionRate: formatConversionRate(row.conversionRate), }); } const buffer = await workbook.xlsx.writeBuffer(); const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }); triggerBlobDownload(blob, `${baseFileName}_${new Date().toISOString().slice(0, 10)}.xlsx`); } async function downloadWorkbook(params: { worksheetName: string; columns: Array<{ header: string; key: string; width: number }>; rows: Array>; fileName: string; }) { const { Workbook } = await import("exceljs"); const workbook = new Workbook(); const sheet = workbook.addWorksheet(params.worksheetName); sheet.columns = params.columns; sheet.getRow(1).font = { bold: true }; sheet.views = [{ state: "frozen", ySplit: 1 }]; for (const row of params.rows) { sheet.addRow(row); } const buffer = await workbook.xlsx.writeBuffer(); const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }); triggerBlobDownload(blob, `${params.fileName}_${new Date().toISOString().slice(0, 10)}.xlsx`); } export async function downloadCompetitorWorkbook( rows: ProductPlanningTaobaoItem[], baseFileName = "商品策划工具_竞品分析" ) { await downloadWorkbook({ worksheetName: "竞品分析", fileName: baseFileName, columns: [ { header: "数据来源", key: "dataSource", width: 14 }, { header: "平台", key: "platform", width: 12 }, { header: "商品ID", key: "itemId", width: 18 }, { header: "请求ID", key: "requestedItemId", width: 18 }, { header: "商品标题", key: "title", width: 40 }, { header: "品牌", key: "brand", width: 18 }, { header: "店铺", key: "shopName", width: 26 }, { header: "店铺ID", key: "shopId", width: 18 }, { header: "发货地", key: "location", width: 18 }, { header: "类目ID", key: "categoryId", width: 18 }, { header: "当前价格", key: "price", width: 14 }, { header: "划线价格", key: "originalPrice", width: 14 }, { header: "总销量", key: "totalSales", width: 14 }, { header: "近期销量", key: "recentSales", width: 14 }, { header: "材质", key: "material", width: 24 }, { header: "详细材质", key: "detailedMaterial", width: 36 }, { header: "标准品类", key: "standardProductType", width: 22 }, { header: "市场分类", key: "marketCategoryName", width: 22 }, { header: "价格带", key: "priceBand", width: 16 }, { header: "SKU数量", key: "skuCount", width: 12 }, { header: "主图数", key: "itemImageCount", width: 12 }, { header: "详情图数", key: "detailImageCount", width: 12 }, { header: "主图视频", key: "videoUrl", width: 36 }, { header: "企划详情ID", key: "detailStorageRecordId", width: 14 }, { header: "产品记录ID", key: "productRecordId", width: 14 }, { header: "参数预览", key: "propertySummary", width: 80 }, { header: "商品链接", key: "detailUrl", width: 48 }, { header: "来源链接", key: "sourceUrl", width: 48 }, ], rows: rows.map((row) => ({ dataSource: formatDataSource(row.dataSource), platform: formatPlatform(row.platform, row.isTmall), itemId: row.itemId, requestedItemId: row.requestedItemId || row.itemId, title: row.title, brand: row.brand || "", shopName: row.shopName || "", shopId: row.shopId || "", location: row.location || "", categoryId: row.categoryId || "", price: row.price ?? "", originalPrice: row.originalPrice ?? "", totalSales: row.totalSales ?? "", recentSales: row.recentSales ?? "", material: row.material || "", detailedMaterial: row.detailedMaterial || "", standardProductType: row.standardProductType || "", marketCategoryName: row.marketCategoryName || "", priceBand: row.priceBand || "", skuCount: row.skuCount ?? row.skus.length, itemImageCount: row.itemImages.length, detailImageCount: row.detailImages.length, videoUrl: row.videoUrl || "", detailStorageRecordId: row.detailStorageRecordId || "", productRecordId: row.productRecordId || "", propertySummary: formatPropertySummary(row), detailUrl: row.detailUrl || "", sourceUrl: row.sourceUrl || "", })), }); } export async function downloadSalesWorkbook( rows: ProductPlanningTaobaoItem[], baseFileName = "商品策划工具_ID销量查询" ) { await downloadWorkbook({ worksheetName: "ID销量查询", fileName: baseFileName, columns: [ { header: "平台", key: "platform", width: 12 }, { header: "商品ID", key: "itemId", width: 18 }, { header: "商品标题", key: "title", width: 40 }, { header: "近期销量", key: "recentSales", width: 14 }, { header: "当前价格", key: "price", width: 14 }, { header: "划线价格", key: "originalPrice", width: 14 }, { header: "品牌", key: "brand", width: 18 }, { header: "店铺", key: "shopName", width: 26 }, { header: "发货地", key: "location", width: 18 }, { header: "材质", key: "material", width: 22 }, { header: "详情图数", key: "detailImageCount", width: 12 }, { header: "参数预览", key: "propertySummary", width: 80 }, { header: "商品链接", key: "detailUrl", width: 48 }, ], rows: rows.map((row) => ({ platform: formatPlatform(row.platform, row.isTmall), itemId: row.itemId, title: row.title, recentSales: row.recentSales ?? "", price: row.price ?? "", originalPrice: row.originalPrice ?? "", brand: row.brand || "", shopName: row.shopName || "", location: row.location || "", material: row.material || "", detailImageCount: row.detailImages.length, propertySummary: formatPropertySummary(row), detailUrl: row.detailUrl || "", })), }); } export async function downloadKeywordInsightSuggestionsWorkbook( rows: ProductPlanningKeywordInsightSuggestion[], baseFileName = "商品策划工具_关键词洞察_搜索建议" ) { await downloadWorkbook({ worksheetName: "搜索建议", fileName: baseFileName, columns: [ { header: "排名", key: "rank", width: 10 }, { header: "关键词", key: "keyword", width: 28 }, { header: "权重", key: "weight", width: 16 }, ], rows: rows.map((row) => ({ rank: row.rank, keyword: row.keyword, weight: row.weight, })), }); } export async function downloadKeywordInsightGroupsWorkbook( rows: ProductPlanningKeywordInsightGroup[], baseFileName = "商品策划工具_关键词洞察_标签分组" ) { await downloadWorkbook({ worksheetName: "标签分组", fileName: baseFileName, columns: [ { header: "组序号", key: "index", width: 10 }, { header: "分组类型", key: "type", width: 20 }, { header: "标签名称", key: "title", width: 28 }, { header: "标签热度", key: "tagType", width: 12 }, ], rows: rows.flatMap((group) => group.tags.map((tag) => ({ index: group.index, type: group.type, title: tag.title, tagType: tag.type === "hot" ? "热门" : "普通", })) ), }); } export function downloadMarkdownFile( markdown: string, baseFileName = "商品策划工具_分析结果" ) { const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8", }); triggerBlobDownload(blob, `${baseFileName}_${new Date().toISOString().slice(0, 10)}.md`); } export async function downloadCompetitorAnalysisWorkbook( records: Record, baseFileName = "商品策划工具_竞品分析结果" ) { const rows = Object.entries(records) .map(([key, value]) => ({ key, kind: value.kind === "sku" ? "SKU卖点分析" : "图片分析", title: value.title, updatedAt: value.updatedAt, markdown: value.markdown, })) .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)); await downloadWorkbook({ worksheetName: "AI分析结果", fileName: baseFileName, columns: [ { header: "结果键", key: "key", width: 26 }, { header: "分析类型", key: "kind", width: 16 }, { header: "标题", key: "title", width: 42 }, { header: "更新时间", key: "updatedAt", width: 24 }, { header: "Markdown结果", key: "markdown", width: 120 }, ], rows, }); }