| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- // ==============================================================================
- // 江中猴菇饮 OTC · VOC 深度洞察报告 · 主渲染器
- // ==============================================================================
- // 设计哲学:反向定位(VOC 先于产品决策)× 理论 × 实证双轴验证
- //
- // 报告结构(8 章 × 约 38 slides):
- // 01 · Cover
- // 02 · Agenda
- // 03-05 · Ch1 诘问起点(3 子章):产品困境 / 市场现实 / VOC 驱动反向定位
- // 06-09 · Ch2 米稀归因学(4 子章):成功因子 / 差评挖机会 / 饼干失败 / 可迁移性
- // 10-13 · Ch3 胃药 VOC 全景(4 子章):拉唑依赖 / 中成药抗性 / 功能食品乏力 / 未满足地图
- // 14-18 · Ch4 KANO × JTBD(5 子章):KANO 五类 / F / E / S / 决策优先级
- // 19-22 · Ch5 场景三元素地图(4 子章):独占场景 Top 4
- // 23-25 · Ch6 竞品三轴(3 子章):三轴图 / 差异化坐标 / 同名对标
- // 26-28 · Ch7 新机会(3 子章):3 条长尾赛道
- // 29-30 · Ch8 4P 蓝图(2 子章):产品/渠道/推广/价格 + 5000 万 → 5 亿路径
- //
- // Batch 1:cover + agenda + 8 dividers = 10 slides 骨架
- // Batch 3-6 逐步填充 Ch1-Ch8 子章
- // ==============================================================================
- const STYLES = require('./voc-styles.js');
- const SCRIPTS = require('./voc-scripts.js');
- const HGY = require('./houguyin-analyze.js');
- const CH1 = require('./houguyin-ch1-landscape.js');
- const CH2 = require('./houguyin-ch2-unmet.js');
- const CH3 = require('./houguyin-ch3-fit.js');
- const CH4 = require('./houguyin-ch4-kano.js');
- const CH5 = require('./houguyin-ch5-scene.js');
- const CH6 = require('./houguyin-ch6-competitor.js');
- const CH7 = require('./houguyin-ch7-opportunity.js');
- const CH8 = require('./houguyin-ch8-blueprint.js');
- const CH9 = require('./houguyin-ch9-voice.js');
- // ============================================================
- // 主题色(猴菇饮专属色板)
- // ============================================================
- const BRAND = {
- JIANG_GREEN: '#2D9C5D', // 江中主色(品牌认知/新机会)
- HOUGU_TAN: '#E8A87C', // 猴菇暖棕(米稀归因/产品主色)
- DEEP_AMBER: '#C96E3F', // 猴头菇深色(礼品装/传统)
- CREAM: '#F5E6D3', // 米黄色(米稀联想)
- TECH_BLUE: '#0085CA', // 信任蓝(药品 VOC / 胃药市场)
- WARM_ORANGE: '#FF8C42', // 温暖橙(场景地图)
- CORAL: '#FF6B6B', // 珊瑚红(诘问/痛点情绪)
- SAGE: '#87A96B', // 药食鼠尾草绿(日常养护)
- PURPLE: '#8B5CF6', // 紫色(KANO × JTBD 理论/心智)
- ROSE: '#FF4D8D', // 玫瑰(竞品对比)
- };
- // ============================================================
- // 8 章元信息(按认知深度递进,非模块平铺)
- // ============================================================
- const CHAPTERS = [
- { id: 1, num: '1', key: 'landscape', title: '胃病人群全景', en: 'GI POPULATION', tone: 'blue', color: BRAND.TECH_BLUE, icon: '�',
- summary: '2.5 亿胃病人群 × 5 级症状谱(由重到轻)× 每层当前用什么产品' },
- { id: 2, num: '2', key: 'unmet', title: '未被满足的需求', en: 'UNMET NEEDS', tone: 'rose', color: BRAND.CORAL, icon: '🔥',
- summary: '每一层产品的用户都在痛苦什么?PPI 依赖焦虑 / 中成药口感抗性 / 功能食品无信任' },
- { id: 3, num: '3', key: 'fit', title: '猴菇饮的机会', en: 'OUR OPPORTUNITY', tone: 'green', color: BRAND.JIANG_GREEN, icon: '🎯',
- summary: '哪些未满足需求是我们的产品可以满足的?3 大机会×无人地带坐标' },
- { id: 4, num: '4', key: 'kano', title: 'KANO × JTBD 洞察', en: 'USER INSIGHT', tone: 'purple', color: BRAND.PURPLE, icon: '🧠',
- summary: 'KANO 五类需求 × JTBD Functional/Emotional/Social 三维用户价值' },
- { id: 5, num: '5', key: 'scene', title: '场景三元素地图', en: 'SCENE MAP', tone: 'orange', color: BRAND.WARM_ORANGE, icon: '🗺',
- summary: '时间 × 空间 × 触发事件 · 米稀没覆盖的"饮独占场景" 4 条' },
- { id: 6, num: '6', key: 'competitor', title: '竞品三轴图谱', en: 'COMPETITION AXES', tone: 'rose', color: BRAND.ROSE, icon: '⚔',
- summary: '食品(米稀/饼干)、保健品(同名猴菇饮)、药品(三九胃泰/拉唑)三轴定位图谱上,猴菇饮 OTC 的无人地带坐标' },
- { id: 7, num: '7', key: 'opportunity',title: '新机会 × 新场景 × 新人群', en: 'OPPORTUNITY', tone: 'green', color: BRAND.JIANG_GREEN, icon: '💡',
- summary: '3 条可落地长尾赛道 · 每条都带 VOC 证据链 + 转化路径' },
- { id: 8, num: '8', key: 'blueprint', title: '4P 配称蓝图', en: '4P BLUEPRINT', tone: 'green', color: BRAND.SAGE, icon: '🚀',
- summary: '产品 / 渠道 / 推广 / 价格 · 药店 5000 万 → 5 亿落地路径' },
- { id: 9, num: '9', key: 'voice', title: '真声洞察', en: 'VOICE OF CUSTOMER', tone: 'rose', color: BRAND.CORAL, icon: '💬',
- summary: '清洗后 404 条真 VOC 的独家维度:痛点金句墙 × 慢性陪伴时长 × 替代方案尝试史' },
- ];
- // ============================================================
- // 各章节 subsections 清单(Batch 1 定义,后续批次填充内容)
- // ============================================================
- const CHAPTER_SUBSECTIONS = {
- 'landscape': [
- '2.5亿胃病人群·5级症状谱×产品对应',
- '产品竞争格局·100亿市场拆解×代表品牌',
- '用户决策路径·从症状到产品选择的真实链路',
- ],
- 'unmet': [
- 'PPI层·依赖焦虑×反弹恐惧×副作用担忧',
- '中成药层·口感抗性×起效慢×代际断层',
- '功能食品层·身份尴尬×场景单一×无OTC信任',
- '跨层汇总·5大共性未满足需求',
- ],
- 'fit': [
- '机会①·PPI减量的温和伴侣',
- '机会②·中成药新代际替代',
- '机会③·功能食品OTC信任升级×米稀借力',
- '战略坐标·无人地带×机会规模总览',
- ],
- 'kano': [
- 'KANO 五类需求·必备/期望/兴奋/无差异/反向',
- 'JTBD·Functional 功能价值',
- 'JTBD·Emotional 情绪价值',
- 'JTBD·Social 社会价值',
- '决策优先级·SKU/话术/包装映射',
- ],
- 'scene': [
- '场景#1·应酬应急·液体快速',
- '场景#2·熬夜前后·便携单支',
- '场景#3·办公室养护·节奏断续',
- '场景#4·差旅/术后·无菜谱无辅料',
- ],
- 'competitor': [
- '三轴定位图谱·食品/保健品/药品',
- '无人地带坐标·猴菇饮独占位',
- '同名竞品对标·3 家猴菇饮 VOC',
- ],
- 'opportunity': [
- '新机会·PPI 离断过渡饮',
- '新场景·"送胃"礼品赛道',
- '新人群·糖友无糖版 + 夜宵族',
- ],
- 'blueprint': [
- '4P 配称·产品+渠道+推广+价格',
- '5000 万 → 5 亿路径·3 阶段',
- ],
- 'voice': [
- '真痛点金句墙·10 条 VOC × 未满足需求',
- '胃病 N 年地图·慢性陪伴时长分布',
- '替代方案尝试史·4 条折返路径',
- ],
- };
- // ============================================================
- // 每章 hero line(divider 用)
- // ============================================================
- const CHAPTER_HERO_LINES = {
- 'landscape': '中国 <strong style="color:#0085CA;">2.5 亿</strong>胃病患者,从胃溡穿孔到偶发胃胀,症状严重度跨越 5 个层级。<strong>每一层用户现在在用什么产品?</strong>从处方 PPI 到达喜铝碳酸镁刲片,从三九胃泰到猴菇米稀——把 100 亿胃药市场按<strong style="color:#FF6B6B;">“症状严重度 × 产品对应”</strong>拆开,看清每层的竞争现状和用户决策路径。',
- 'unmet': '每一层产品的用户都在痛苦。PPI 用户“<strong style="color:#FF6B6B;">有效但不敢停</strong>”,中成药用户“<strong style="color:#FF8C42;">苦涩难咽年轻人不买账</strong>”,功能食品用户“<strong style="color:#E8A87C;">吃了个寂寞无 OTC 信任</strong>”。把每层的 VOC 痛声铺开,提炼出 <strong style="color:#8B5CF6;">5 大跨层共性未满足需求</strong>。',
- 'fit': '把未满足需求与猴菇饮 OTC 的产品特性一一对位:<strong style="color:#2D9C5D;">PPI 减量伴侣</strong>(接住“想停药但不敢停”)、<strong style="color:#8B5CF6;">中成药新代际替代</strong>(消灭口感/冲泡/疗程压力)、<strong style="color:#E8A87C;">OTC 信任升级</strong>(从食品跳进药品池)。在“疗效强度 × 使用门槛”四象限里找到<strong style="color:#2D9C5D;">无人地带坐标</strong>。',
- 'kano': '不再用"4 渠道 × 5 模块"装饰理论。<strong style="color:#8B5CF6;">KANO 五类需求模型</strong>(必备 / 期望 / 兴奋 / 无差异 / 反向)逐个映射到 SKU / 包装 / 话术决策。<strong style="color:#E8A87C;">JTBD 用户价值三维</strong>(Functional 胃舒服 · Emotional 不焦虑不依赖 · Social 养生时尚/孝心/面子)定义用户"雇佣"这瓶饮的真正理由。',
- 'scene': '早餐场景已被米稀占满。液体饮(快速 / 便携 / 单支)的独占场景在哪里?<strong style="color:#FF8C42;">时间 × 空间 × 触发事件</strong> 三元素交叉,定位出 <strong>应酬应急 / 熬夜前后 / 办公室节奏 / 差旅术后</strong> 4 条米稀触不到的独占场景 —— 每个场景都有对应的人群、话术、触发物。',
- 'competitor': '食品(米稀/饼干)、保健品(同名猴菇饮)、药品(三九胃泰/拉唑)<strong style="color:#FF4D8D;">三轴定位图谱</strong>上,猴菇饮 OTC 的 <strong style="color:#FF8C42;">无人地带坐标</strong> = "食品的温和 × 药品的 OTC 信任 × 保健品的日常节奏"。直接对标同名 3 家猴菇饮的 VOC 差评,找出差异化 MOAT。',
- 'opportunity': '基于 VOC 深挖,提炼 <strong style="color:#2D9C5D;">3 条可落地长尾赛道</strong>:① <strong>PPI 离断过渡饮</strong>(焦虑断药人群)② <strong>"送胃"礼品赛道</strong>(孝心/应酬)③ <strong>糖友无糖版 + 夜宵族</strong>(细分人群)。每条赛道配 VOC 原声证据链 + 场景化转化路径 + 数据化规模预估。',
- 'blueprint': '以 VOC 洞察反推 <strong style="color:#87A96B;">4P 配称</strong>:产品(多规格 SKU 矩阵)+ 渠道(药店 + 电商 + 食疗挂靠)+ 推广(KANO 兴奋需求作为钩子)+ 价格(日服用成本 12 元毛利释放)。3 阶段落地路径:<strong>Y1 药店 5000 万验证 → Y2 渠道复制 1.5 亿 → Y3 品类升级 5 亿</strong>。',
- 'voice': '理论章节用完后,是时候<strong style="color:#FF6B6B;">把麦克风交回给用户</strong>。这一章只有三件事:① <strong>10 条真痛点金句</strong>(每条都有真实赞数与平台来源,每条都对应一个猴菇饮可以直接接住的未满足需求)② <strong>胃病 N 年地图</strong>(胃病不是急症是慢性陪伴,≤1/2-5/5-10/10+ 年 4 段用户需要不同接入策略)③ <strong>4 条替代方案尝试路径</strong>(PPI 独行者 / 西中食折返者 / 自救派 / 崩溃躺平者——差异化介入节点)。这一章不是补遗,是所有前 8 章理论归纳的<strong style="color:#E8A87C;">用户原声锚点</strong>。',
- };
- // 预估 slide 总数(Batch 1 仅骨架 10 张,后续批次填充到 ~38)
- const TOTAL_SLIDES_TARGET = 38;
- // ============================================================
- // utils
- // ============================================================
- function esc(s) {
- return String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
- }
- function fmtNum(n) {
- if (n == null || isNaN(n)) return '—';
- if (n >= 10000) return (n / 10000).toFixed(1).replace(/\.0$/, '') + 'w';
- if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k';
- return String(n);
- }
- 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>产品开发部 / 猴菇饮 OTC VOC 深度洞察 v1.0</div>
- <div class="text-mono text-xs" style="color:var(--text-3);">REVERSE POSITIONING / 三轴无人地带 / 借力米稀 7.5 亿</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 || 'batch-1-scaffold';
- const tier = meta?.sourceTier || 'unknown';
- const isScaffold = stage === 'batch-1-scaffold';
- const isSeed = tier === 'pattern-curated';
- const isReal = tier === 'real-collected';
- // 源标识(右上角徽标,透明度原则)
- const sourceBadge = isReal
- ? { label: '真实采集', color: BRAND.JIANG_GREEN, icon: '✓' }
- : isSeed
- ? { label: 'Batch 2 · 公开模式归纳种子版', color: BRAND.HOUGU_TAN, icon: '◈' }
- : { label: 'Batch 1 · 骨架版', 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 text-amber rise-in" style="font-size:0.9rem;letter-spacing:0.2em;margin-bottom:18px;">REVERSE POSITIONING × KANO × JTBD × SCENE</p>
- <h1 class="cover-title rise-in">${esc(product)}<br/><span style="color:${BRAND.HOUGU_TAN}; -webkit-text-fill-color:${BRAND.HOUGU_TAN}; 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;">
- 没有体感优势 · 如何从用户真实声音<strong style="color:${BRAND.HOUGU_TAN};">反向定位</strong>出新机会
- </p>
- </div>
- <p class="cover-sub fade-up">
- 基于 <strong class="text-amber">0.基础调研.md 内部会议确认</strong>的 VOC 反向定位方法论,跳出"10 亿×4 渠道"正向框架,
- 直面 <strong style="color:${BRAND.CORAL};">产品无显著体感</strong>的残酷现实,
- 通过 <strong class="text-amber">KANO × JTBD × 场景三元素</strong> 理论模型 × <strong class="text-amber">${isScaffold ? '5000+' : totalComments.toLocaleString()}</strong> 条${isSeed ? '公开讨论模式归纳的' : ''}多平台<strong class="text-amber">评论颗粒度</strong>原声交叉验证,
- 解构 <strong style="color:${BRAND.HOUGU_TAN};">米稀 7.5 亿成功</strong>的可迁移因子,对标 <strong style="color:${BRAND.TECH_BLUE};">100 亿胃药 OTC 市场</strong>的 VOC 痛点地图,
- 在 <strong style="color:${BRAND.ROSE};">食品 ↔ 保健品 ↔ 药品三轴无人地带</strong>中提炼 <strong style="color:${BRAND.JIANG_GREEN};">3 条长尾赛道</strong>,
- 输出 <strong style="color:${BRAND.SAGE};">4P 配称蓝图</strong>,闭环 <strong style="color:${BRAND.HOUGU_TAN};">药店 5000 万 → 5 亿</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">5000万</div><div class="lbl">药店目标</div></div>
- <div class="cover-stat"><div class="num">${commentsDisplay}</div><div class="lbl">${isSeed ? 'Seed VOC' : '真实评论'}</div></div>
- <div class="cover-stat"><div class="num">${isScaffold ? '7+' : platformCount}</div><div class="lbl">${isSeed ? '覆盖平台' : '采集平台'}</div></div>
- <div class="cover-stat"><div class="num">8</div><div class="lbl">核心假设</div></div>
- <div class="cover-stat"><div class="num">${isScaffold ? '14' : (productsCount || 14)}</div><div class="lbl">产品维度</div></div>
- <div class="cover-stat"><div class="num">${slideTotal}</div><div class="lbl">slides</div></div>
- </div>
- ${isSeed ? `<div class="fade-up" style="margin-top:32px; padding:14px 20px; background:${BRAND.HOUGU_TAN}08; border-left:3px solid ${BRAND.HOUGU_TAN}; border-radius:4px; max-width:920px; margin-left:auto; margin-right:auto; text-align:left;">
- <div class="text-mono text-xs" style="color:${BRAND.HOUGU_TAN}; letter-spacing:0.14em; margin-bottom:6px; font-weight:700;">DATA TRANSPARENCY · 数据透明度声明</div>
- <p style="color:var(--text-2); font-size:0.82rem; line-height:1.6; margin:0;">
- 本报告 Batch 2 使用的 <strong style="color:${BRAND.HOUGU_TAN};">${totalComments} 条 Seed VOC</strong> 为<strong>公开讨论模式归纳</strong>(电商评论/社交笔记/医学论坛公开数据),
- 覆盖 <strong>${platformCount} 平台 · ${productsCount || 14} 产品维度 · H1-H8 全假设</strong>,用于验证分析框架与渲染质量。
- 每条 VOC 带 <code style="background:${BRAND.HOUGU_TAN}15; padding:1px 5px; border-radius:3px; color:${BRAND.HOUGU_TAN};">source=pattern-curated</code> 明确标识,
- 在正式交付前 <strong style="color:${BRAND.JIANG_GREEN};">会由 houguyin-collect.js 替换为真实 API 采集数据</strong>。
- </p>
- </div>` : ''}
- <p class="text-mono text-xs fade-up" style="margin-top:${isSeed ? '40' : '64'}px; color:var(--text-3);">SCROLL DOWN · ${isScaffold ? 'Batch 1 · 骨架版 · 待 Batch 2 采集完成填充真实 VOC' : isSeed ? `Batch 2 · 种子版 · ${totalComments} 条公开模式 VOC · 覆盖 H1-H8` : `采集截止 ${esc(collectedAt || '')} · ${totalComments.toLocaleString()} 条真实 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">CONTENTS · 8 章认知递进</div>
- <h2 class="text-h1"><span class="headline-anim">从诘问到蓝图 · 反向定位 VOC 深洞察</span></h2>
- <p class="section-sub">不按模块平铺 · 按<strong class="text-amber">认知深度递进</strong>:① 诘问 → ② 米稀归因 → ③ 胃药全景 → ④ 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.HOUGU_TAN}10, ${BRAND.JIANG_GREEN}06); border:1px solid ${BRAND.HOUGU_TAN}22; border-radius:var(--radius-md);">
- <div class="text-mono text-xs" style="color:${BRAND.HOUGU_TAN}; 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.HOUGU_TAN};">docs/jiangzhong-houguyin/1.VOC深度思路.md</strong>》反向定位方法论:<br/>
- <strong style="color:${BRAND.CORAL};">❌ 不做</strong>:改配方/改批文/改剂型、宣称治疗、装饰性理论图表;<br/>
- <strong style="color:${BRAND.JIANG_GREEN};">✅ 做</strong>:8 条核心假设 H1-H8 × 多平台 VOC 实证(米稀/饼干/三九胃泰/拉唑/同名竞品/礼品类比)× KANO+JTBD 理论模型作决策工具;<br/>
- 每一个结论都附 <strong style="color:${BRAND.HOUGU_TAN};">真实用户原声</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} 个子章 · 理论 × 实证 × 机会</div>
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // 占位子章(Coming Soon 提示)· 会展示当前 Seed VOC 覆盖度
- // ============================================================
- function renderComingSoon({ chapter, subIdx, sub, slideNum, slideTotal, targetBatch, meta }) {
- const c = chapter;
- const tier = meta?.sourceTier || 'unknown';
- const isSeedReady = tier === 'pattern-curated' || tier === 'real-collected';
- // 为此章节所映射的假设准备 seed 覆盖提示
- const chapterHypothesisMap = {
- 'landscape': ['H1', 'H3', 'H5'],
- 'unmet': ['H1', 'H2'],
- 'fit': ['H1', 'H3', 'H4', 'H5'],
- 'kano': ['H1', 'H3', 'H4', 'H5'],
- 'scene': ['H5'],
- 'competitor': ['H5', 'H6'],
- 'opportunity': ['H4', 'H7', 'H8'],
- 'blueprint': ['H6', 'H8'],
- };
- const hs = chapterHypothesisMap[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.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>
- ${isSeedReady ? `
- <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> Seed VOC 已就绪 · ${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;">
- Batch 2 已完成 <strong style="color:${BRAND.HOUGU_TAN};">${meta?.comments || 326} 条公开模式 seed VOC</strong> 采集(覆盖 H1-H8 × 6 平台 × 14 产品维度),<br/>
- Batch ${targetBatch} 将基于本假设的 <strong style="color:${c.color};">${hsCount} 条</strong> 证据 + KANO×JTBD 理论工具,输出 <strong>理论映射 × 实证卡片 × 决策项</strong>。
- </p>` : `
- <p style="color:var(--text-2); font-size:0.95rem; max-width:600px; margin:0 auto; line-height:1.7;">
- Batch 2 将完成多平台 VOC 采集,Batch ${targetBatch} 填充本子章内容。
- </p>`}
- </div>
- </div>
- </section>`;
- }
- // ============================================================
- // 子章 → Batch 映射(每章归属哪个 Batch)
- // ============================================================
- const SUB_TO_BATCH = {
- 'landscape': 3, 'unmet': 3, 'fit': 3,
- 'kano': 4, 'scene': 4,
- 'competitor': 5, 'opportunity': 5,
- 'blueprint': 6,
- 'voice': 7,
- };
- // ============================================================
- // 子章渲染器注册表(Batch 3 已填充 Ch1/Ch2/Ch3;Batch 4-6 逐步补齐)
- // ============================================================
- const SLIDE_RENDERERS = {
- ...CH1, // Ch1 胃病人群全景
- ...CH2, // Ch2 未被满足的需求
- ...CH3, // Ch3 猴菇饮的机会
- ...CH4, // Ch4 KANO × JTBD 深度洞察
- ...CH5, // Ch5 场景三元素地图
- ...CH6, // Ch6 竞品三轴图谱
- ...CH7, // Ch7 新机会 × 新场景 × 新人群
- ...CH8, // Ch8 4P 配称蓝图
- ...CH9, // Ch9 真声洞察(基于真 VOC 的独家维度)
- };
- // ============================================================
- // buildHTML · 主装配
- // ============================================================
- function buildHTML({ product, collectedAt } = {}) {
- product = product || '江中猴菇饮';
- collectedAt = collectedAt || new Date().toISOString().slice(0, 10);
- // 加载数据(Batch 1 为 skeleton)
- const data = HGY.loadMerged();
- const meta = HGY.getMeta(data);
- // 计算 slide 总数:2 (cover+agenda) + 每章 (1 divider + N 子章)
- let slideTotal = 2;
- for (const c of CHAPTERS) {
- slideTotal += 1; // divider
- slideTotal += (CHAPTER_SUBSECTIONS[c.key] || []).length; // subsections
- }
- const slides = [];
- let num = 1;
- // Slide 01 · Cover
- slides.push(renderCover({ product, collectedAt, slideNum: sn(num), slideTotal: sn(slideTotal), meta }));
- num++;
- // Slide 02 · Agenda
- slides.push(renderAgenda({ slideNum: sn(num), slideTotal: sn(slideTotal) }));
- num++;
- // 每章节:divider + 子章们
- for (const c of CHAPTERS) {
- // Divider
- slides.push(renderChapterDivider({ chapter: c, slideNum: sn(num), slideTotal: sn(slideTotal) }));
- num++;
- // Subsections
- 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] || 3, 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 深度洞察报告 · 反向定位</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,
- TOTAL_SLIDES_TARGET,
- renderCover,
- renderAgenda,
- renderChapterDivider,
- renderComingSoon,
- };
|