| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- // ==============================================================================
- // 江中肝纯片 · VOC 深度洞察报告 v2 · 主渲染器
- // ==============================================================================
- // 会议要求(增量优化):
- // A. 新增自身产品分析(肝纯片抖音已卖数年→用户画像)
- // B. VOC 分类归拢(7715条→几大类→共性需求)
- // C. 竞品正反面全面分析(当前只有缺点→加优点)
- // + 特劳特定位 + 参照"右旋"框架
- //
- // 新结构(6 章):
- // Ch0 护肝人群全景 + VOC 归拢 + TAM/SAM/SOM(req B)
- // Ch1 肝纯片自身画像(req A · 全新)
- // Ch2 竞品正反面全面分析(req C)
- // Ch3 品类定位 · 里斯×特劳特
- // Ch4 场景×机会(整合旧 Ch5+Ch7)
- // Ch5 落地行动
- // ==============================================================================
- const STYLES = require('./voc-styles.js');
- const SCRIPTS = require('./voc-scripts.js');
- const LA = require('./liver-analyze.js');
- const C = require('./liver-components.js');
- const { BRAND, esc } = C;
- // Chapter submodules
- const ch0 = require('./liver-v2-ch0-landscape.js');
- const ch1 = require('./liver-v2-ch1-self.js');
- const ch2 = require('./liver-v2-ch2-competitor.js');
- const ch3 = require('./liver-v2-ch3-position.js');
- const ch4 = require('./liver-v2-ch4-scene.js');
- const ch5 = require('./liver-v2-ch5-action.js');
- const SUB_MODULES = { landscape: ch0, self: ch1, competitor: ch2, position: ch3, scene: ch4, action: ch5 };
- // ============================================================
- // 6 章元信息
- // ============================================================
- const CHAPTERS = [
- { id: 0, num: '0', key: 'landscape', title: '护肝人群全景 · VOC 分类归拢', en: 'LIVER LANDSCAPE', tone: 'blue', color: BRAND.TECH_BLUE, icon: '🔍',
- summary: '7715 条 VOC 结构化分类:问题类型×人群×需求 + TAM→SAM→SOM 漏斗' },
- { id: 1, num: '1', key: 'self', title: '肝纯片自身画像', en: 'SELF PORTRAIT', tone: 'amber', color: BRAND.LIVER_AMBER, icon: '🪞',
- summary: '肝纯片抖音已卖数年 · 用户画像 · 满意/不满意 · 价值感知 · DMY 认知' },
- { id: 2, num: '2', key: 'competitor', title: '竞品正反面 · 全面分析', en: 'COMPETITOR SWOT', tone: 'rose', color: BRAND.ROSE, icon: '⚔',
- summary: '6 大竞品正反面:Swisse / 易善复 / 葵花 / 片仔癀 / 海王金樽 / 熊胆粉' },
- { id: 3, num: '3', key: 'position', title: '品类定位 · 里斯×特劳特', en: 'CATEGORY POSITIONING', tone: 'purple', color: BRAND.PURPLE, icon: '🎯',
- summary: '里斯品类进化树 + 特劳特心智阶梯 · 藤茶 DMY 差异化锚点 · 一句话定位' },
- { id: 4, num: '4', key: 'scene', title: '场景×机会 · 四大独占场景', en: 'SCENE & OPPORTUNITY', tone: 'orange', color: BRAND.WARM_ORANGE, icon: '🗺',
- summary: '应酬解酒 / 脂肪肝调理 / 熬夜前后 / 送长辈 · 每个场景带 VOC 证据链' },
- { id: 5, num: '5', key: 'action', title: '落地行动', en: 'ACTION PLAN', tone: 'green', color: BRAND.JIANG_GREEN, icon: '🚀',
- summary: '4P 配称 + 10 亿路径 + P0/P1 行动清单 + 包装优化方向' },
- ];
- // ============================================================
- // 子章节
- // ============================================================
- const CHAPTER_SUBSECTIONS = {
- landscape: [
- '护肝问题分类归拢 · 六大类 + 共性需求',
- '人群声量 × 平台分布 × 情感地图',
- 'TAM → SAM → SOM · 10 亿目标漏斗',
- ],
- self: [
- '肝纯片自身 VOC · 用户画像',
- '满意 vs 不满意 · 双面分析',
- '藤茶 DMY 认知度 · 用户感知',
- ],
- competitor: [
- '6 大竞品正反面全景(优点+缺点)',
- '竞品差评痛点 → 肝纯片机会窗口',
- '三轴定位图谱 · 肝纯片无人地带',
- ],
- position: [
- '里斯品类战略 · 护肝品类进化树',
- '特劳特定位 · 一句话方案',
- '差异化 MOAT · 藤茶 DMY 锚点',
- ],
- scene: [
- '场景#1 · 应酬解酒 × 液体应急',
- '场景#2 · 脂肪肝调理 × 日常养护',
- '场景#3 · 熬夜前后 × 便携快取',
- '场景#4 · 送长辈 × 孝心礼盒',
- ],
- action: [
- '4P 配称 · 产品+渠道+推广+价格',
- '10 亿路径 · 3 阶段 Roadmap',
- 'P0/P1 行动清单 + 包装优化',
- ],
- };
- const CHAPTER_HERO_LINES = {
- landscape: `7715 条真实 VOC(小红书 + 抖音 + Amazon)结构化分类为 <strong style="color:${BRAND.TECH_BLUE};">6 大护肝问题类型</strong>,从"单点式反馈"升级为"<strong>分类归拢 + 共性需求</strong>"视角。江旭原话:"看能不能让 AI 把这么多条整个梳理分类归拢一下,大概分为哪几大类,然后有哪些共性的需求。"`,
- self: `江旭指出"<strong style="color:${BRAND.CORAL};">漏掉了我们自己产品的分析</strong>"——肝纯片已在抖音卖了数年,必须回答:<strong>谁在买?为什么买?满意什么?不满意什么?</strong>本章从自身 VOC 中提炼用户画像,找到产品的真实价值感知和改进方向。`,
- competitor: `不再只看缺点。6 大竞品(Swisse / 易善复 / 葵花 / 片仔癀 / 海王金樽 / 熊胆粉)全面正反面分析——<strong style="color:${BRAND.JIANG_GREEN};">优点是我们要学习的</strong>,<strong style="color:${BRAND.CORAL};">缺点是我们的机会窗口</strong>。`,
- position: `用客户的 <strong style="color:${BRAND.PURPLE};">组织语言</strong>(里斯品类战略 + 特劳特定位)重新组织内容。王总反复强调:"不用这套语言,内部看不懂。"本章用品类进化树找到位置,用心智阶梯找到定位,用 <strong style="color:${BRAND.TENGCHA_GREEN};">藤茶 DMY</strong> 锚定差异化。`,
- scene: `<strong style="color:${BRAND.WARM_ORANGE};">应酬解酒 / 脂肪肝调理 / 熬夜前后 / 送长辈</strong>——四大场景各有 VOC 证据链。场景决定话术、场景决定渠道、场景决定包装形态。每个场景给出人群画像 + 核心话术 + 产品形态建议。`,
- action: `从 VOC 洞察反推 <strong style="color:${BRAND.JIANG_GREEN};">4P 配称</strong>,收敛为 <strong>10 亿路径 × 3 阶段</strong>:Y1 药线+电商 5 亿验证 → Y2 礼品+餐饮 3 亿 → Y3 国际+升级 2 亿。附包装优化方向(上版"放蓬塔"偏了,需重新定义)。`,
- };
- // ============================================================
- // 工具函数
- // ============================================================
- function fmtNum(n) {
- if (n >= 10000) return (n / 10000).toFixed(1) + '万';
- if (n >= 1000) return (n / 1000).toFixed(1) + 'k';
- return String(n);
- }
- function sn(slideNum, slideTotal) { return `<span style="position:absolute;bottom:14px;right:20px;font-family:var(--font-mono);font-size:0.65rem;color:var(--text-3);">${slideNum} / ${slideTotal}</span>`; }
- // ============================================================
- // 导航
- // ============================================================
- function renderNav() {
- return `<nav id="report-nav" style="position:fixed;top:0;left:0;right:0;z-index:100;background:rgba(255,255,255,0.92);backdrop-filter:blur(6px);border-bottom:1px solid var(--border);padding:6px 20px;display:flex;align-items:center;gap:12px;font-size:0.72rem;font-family:var(--font-mono);overflow-x:auto;white-space:nowrap;">
- <a href="#cover" style="font-weight:800;color:${BRAND.JIANG_GREEN};text-decoration:none;letter-spacing:0.15em;">肝纯片 v2</a>
- <span style="color:var(--border);">|</span>
- ${CHAPTERS.map(c => `<a href="#ch-${c.key}" style="color:var(--text-2);text-decoration:none;padding:2px 6px;border-radius:3px;transition:background .2s;" onmouseover="this.style.background='${c.color}15'" onmouseout="this.style.background='transparent'">${c.icon} ${c.title.split('·')[0].trim()}</a>`).join('')}
- </nav>`;
- }
- // ============================================================
- // Cover
- // ============================================================
- function renderCover(meta) {
- return `<section class="report-section cover-section" id="cover" data-tone="liver" style="min-height:100vh;display:flex;flex-direction:column;justify-content:center;padding:60px 40px;">
- <div style="max-width:920px;margin:0 auto;text-align:center;">
- <div class="text-mono text-xs" style="color:${BRAND.LIVER_AMBER};letter-spacing:0.3em;margin-bottom:18px;font-weight:700;">JIANGZHONG · VOC DEEP INSIGHT · V2</div>
- <h1 style="font-family:var(--font-head);font-size:clamp(2rem,5vw,3.2rem);font-weight:900;line-height:1.2;color:var(--text-1);margin-bottom:16px;">
- 江中肝纯片<br/><span style="color:${BRAND.LIVER_AMBER};">VOC 深度洞察报告</span> <span style="color:${BRAND.TENGCHA_GREEN};">v2</span>
- </h1>
- <div style="color:var(--text-2);font-size:1rem;line-height:1.8;max-width:700px;margin:0 auto 30px;">
- 基于 <strong>${fmtNum(meta.comments)}</strong> 条真实 VOC(${Object.entries(meta.platforms).map(([p, n]) => `${({xhs:'小红书',douyin:'抖音',amazon:'Amazon'})[p]||p} ${fmtNum(n)}`).join(' + ')})<br/>
- <strong>v2 新增</strong>:自身产品画像 · VOC 分类归拢 · 竞品正反面 · 里斯×特劳特定位
- </div>
- <div style="display:flex;justify-content:center;gap:24px;flex-wrap:wrap;">
- ${CHAPTERS.map(c => `<span style="color:${c.color};font-size:0.78rem;">${c.icon} ${c.title.split('·')[0].trim()}</span>`).join('')}
- </div>
- <div style="margin-top:40px;color:var(--text-3);font-size:0.72rem;">
- 采集阶段 ${meta.stage} · ${meta.collectedAt} · ${meta.keywords} 关键词 · ${Object.keys(meta.platforms).length} 平台
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // Agenda
- // ============================================================
- function renderAgenda() {
- return `<section class="report-section" id="agenda" data-tone="liver">
- <div class="section-inner">
- <div class="text-mono text-xs" style="color:${BRAND.LIVER_AMBER};letter-spacing:0.25em;margin-bottom:12px;font-weight:700;">REPORT AGENDA · V2</div>
- <h2 style="font-family:var(--font-head);font-size:1.8rem;font-weight:800;color:var(--text-1);margin-bottom:24px;">报告目录</h2>
- <div style="display:grid;gap:16px;">
- ${CHAPTERS.map(c => {
- const subs = CHAPTER_SUBSECTIONS[c.key] || [];
- return `<div style="padding:18px 22px;background:${c.color}08;border-left:4px solid ${c.color};border-radius:0 var(--radius-sm) var(--radius-sm) 0;">
- <a href="#ch-${c.key}" style="text-decoration:none;display:flex;align-items:center;gap:12px;">
- <span style="font-size:1.3rem;">${c.icon}</span>
- <div>
- <div style="font-family:var(--font-head);font-weight:700;color:${c.color};font-size:1rem;">Ch${c.num} · ${c.title}</div>
- <div style="color:var(--text-2);font-size:0.78rem;margin-top:2px;">${subs.map((s,i) => `${c.num}.${i+1} ${s}`).join(' · ')}</div>
- </div>
- </a>
- </div>`;
- }).join('')}
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // Chapter Divider
- // ============================================================
- function renderChapterDivider(c) {
- const heroLine = CHAPTER_HERO_LINES[c.key] || c.summary;
- const subs = CHAPTER_SUBSECTIONS[c.key] || [];
- return `<section class="report-section chapter-divider" id="ch-${c.key}" data-tone="${c.tone}" style="min-height:80vh;display:flex;flex-direction:column;justify-content:center;padding:60px 40px;">
- <div style="max-width:860px;margin:0 auto;">
- <div class="text-mono text-xs" style="color:${c.color};letter-spacing:0.3em;margin-bottom:14px;font-weight:700;">CHAPTER ${c.num} · ${c.en}</div>
- <h2 style="font-family:var(--font-head);font-size:clamp(1.8rem,4vw,2.8rem);font-weight:900;color:var(--text-1);line-height:1.2;margin-bottom:20px;">${c.icon} ${c.title}</h2>
- <div style="color:var(--text-1);font-size:0.94rem;line-height:1.82;max-width:780px;margin-bottom:28px;">${heroLine}</div>
- <div style="display:flex;gap:14px;flex-wrap:wrap;">
- ${subs.map((s, i) => `<a href="#${c.key}-${i+1}" style="padding:6px 14px;background:${c.color}10;border:1px solid ${c.color}33;border-radius:16px;color:${c.color};font-size:0.78rem;text-decoration:none;font-weight:600;">${c.num}.${i+1} ${s.split('·')[0].trim()}</a>`).join('')}
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // Placeholder fallback
- // ============================================================
- function renderPlaceholder(c, subIdx, sub, slideNum, slideTotal) {
- return `<section class="report-section" id="${c.key}-${subIdx}" data-tone="${c.tone}" data-slide-num="${slideNum}/${slideTotal}">
- <div class="section-inner" style="text-align:center;padding:80px 40px;">
- <div style="font-size:2.5rem;margin-bottom:16px;">${c.icon}</div>
- <div class="text-mono text-xs" style="color:${c.color};letter-spacing:0.2em;font-weight:700;">${c.num}.${subIdx} · 待填充</div>
- <h3 style="font-family:var(--font-head);font-size:1.3rem;color:var(--text-1);margin-top:10px;">${esc(sub)}</h3>
- </div>
- </section>`;
- }
- // ============================================================
- // buildHTML
- // ============================================================
- function buildHTML({ product, collectedAt } = {}) {
- const data = LA.loadMerged();
- const meta = LA.getMeta(data);
- const slides = [];
- slides.push(renderCover(meta));
- slides.push(renderAgenda());
- let slideCount = 2;
- const totalSubs = Object.values(CHAPTER_SUBSECTIONS).reduce((a, s) => a + s.length, 0);
- const slideTotal = 2 + CHAPTERS.length + totalSubs;
- for (const c of CHAPTERS) {
- slideCount++;
- slides.push(renderChapterDivider(c));
- const subs = CHAPTER_SUBSECTIONS[c.key] || [];
- const mod = SUB_MODULES[c.key];
- for (let i = 0; i < subs.length; i++) {
- slideCount++;
- const subIdx = i + 1;
- const fnName = `renderSub${subIdx}`;
- if (mod && typeof mod[fnName] === 'function') {
- try {
- slides.push(mod[fnName]({
- chapter: c, subIdx, sub: subs[i],
- slideNum: slideCount, slideTotal,
- data, meta,
- }));
- } catch (err) {
- console.warn(`⚠ ${c.key}.${fnName} error:`, err.message);
- slides.push(renderPlaceholder(c, subIdx, subs[i], slideCount, slideTotal));
- }
- } else {
- slides.push(renderPlaceholder(c, subIdx, subs[i], slideCount, slideTotal));
- }
- }
- }
- return `<!DOCTYPE html>
- <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
- <title>${product || '江中肝纯片'} · VOC 深度洞察报告 v2</title>
- ${STYLES}</head><body>
- ${renderNav()}
- ${slides.join('\n')}
- <script>${SCRIPTS}</script>
- </body></html>`;
- }
- module.exports = { buildHTML, CHAPTERS, CHAPTER_SUBSECTIONS, CHAPTER_HERO_LINES };
|