| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- // ==============================================================================
- // 江中乳酸菌素片儿童版 · VOC 深度洞察报告 · 主渲染器
- // ==============================================================================
- // 01 · Cover
- // 02 · Agenda
- // 03-05 · Ch1 诘问起点(3 子章)
- // 06-09 · Ch2 药品益生菌 VOC 反面教材(4 子章)
- // 10-13 · Ch3 食品益生菌 VOC 矛盾盘(4 子章)
- // 14-18 · Ch4 KANO × JTBD 双视角(5 子章)
- // 19-22 · Ch5 场景四元素地图(4 子章)
- // 23-25 · Ch6 三轴图谱 × 无人地带(3 子章)
- // 26-28 · Ch7 新机会 × 新人群(3 子章)
- // 29-30 · Ch8 4P 配称蓝图(2 子章)
- // 总计 38 slides
- // ==============================================================================
- const STYLES = require('./voc-styles.js');
- const SCRIPTS = require('./voc-scripts.js');
- const LA = require('./lactic-analyze.js');
- const C = require('./lactic-components.js');
- const { BRAND, esc, fmtLikes } = C;
- // ============================================================
- // 8 章元信息
- // ============================================================
- const CHAPTERS = [
- { id: 1, num: '1', key: 'challenge', title: '诘问起点', en: 'THE CHALLENGE', tone: 'rose', color: BRAND.CORAL, icon: '🎯',
- summary: '6000万→10亿 · 差异化定位的起点 · 为什么只加"娃娃头"不够' },
- { id: 2, num: '2', key: 'drug_voc', title: '药品益生菌 VOC 反面教材', en: 'RX PROBIOTIC VOC', tone: 'blue', color: BRAND.TECH_BLUE, icon: '💊',
- summary: '妈咪爱/亿活/金双岐痛点全扫描 · 冷链/处方/依赖焦虑' },
- { id: 3, num: '3', key: 'food_voc', title: '食品益生菌 VOC 矛盾盘', en: 'FOOD PROBIOTIC VOC',tone: 'amber', color: BRAND.SUNNY_YELLOW, icon: '🍬',
- summary: '合生元/万益蓝/拜奥/inne 家长"怕没效果"的信任缺口' },
- { id: 4, num: '4', key: 'kano', title: 'KANO × JTBD 双视角', en: 'USER INSIGHT', tone: 'purple', color: BRAND.PURPLE, icon: '🧠',
- summary: '家长 × 儿童双决策链 · F/E/S 三维价值' },
- { id: 5, num: '5', key: 'scene', title: '场景四元素地图', en: 'SCENE MAP', tone: 'orange', color: BRAND.WARM_ORANGE, icon: '🗺',
- summary: '入园/抗生素后/挑食/换季 · 四大高频触发场景' },
- { id: 6, num: '6', key: 'competitor', title: '三轴图谱 × 无人地带', en: 'COMPETITION AXES', tone: 'rose', color: BRAND.ROSE, icon: '⚔',
- summary: '药品 / 食品 / 营养软糖 三轴 · 乳酸菌素片独占坐标' },
- { id: 7, num: '7', key: 'opportunity',title: '新机会 × 新人群', en: 'OPPORTUNITY', tone: 'green', color: BRAND.JIANG_GREEN, icon: '💡',
- summary: '分龄产品线 / 内源吸收赛道 / 包装差异化三大破局' },
- { id: 8, num: '8', key: 'blueprint', title: '4P 配称蓝图', en: '4P BLUEPRINT', tone: 'green', color: BRAND.LACTIC_MINT, icon: '🚀',
- summary: '产品/渠道/推广/价格 · 6000万→10亿 三年路径' },
- ];
- // ============================================================
- // 各章节 subsections 清单
- // ============================================================
- const CHAPTER_SUBSECTIONS = {
- challenge: [
- '现状困境·6000万规模 × 0 差异化',
- '10亿目标·药品/食品/软糖三轴破局',
- 'VOC 反向验证·家长 × 儿童双视角起点',
- ],
- drug_voc: [
- '妈咪爱·冷链活菌 × 处方门槛痛点',
- '亿活/金双岐·依赖焦虑 × 停药反弹',
- '喂药难·口感苦 × 不独立包装',
- '药品益生菌 GAP·乳酸菌素片切入点',
- ],
- food_voc: [
- '合生元·食品级 × 家长怀疑效果',
- '万益蓝/拜奥·菌株混乱 × 价格贵',
- 'inne 噗噗宝·便秘单点但单薄',
- '食品益生菌 GAP·OTC 信任空白',
- ],
- kano: [
- 'KANO 五类·必备/期望/兴奋/无差异/反向',
- 'JTBD·家长 Functional 功能价值',
- 'JTBD·家长 Emotional 情绪价值',
- 'JTBD·儿童 × 家长 Social 社会价值',
- '决策优先级·SKU / 话术 / 包装映射',
- ],
- scene: [
- '场景#1·入园生病·集体生活综合征',
- '场景#2·抗生素后·肠道修复刚需',
- '场景#3·挑食积食·日常消化养护',
- '场景#4·换季腹泻·季节性防护',
- ],
- competitor: [
- '三轴图谱·药品 / 食品 / 营养软糖',
- '无人地带坐标·乳酸菌素片独占位',
- '8 竞品精对标·VOC 差异化 MOAT',
- ],
- opportunity: [
- '新机会·分龄产品线(0-3 / 3-6 / 6-12)',
- '新赛道·告别瓶瓶罐罐内源吸收',
- '新包装·卡通 IP × 咀嚼片革命',
- ],
- blueprint: [
- '4P 配称·产品 + 渠道 + 推广 + 价格',
- '10 亿路径·3 年 × 4 渠道分阶段',
- ],
- };
- // ============================================================
- // 每章 hero line
- // ============================================================
- const CHAPTER_HERO_LINES = {
- challenge: `江中乳酸菌素片儿童版当前规模 <strong style="color:${BRAND.CORAL};">线下 6000 万 + 线上 400-500 万</strong>,与成人版唯一区别是<strong style="color:${BRAND.CORAL};">"包装上加了个娃娃头"</strong>。妈咪爱线下 3.6 亿 + 线上 3848 万,合生元益生菌全家桶 5 亿+。我们不能再把儿童当"成人减量版"卖。本章直面困境:<strong style="color:${BRAND.LACTIC_MINT};">没有儿童专属定位 / 没有专属场景 / 没有家长非买不可的理由</strong>,VOC 反向验证是唯一出路。`,
- drug_voc: `药品益生菌(<strong style="color:${BRAND.TECH_BLUE};">妈咪爱 / 亿活 / 金双岐</strong>)是家长"孩子生病时想起的那个药",但也背负着三大痛点:<strong style="color:${BRAND.CORAL};">冷链储存麻烦</strong>、<strong style="color:${BRAND.CORAL};">必须医生处方才敢用</strong>、<strong style="color:${BRAND.CORAL};">停药就反弹的依赖焦虑</strong>。本章逐一解剖妈咪爱、亿活、金双岐的 XHS / 抖音真实家长吐槽,找出乳酸菌素片<strong style="color:${BRAND.LACTIC_MINT};">"非活菌常温稳定 × OTC 无需处方 × 可日常长期"</strong>的差异化切入点。`,
- food_voc: `食品益生菌(<strong style="color:${BRAND.SUNNY_YELLOW};">合生元 / 万益蓝 / 拜奥 / inne / 小胖瓶 / 康萃乐</strong>)靠果味 + 卡通包装 + 颜值营销在小红书起量,但也背负着家长最大的信任焦虑:<strong style="color:${BRAND.CORAL};">"没有 OTC 药品背书 / 菌株效果不稳定 / 价格贵但不确定值不值"</strong>。本章解剖食品益生菌的 VOC 矛盾盘——家长给孩子吃得多,但心里不踏实。乳酸菌素片的 <strong style="color:${BRAND.LACTIC_MINT};">OTC 蓝帽子背书</strong> 是这个赛道里的天然信任壁垒。`,
- kano: `儿童产品不是单人决策,是 <strong style="color:${BRAND.PURPLE};">家长 × 儿童双引擎</strong>:家长决定买什么、孩子决定吃不吃。<strong style="color:${BRAND.PURPLE};">KANO 五类需求</strong>(必备=安全OTC / 期望=见效 / 兴奋=分龄礼盒 / 反向=药盒感)映射到 SKU/包装/话术。<strong style="color:${BRAND.LACTIC_MINT};">JTBD 三维价值</strong>:Functional(解决便秘/积食/抗生素后)、Emotional(家长不焦虑带娃)、Social(妈妈圈专业感 + 孩子被羡慕)。`,
- scene: `<strong style="color:${BRAND.WARM_ORANGE};">时间 × 空间 × 触发事件 × 人群</strong> 四元素交叉,乳酸菌素片独占 <strong>入园生病 / 抗生素后 / 挑食积食 / 换季腹泻</strong> 四大高频场景——每个场景都在 XHS + 抖音有高赞家长 VOC 可做证据。其中<strong style="color:${BRAND.BERRY_PINK};">入园季(9月)+ 开学季(3月)</strong>是全年两个消费高峰,带独特人群(新手妈妈 + 3-6 岁宝宝)和独家话术模板。`,
- competitor: `<strong style="color:${BRAND.ROSE};">药品益生菌 ↔ 食品益生菌 ↔ 营养软糖</strong> 三轴定位图谱上,乳酸菌素片的<strong style="color:${BRAND.LACTIC_MINT};">无人地带坐标</strong> = "<strong>药品级 OTC 背书</strong> × <strong>食品级日常安全</strong> × <strong>营养吸收源头改善</strong>"。直接对标 8 大竞品(妈咪爱 / 亿活 / 金双岐 / 合生元 / 万益蓝 / 拜奥 / inne / 康萃乐)的 VOC 真痛点,找出乳酸菌素片的<strong style="color:${BRAND.JIANG_GREEN};">差异化 MOAT</strong>。`,
- opportunity: `基于 VOC 深挖,提炼 <strong style="color:${BRAND.JIANG_GREEN};">3 条长尾赛道</strong>:<br/>① <strong>分龄产品线</strong>(0-3 颗粒 / 3-6 水果咀嚼片 / 6-12 加量片)三 SKU 矩阵<br/>② <strong>"告别瓶瓶罐罐"内源吸收</strong>赛道切入 100 亿儿童营养软糖市场<br/>③ <strong>卡通 IP × 咀嚼片革命</strong>解决喂药依从性 + 建立货架辨识度。每条赛道配真实 VOC 证据 + 场景话术 + 规模预估。`,
- blueprint: `以 VOC 洞察反推 <strong style="color:${BRAND.LACTIC_MINT};">4P 配称</strong>:<strong>产品</strong>(颗粒 / 咀嚼片 / 独立包装 / 分龄礼盒 8 SKU)+ <strong>渠道</strong>(药店线下 + 京东 / 天猫线上 + 母婴连锁 + 微信社群)+ <strong>推广</strong>(XHS 新手妈妈种草 + 抖音儿科医生科普 + 丁香妈妈合作)+ <strong>价格</strong>(¥30-298 三带位)。3 阶段落地:<strong>Y1 差异化升级 3 亿 → Y2 赛道突破 6 亿 → Y3 生态化 10 亿</strong>。`,
- };
- // ============================================================
- // utils
- // ============================================================
- function sn(n) { return String(n).padStart(2, '0'); }
- // ============================================================
- // 共用组件(导航 / 键盘提示)
- // ============================================================
- function renderNav() {
- const dots = [
- { tip: '封面', href: '#s0' },
- { tip: '目录', href: '#agenda' },
- ...CHAPTERS.map((c) => ({ tip: `${c.num} ${c.title}`, href: `#${c.key}` })),
- ];
- return `<nav class="nav-rail" aria-label="章节导航">
- ${dots.map((d, i) => `<a class="nav-dot${i === 0 ? ' active' : ''}" href="${d.href}" data-tip="${esc(d.tip)}" data-idx="${i}"></a>`).join('')}
- </nav>
- <div class="top-bar">
- <div class="brand-logo">江中<span class="dot">·</span>产品开发部 / 乳酸菌素片儿童版 VOC 深度洞察 v1.0</div>
- <div class="text-mono text-xs" style="color:var(--text-3);">6000万→10亿 / 3 赛道 / 8 假设</div>
- </div>`;
- }
- function renderKbdHint() {
- return `<div class="kbd-hint" id="kbdHint">
- <span>键盘切换</span>
- <kbd>↑</kbd><kbd>↓</kbd>
- <span>或</span>
- <kbd>PgUp</kbd><kbd>PgDn</kbd>
- </div>`;
- }
- // ============================================================
- // Slide 01 · Cover
- // ============================================================
- function renderCover({ product, collectedAt, slideNum, slideTotal, meta }) {
- const totalComments = meta?.comments || 0;
- const platformCount = Object.values(meta?.platforms || {}).filter((n) => n > 0).length;
- const productsCount = meta?.productsCount || 0;
- const stage = meta?.stage || 'skeleton';
- const tier = meta?.sourceTier || 'unknown';
- const isScaffold = stage === 'skeleton';
- const isReal = tier === 'real-collected';
- const sourceBadge = isReal
- ? { label: '真实采集 · XHS + 抖音评论颗粒度', color: BRAND.JIANG_GREEN, icon: '✓' }
- : { label: '骨架版 · 待 VOC 数据加载', color: BRAND.CORAL, icon: '○' };
- const commentsDisplay = isScaffold ? '待采集' : totalComments.toLocaleString();
- return `<section class="report-section" id="s0" data-tone="amber" data-slide-num="${slideNum}/${slideTotal}" style="min-height:100vh;padding:0;">
- <div class="cover-hero">
- <div class="aurora" aria-hidden="true"><span></span><span></span><span></span></div>
- <div class="cover-grid-bg"></div>
- <div class="cover-content">
- <div class="cover-meta rise-in" style="display:flex; justify-content:space-between; align-items:center; gap:16px; flex-wrap:wrap;">
- <span>江中 / 产品开发部 / 2026 · ${esc(product)} · VOC 深度洞察</span>
- <span style="display:inline-flex; align-items:center; gap:6px; padding:4px 12px; background:${sourceBadge.color}15; color:${sourceBadge.color}; border:1px solid ${sourceBadge.color}55; border-radius:16px; font-family:var(--font-mono); font-size:0.72rem; letter-spacing:0.12em; font-weight:600;">
- <span style="font-size:0.9rem;">${sourceBadge.icon}</span>${esc(sourceBadge.label)}
- </span>
- </div>
- <div class="cover-title-stack">
- <p class="text-mono rise-in" style="color:${BRAND.LACTIC_MINT}; font-size:0.9rem;letter-spacing:0.2em;margin-bottom:18px;">KANO × JTBD × SCENE × COMPETITOR · 四维儿童 VOC 验证</p>
- <h1 class="cover-title rise-in">${esc(product)}<br/><span style="color:${BRAND.LACTIC_MINT}; -webkit-text-fill-color:${BRAND.LACTIC_MINT}; background:none; font-size:0.66em;">VOC 深度洞察报告</span></h1>
- <p class="text-poster rise-in" style="margin-top:20px;color:var(--text-2); font-size:1.42rem;">
- 儿童肠道调理专属 OTC · 从 <strong style="color:${BRAND.LACTIC_MINT};">6000 万到 10 亿的真实路径</strong>
- </p>
- </div>
- <p class="cover-sub fade-up">
- 基于 <strong style="color:${BRAND.LACTIC_MINT};">0.基础调研.md + 1.场景的补充.md 会议确认</strong> 的"10 亿 × 3 赛道破局"落地框架,
- 以 <strong style="color:${BRAND.JIANG_GREEN};">OTC 蓝帽子非活菌 + 儿童专属剂型</strong> 为起点,
- 通过 <strong style="color:${BRAND.LACTIC_MINT};">KANO × JTBD × 场景四元素</strong> × <strong style="color:${BRAND.LACTIC_MINT};">${commentsDisplay}</strong> 条真实家长评论<strong style="color:${BRAND.LACTIC_MINT};">颗粒度</strong> VOC 交叉验证,
- 对标 <strong style="color:${BRAND.TECH_BLUE};">6 亿药品益生菌 + 20 亿食品益生菌 + 100 亿儿童营养软糖</strong> 的痛点地图,
- 在 <strong style="color:${BRAND.ROSE};">药品 ↔ 食品 ↔ 营养软糖三轴</strong> 找到乳酸菌素片<strong style="color:${BRAND.JIANG_GREEN};">无人地带</strong>,
- 提炼 <strong style="color:${BRAND.LACTIC_MINT};">3 条长尾赛道</strong>,输出 <strong style="color:${BRAND.SAGE};">4P 配称蓝图</strong>,闭环 <strong style="color:${BRAND.JIANG_GREEN};">10 亿 · 3 年</strong> 路径。
- </p>
- <div class="cover-stats fade-up" style="grid-template-columns:repeat(6, 1fr); max-width:1100px;">
- <div class="cover-stat"><div class="num">10亿</div><div class="lbl">3 年目标</div></div>
- <div class="cover-stat"><div class="num">${commentsDisplay}</div><div class="lbl">真实家长 VOC</div></div>
- <div class="cover-stat"><div class="num">${isScaffold ? '2' : platformCount}</div><div class="lbl">采集平台</div></div>
- <div class="cover-stat"><div class="num">8</div><div class="lbl">核心假设</div></div>
- <div class="cover-stat"><div class="num">${isScaffold ? '30' : (productsCount || 30)}</div><div class="lbl">关键词维度</div></div>
- <div class="cover-stat"><div class="num">${slideTotal}</div><div class="lbl">slides</div></div>
- </div>
- <div class="fade-up" style="margin-top:32px; padding:14px 20px; background:${BRAND.LACTIC_MINT}08; border-left:3px solid ${BRAND.LACTIC_MINT}; border-radius:4px; max-width:920px; margin-left:auto; margin-right:auto; text-align:left;">
- <div class="text-mono text-xs" style="color:${BRAND.LACTIC_MINT}; letter-spacing:0.14em; margin-bottom:6px; font-weight:700;">DATA FOUNDATION · 数据底座</div>
- <p style="color:var(--text-2); font-size:0.82rem; line-height:1.6; margin:0;">
- 本报告基于 <strong style="color:${BRAND.LACTIC_MINT};">docs/乳酸菌/raw/_merged.json</strong> 真实多平台采集:
- XHS <strong>${meta?.platforms?.xhs || '待采集'}</strong> 条评论 + 抖音 <strong>${meta?.platforms?.douyin || '待采集'}</strong> 条评论。
- 每条 VOC 带 <code style="background:${BRAND.JIANG_GREEN}15; padding:1px 5px; border-radius:3px; color:${BRAND.JIANG_GREEN};">source=real-collected</code> 明确标识。
- </p>
- </div>
- <p class="text-mono text-xs fade-up" style="margin-top:40px; color:var(--text-3);">SCROLL DOWN · ${isScaffold ? 'Batch 1 · 骨架版 · 待逐章填充' : `采集截止 ${esc(collectedAt || '')} · ${commentsDisplay} 条真实 VOC`}</p>
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // Slide 02 · Agenda
- // ============================================================
- function renderAgenda({ slideNum, slideTotal }) {
- return `<section class="report-section" id="agenda" data-tone="amber" data-slide-num="${slideNum}/${slideTotal}">
- <div class="section-inner">
- <div class="section-head rise-in">
- <div class="section-eyebrow" style="color:${BRAND.LACTIC_MINT};">CONTENTS · 8 章认知递进</div>
- <h2 class="text-h1"><span class="headline-anim">从诘问到蓝图 · 家长 × 儿童 双视角 VOC 实证</span></h2>
- <p class="section-sub">按<strong style="color:${BRAND.LACTIC_MINT};">认知深度递进</strong>:① 诘问 → ② 药品VOC → ③ 食品VOC → ④ KANO×JTBD → ⑤ 场景地图 → ⑥ 三轴定位 → ⑦ 新机会 → ⑧ 4P 蓝图</p>
- </div>
- <div class="grid" style="grid-template-columns:repeat(2, 1fr); gap:22px; margin-top:20px;">
- ${CHAPTERS.map((c, i) => `
- <a href="#${c.key}" class="fade-up" style="text-decoration:none; display:block; background:var(--bg-1); border:1px solid var(--border); border-left:4px solid ${c.color}; border-radius:var(--radius-md); padding:24px; transition:all .35s cubic-bezier(.2,.7,.2,1); position:relative; overflow:hidden;" onmouseover="this.style.transform='translateY(-4px)'; this.style.borderColor='${c.color}'; this.style.boxShadow='0 20px 60px -20px ${c.color}55'" onmouseout="this.style.transform='translateY(0)'; this.style.borderColor='var(--border)'; this.style.boxShadow='none'">
- <div style="position:absolute; top:-18px; right:-10px; font-family:var(--font-head); font-weight:900; font-size:8rem; line-height:1; color:${c.color}; opacity:.08; letter-spacing:-0.06em; pointer-events:none;">${c.num}</div>
- <div style="display:flex; justify-content:space-between; align-items:start; margin-bottom:14px;">
- <div class="text-mono text-xs" style="color:${c.color}; letter-spacing:0.18em; font-weight:700;">CH ${c.num} · ${c.en}</div>
- <div style="font-size:1.6rem; filter:grayscale(20%);">${c.icon}</div>
- </div>
- <h3 class="text-h2" style="margin:0 0 10px; color:var(--text-1); font-size:1.38rem;">${esc(c.title)}</h3>
- <p style="color:var(--text-2); font-size:0.88rem; line-height:1.6; margin-bottom:12px;">${esc(c.summary)}</p>
- <div style="display:flex; flex-wrap:wrap; gap:5px; margin-bottom:12px;">
- ${(CHAPTER_SUBSECTIONS[c.key] || []).slice(0, 5).map((sub, j) => `<span style="padding:3px 8px; background:${c.color}15; color:${c.color}; border-radius:3px; font-size:0.66rem; font-weight:600;">${c.num}.${j + 1} ${esc(sub.split('·')[0])}</span>`).join('')}
- </div>
- <div style="padding-top:12px; border-top:1px solid var(--border); display:flex; justify-content:space-between; align-items:center;">
- <span class="text-xs text-mono" style="color:var(--text-3); letter-spacing:0.12em;">→ 跳转章节</span>
- <span class="text-mono text-xs" style="color:${c.color};">${i + 1} / ${CHAPTERS.length}</span>
- </div>
- </a>`).join('')}
- </div>
- <div class="fade-up" style="margin-top:44px; padding:22px 26px; background:linear-gradient(135deg, ${BRAND.LACTIC_MINT}10, ${BRAND.JIANG_GREEN}06); border:1px solid ${BRAND.LACTIC_MINT}22; border-radius:var(--radius-md);">
- <div class="text-mono text-xs" style="color:${BRAND.LACTIC_MINT}; letter-spacing:0.15em; margin-bottom:10px;">METHODOLOGY · 方法论自律</div>
- <div style="color:var(--text-1); font-size:0.98rem; line-height:1.72;">
- 本报告严格遵循 《<strong style="color:${BRAND.LACTIC_MINT};">docs/乳酸菌/0.基础调研.md + 1.场景的补充.md</strong>》10 亿 × 3 赛道破局方法论:<br/>
- <strong style="color:${BRAND.CORAL};">❌ 不做</strong>:改药理主成分、宣称"提升免疫力/促进生长发育"(需场景化话术替代)、装饰性图表、脱离 VOC 的拍脑袋;<br/>
- <strong style="color:${BRAND.JIANG_GREEN};">✅ 做</strong>:8 条核心假设 H1-H8 × 多平台 VOC 实证 × KANO × JTBD × 场景四元素 × 3 轴竞品地图 × 4P 落地映射;<br/>
- 每一个结论都附 <strong style="color:${BRAND.LACTIC_MINT};">真实家长原声</strong>(昵称 + IP + 点赞)+ <strong style="color:${BRAND.TECH_BLUE};">理论模型映射</strong> + <strong style="color:${BRAND.SAGE};">可落地决策项</strong> 三重验证。
- </div>
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // 章节 Divider(8 个)
- // ============================================================
- function renderChapterDivider({ chapter, slideNum, slideTotal }) {
- const c = chapter;
- const heroLine = CHAPTER_HERO_LINES[c.key] || c.summary;
- const subs = CHAPTER_SUBSECTIONS[c.key] || [];
- return `<section class="report-section" id="${c.key}" data-tone="${c.tone}" data-slide-num="${slideNum}/${slideTotal}" style="justify-content:center;">
- <div class="section-inner">
- <div class="rise-in" style="text-align:center; margin-bottom:40px;">
- <div style="font-family:var(--font-head); font-weight:900; font-size:clamp(5rem, 14vw, 11rem); line-height:0.9; color:${c.color}; opacity:0.12; letter-spacing:-0.06em;">0${c.num}</div>
- <div class="text-mono text-xs" style="color:${c.color}; letter-spacing:0.3em; margin-top:-2rem; font-weight:700;">CHAPTER ${c.num} · ${c.en}</div>
- </div>
- <div class="rise-in" style="text-align:center; margin-bottom:36px;">
- <div style="font-size:3.2rem; margin-bottom:14px;">${c.icon}</div>
- <h2 class="text-poster" style="font-size:clamp(2.4rem, 5.2vw, 4.2rem); color:var(--text-1); letter-spacing:-0.025em;">${esc(c.title)}</h2>
- <p style="color:${c.color}; font-family:var(--font-mono); font-size:0.92rem; letter-spacing:0.18em; margin-top:12px; font-weight:600;">${c.en}</p>
- </div>
- <div class="fade-up" style="max-width:960px; margin:0 auto; text-align:center; padding:28px 32px; background:linear-gradient(135deg, ${c.color}0C, transparent); border-left:3px solid ${c.color}; border-radius:var(--radius-md);">
- <p style="color:var(--text-1); font-size:1.08rem; line-height:1.82;">${heroLine}</p>
- </div>
- <div class="fade-up" style="margin-top:40px; display:grid; grid-template-columns:repeat(${Math.min(subs.length, 5)}, 1fr); gap:14px; max-width:1100px; margin-left:auto; margin-right:auto;">
- ${subs.map((sub, i) => `
- <div style="padding:16px 14px; background:var(--bg-1); border:1px solid ${c.color}22; border-radius:var(--radius-sm); text-align:center;">
- <div class="text-mono text-xs" style="color:${c.color}; letter-spacing:0.15em; margin-bottom:6px; font-weight:700;">${c.num}.${i + 1}</div>
- <div style="color:var(--text-1); font-size:0.86rem; line-height:1.5;">${esc(sub)}</div>
- </div>`).join('')}
- </div>
- <div class="fade-up" style="margin-top:48px; text-align:center;">
- <div class="text-mono text-xs" style="color:var(--text-3); letter-spacing:0.3em;">SCROLL DOWN · ${subs.length} 个子章 · VOC 实证 × 理论 × 决策</div>
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // 占位子章(Coming Soon)
- // ============================================================
- function renderComingSoon({ chapter, subIdx, sub, slideNum, slideTotal, targetBatch, meta }) {
- const c = chapter;
- const hs = LA.CHAPTER_HYPOTHESIS_MAP[c.key] || [];
- const hsCount = hs.reduce((s, h) => s + (meta?.hypotheses?.[h] || 0), 0);
- return `<section class="report-section" id="${c.key}-${subIdx}" data-tone="${c.tone}" data-slide-num="${slideNum}/${slideTotal}">
- <div class="section-inner">
- <div class="section-head rise-in">
- <div class="section-eyebrow" style="color:${c.color};">${c.num}.${subIdx} · ${esc((sub || '').split('·')[0].toUpperCase())}</div>
- <h2 class="text-h1"><span class="headline-anim">${esc(sub)}</span></h2>
- <p class="section-sub">此子章将在 <strong style="color:${c.color};">Batch ${targetBatch}</strong> 填充 VOC 证据卡 + 理论映射 + 决策项</p>
- </div>
- <div class="fade-up" style="margin-top:40px; padding:40px; background:${c.color}08; border:1px dashed ${c.color}55; border-radius:var(--radius-lg); text-align:center;">
- <div style="font-size:3.4rem; margin-bottom:18px;">🚧</div>
- <div class="text-h2" style="color:${c.color}; margin-bottom:12px;">Coming in Batch ${targetBatch}</div>
- ${hsCount ? `
- <div style="display:inline-flex; align-items:center; gap:10px; padding:8px 16px; background:${BRAND.JIANG_GREEN}12; color:${BRAND.JIANG_GREEN}; border:1px solid ${BRAND.JIANG_GREEN}44; border-radius:20px; margin-bottom:20px; font-family:var(--font-mono); font-size:0.82rem; font-weight:600;">
- <span>✓</span> 数据就绪 · ${hsCount} 条 ${hs.join('/')} 相关真实 VOC
- </div><br/>
- <p style="color:var(--text-2); font-size:0.92rem; max-width:680px; margin:0 auto; line-height:1.7;">
- docs/乳酸菌/raw/_merged.json 已就绪 <strong style="color:${BRAND.LACTIC_MINT};">${meta?.comments || 0} 条真实 VOC</strong>,<br/>
- Batch ${targetBatch} 将基于本假设的 <strong style="color:${c.color};">${hsCount} 条</strong> 证据 + 理论工具,输出 <strong>证据卡 × 理论映射 × 决策项</strong>。
- </p>` : `
- <p style="color:var(--text-2); font-size:0.95rem; max-width:600px; margin:0 auto; line-height:1.7;">
- Batch ${targetBatch} 将基于已采集 VOC 数据填充本子章内容。
- </p>`}
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // 子章 → Batch 映射
- // ============================================================
- const SUB_TO_BATCH = {
- 'challenge': 2, 'drug_voc': 2, 'food_voc': 2,
- 'kano': 3, 'scene': 3,
- 'competitor': 4, 'opportunity': 4,
- 'blueprint': 5,
- };
- // ============================================================
- // 子章渲染器注册表
- // ============================================================
- let SLIDE_RENDERERS = {};
- function tryRequire(modPath) {
- try { return require(modPath); } catch (e) { return null; }
- }
- const CH1 = tryRequire('./lactic-ch1-challenge.js');
- const CH2 = tryRequire('./lactic-ch2-drug-voc.js');
- const CH3 = tryRequire('./lactic-ch3-food-voc.js');
- const CH4 = tryRequire('./lactic-ch4-kano.js');
- const CH5 = tryRequire('./lactic-ch5-scene.js');
- const CH6 = tryRequire('./lactic-ch6-competitor.js');
- const CH7 = tryRequire('./lactic-ch7-opportunity.js');
- const CH8 = tryRequire('./lactic-ch8-blueprint.js');
- SLIDE_RENDERERS = {
- ...(CH1 || {}),
- ...(CH2 || {}),
- ...(CH3 || {}),
- ...(CH4 || {}),
- ...(CH5 || {}),
- ...(CH6 || {}),
- ...(CH7 || {}),
- ...(CH8 || {}),
- };
- // ============================================================
- // buildHTML · 主装配
- // ============================================================
- function buildHTML({ product, collectedAt } = {}) {
- product = product || '江中乳酸菌素片儿童版';
- collectedAt = collectedAt || new Date().toISOString().slice(0, 10);
- const data = LA.loadMerged();
- const meta = LA.getMeta(data);
- // slide 总数:2 (cover+agenda) + 每章 (1 divider + N 子章)
- let slideTotal = 2;
- for (const c of CHAPTERS) {
- slideTotal += 1 + (CHAPTER_SUBSECTIONS[c.key] || []).length;
- }
- const slides = [];
- let num = 1;
- slides.push(renderCover({ product, collectedAt, slideNum: sn(num), slideTotal: sn(slideTotal), meta }));
- num++;
- slides.push(renderAgenda({ slideNum: sn(num), slideTotal: sn(slideTotal) }));
- num++;
- for (const c of CHAPTERS) {
- slides.push(renderChapterDivider({ chapter: c, slideNum: sn(num), slideTotal: sn(slideTotal) }));
- num++;
- const subs = CHAPTER_SUBSECTIONS[c.key] || [];
- for (let i = 0; i < subs.length; i++) {
- const subIdx = i + 1;
- const subKey = `${c.key}-${subIdx}`;
- const renderer = SLIDE_RENDERERS[subKey];
- const slideCtx = {
- chapter: c,
- subIdx,
- sub: subs[i],
- slideNum: sn(num),
- slideTotal: sn(slideTotal),
- data,
- meta,
- };
- if (renderer) {
- slides.push(renderer(slideCtx));
- } else {
- slides.push(renderComingSoon({ ...slideCtx, targetBatch: SUB_TO_BATCH[c.key] || 2, meta }));
- }
- num++;
- }
- }
- return `<!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
- <title>${esc(product)} · VOC 深度洞察报告 · 6000万→10亿</title>
- ${STYLES}
- </head>
- <body>
- ${renderNav()}
- ${renderKbdHint()}
- <div class="progress-line" id="progressLine"></div>
- <main class="deck">
- ${slides.join('\n')}
- </main>
- <script>${SCRIPTS}</script>
- </body>
- </html>`;
- }
- module.exports = {
- buildHTML,
- BRAND,
- CHAPTERS,
- CHAPTER_SUBSECTIONS,
- CHAPTER_HERO_LINES,
- SUB_TO_BATCH,
- renderCover,
- renderAgenda,
- renderChapterDivider,
- renderComingSoon,
- };
|