// ============================================================================== // <品类名> · Ch · <章主题>(模板) // ============================================================================== // 使用方法: // 1. 复制此文件为 <品类>-ch-.js // 2. 替换所有 <...> 占位符 // 3. 按实际子章数填充 renderSubN 函数 // 4. 在 module.exports 里映射 '-': renderSubN // 5. 在 render.js 的 SLIDE_RENDERERS 里导入此文件 // // 每个子章必含 5 件套: // ① SectionHead(eyebrow + title + subtitle) // ② ≥ 3 张 VOC 证据卡(来自 getEvidence) // ③ 至少 1 个结构化组件(表格 / 矩阵 / 统计条) // ④ DecisionList 落地决策 // ⑤ data-slide-num 属性 // ============================================================================== const LA = require('./<品类>-analyze.js'); const C = require('./<品类>-components.js'); const { BRAND, esc, fmtLikes } = C; // ========================================================== // Sub 1 · <子章 1 主题> // ========================================================== function renderSub1(ctx) { const { chapter, subIdx, sub, slideNum, slideTotal, data } = ctx; const items = data.items || []; // ① 查询证据 const coreVoc = LA.getEvidence(items, { keyword: '<本品/竞品名>', contentMatch: /<相关词 1>|<相关词 2>|<相关词 3>/, minChars: 25, top: 4, seed: 7, // 种子用奇数,避免和其他章冲突 }); const painVoc = LA.getEvidence(items, { contentMatch: /<痛点词 1>|<痛点词 2>/, sentiment: 'negative', minChars: 25, top: 3, seed: 11, }); // ② 渲染 HTML return `
${C.renderSectionHead({ eyebrow: `${chapter.num}.${subIdx} · <副标题>`, title: '<关键词>:<主标题>', subtitle: '<副标题描述 · 30-80 字解释 subchapter 要讲什么>', color: BRAND.MAIN, })}
${coreVoc.map((it) => C.renderVocCard(it, { accent: BRAND.MAIN, maxChars: 200 })).join('')}
${C.renderStatStrip([ { num: '<数字 1>', label: '<说明>', color: BRAND.MAIN }, { num: '<数字 2>', label: '<说明>', color: BRAND.JIANG_GREEN }, { num: '<数字 3>', label: '<说明>', color: BRAND.CORAL }, { num: '<数字 4>', label: '<说明>', color: BRAND.PURPLE }, ], { accent: BRAND.MAIN })} ${C.renderInsightHero({ eyebrow: '💡 KEY INSIGHT · 关键洞察', title: '<一句话金句观点(25-50 字,带 strong 强调)>', subtitle: '<进一步解释或证据补充>', color: BRAND.MAIN, })}
${painVoc.map((it) => C.renderVocCard(it, { accent: BRAND.CORAL, compact: true, maxChars: 140 })).join('')}
${C.renderDecisionList([ `P0 · 决策 1:<具体动作>`, `P1 · 决策 2:<具体动作>`, `P2 · 决策 3:<具体动作>`, `P3 · 决策 4:<具体动作>`, ], { title: '落地决策', accent: BRAND.MAIN, columns: 2 })}
`; } // ========================================================== // Sub 2 · <子章 2 主题> // ========================================================== function renderSub2(ctx) { const { chapter, subIdx, sub, slideNum, slideTotal, data } = ctx; const items = data.items || []; // 以竞品对比为例 const voc = LA.getEvidence(items, { keyword: '<竞品名>', top: 4, seed: 13, }); return `
${C.renderSectionHead({ eyebrow: `${chapter.num}.${subIdx} · <子章副标题>`, title: '<主标题>', color: BRAND.CORAL, })} ${C.renderCompareTable({ title: 'COMPETITOR COMPARISON', headers: ['维度', '本品', '<竞品 A>', '<竞品 B>'], rows: [ [ '核心成分', { html: '本品', color: BRAND.MAIN, bold: true }, { html: '<竞品 A>', color: 'var(--text-2)' }, { html: '<竞品 B>', color: 'var(--text-2)' }, ], ['价格', '¥<...>', '¥<...>', '¥<...>'], ['批号', 'OTC', '食品', '保健品'], ], accent: BRAND.CORAL, })}
${voc.map((it) => C.renderVocCard(it, { accent: BRAND.CORAL })).join('')}
${C.renderDecisionList([ `决策 1:<...>`, `决策 2:<...>`, ], { accent: BRAND.CORAL })}
`; } // ========================================================== // Sub 3 · <子章 3 主题>(2×2 矩阵示例) // ========================================================== function renderSub3(ctx) { const { chapter, subIdx, sub, slideNum, slideTotal, data } = ctx; return `
${C.renderSectionHead({ eyebrow: `${chapter.num}.${subIdx} · 无人地带坐标`, title: '<主标题>', color: BRAND.JIANG_GREEN, })} ${C.renderMatrix2x2({ xLabel: '', yLabel: '', xLow: '', xHigh: '', yLow: '', yHigh: '', accent: BRAND.JIANG_GREEN, quadrants: { q1: { title: '右上 · <象限 1>', color: BRAND.TECH_BLUE, items: ['<竞品 A>', '<竞品 B>'], note: '痛点:<...>', }, q2: { title: '左上 · <象限 2>', color: BRAND.WINE_RED, items: ['<竞品 C>'], note: '痛点:<...>', }, q3: { title: '左下 · <象限 3>', color: BRAND.WARM_ORANGE, items: ['<竞品 D>'], note: '<...>', }, q4: { title: '右下 · <象限 4>(无人地带)', color: BRAND.JIANG_GREEN, items: ['✨ 本品独占'], note: '✅ 机会:<...>', }, }, })} ${C.renderDecisionList([ `锁定象限:<...>`, `瓦解对手:<...>`, ], { accent: BRAND.JIANG_GREEN })}
`; } // ========================================================== // 导出 // TODO: 按实际 subs 数量增减 // ========================================================== module.exports = { '-1': renderSub1, '-2': renderSub2, '-3': renderSub3, // '-4': renderSub4, // 如有更多子章 // '-5': renderSub5, };