liver-v2-ch1-self.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // ==============================================================================
  2. // 肝纯片 v2 · Ch1 肝纯片自身画像(会议 req A · 全新)
  3. // ==============================================================================
  4. // 1.1 肝纯片自身 VOC · 用户画像
  5. // 1.2 满意 vs 不满意 · 双面分析
  6. // 1.3 藤茶 DMY 认知度 · 用户感知
  7. // ==============================================================================
  8. const LA = require('./liver-analyze.js');
  9. const C = require('./liver-components.js');
  10. const { BRAND, esc, renderSectionHead, renderVocCard, renderVocGrid,
  11. renderStatStrip, renderBarChart, renderCompareTable, renderInsightHero,
  12. renderFindingCard, renderDecisionList, LIVER_CONTEXT_RE } = C;
  13. // ============================================================
  14. // 1.1 自身 VOC · 用户画像
  15. // ============================================================
  16. function renderSub1({ chapter: c, subIdx, sub, slideNum, slideTotal, data, meta }) {
  17. const items = data?.items || [];
  18. // 筛选肝纯片自身 VOC(仅中文平台,排除 Amazon DHM 产品评论)
  19. const selfItems = items.filter(it => {
  20. if (it.platform === 'amazon') return false; // Amazon 上的 DHM 评论不是肝纯片产品
  21. const txt = `${it.keyword || ''} ${it.product || ''} ${it.content || ''}`.toLowerCase();
  22. return /肝纯|江中.*肝|藤茶.*片|肝片|护肝片/i.test(txt);
  23. });
  24. // 平台分布
  25. const selfPlatforms = {};
  26. selfItems.forEach(it => { const p = it.platform || 'unknown'; selfPlatforms[p] = (selfPlatforms[p] || 0) + 1; });
  27. // 情感分布
  28. const selfSentiments = {};
  29. selfItems.forEach(it => { const s = it.sentiment || 'neutral'; selfSentiments[s] = (selfSentiments[s] || 0) + 1; });
  30. // 用户画像标签
  31. const personas = [
  32. { name: '应酬打工人', re: /应酬|酒局|喝酒|打工人|加班/i, color: BRAND.WINE_RED, icon: '🍻' },
  33. { name: '脂肪肝患者', re: /脂肪肝|转氨酶|体检|肝功/i, color: BRAND.WARM_ORANGE, icon: '📊' },
  34. { name: '熬夜族', re: /熬夜|通宵|晚睡|加班/i, color: BRAND.PURPLE, icon: '🌙' },
  35. { name: '孝心子女', re: /送|父母|爸|妈|长辈|孝心|礼/i, color: BRAND.GOLD, icon: '🎁' },
  36. { name: '成分党/科学控', re: /成分|配方|水飞蓟|DMY|藤茶|研究|论文/i, color: BRAND.TECH_BLUE, icon: '🔬' },
  37. ];
  38. const personaStats = personas.map(p => ({
  39. ...p,
  40. count: selfItems.filter(it => p.re.test(it.content || '')).length,
  41. })).sort((a, b) => b.count - a.count);
  42. // 内容本身必须提到护肝产品/成分/症状,排除帖子下的无关闲聊
  43. const SELF_CONTENT_RE = /护肝|肝片|肝纯|转氨酶|脂肪肝|解酒|保肝|水飞蓟|藤茶|总黄酮|DMY|江中|养肝|肝功|肝损|肝不好/i;
  44. const selfEvidence = LA.getEvidence(selfItems, { top: 4, seed: 51, minChars: 20, contentMatch: SELF_CONTENT_RE });
  45. return `<section class="report-section" id="${c.key}-${subIdx}" data-tone="${c.tone}" data-slide-num="${slideNum}/${slideTotal}">
  46. <div class="section-inner">
  47. ${renderSectionHead({
  48. eyebrow: `${c.num}.${subIdx} · SELF PORTRAIT`,
  49. title: sub,
  50. subtitle: '江旭要求:"漏掉了我们自己产品的分析。肝纯片已经在抖音上卖了好几年了。"',
  51. color: c.color,
  52. })}
  53. ${renderStatStrip([
  54. { num: selfItems.length, label: '肝纯片自身 VOC', color: c.color },
  55. { num: selfSentiments.positive || 0, label: '好评', color: BRAND.JIANG_GREEN },
  56. { num: selfSentiments.negative || 0, label: '差评', color: BRAND.CORAL },
  57. { num: Object.keys(selfPlatforms).length, label: '平台覆盖', color: BRAND.TECH_BLUE },
  58. ])}
  59. <div style="margin-top:24px;">
  60. <div class="text-mono text-xs" style="color:${c.color}; letter-spacing:0.15em; margin-bottom:14px; font-weight:700;">用户画像 · 谁在买肝纯片?</div>
  61. <div style="display:grid; grid-template-columns:repeat(5, 1fr); gap:12px;">
  62. ${personaStats.map(p => `
  63. <div style="padding:16px; background:${p.color}08; border:1px solid ${p.color}33; border-radius:var(--radius-sm); text-align:center;">
  64. <div style="font-size:1.5rem; margin-bottom:6px;">${p.icon}</div>
  65. <div style="font-family:var(--font-head); font-size:1.4rem; font-weight:800; color:${p.color};">${p.count}</div>
  66. <div style="color:var(--text-2); font-size:0.74rem; margin-top:4px;">${esc(p.name)}</div>
  67. </div>`).join('')}
  68. </div>
  69. </div>
  70. <div style="margin-top:24px;">
  71. <div class="text-mono text-xs" style="color:${c.color}; letter-spacing:0.15em; margin-bottom:14px; font-weight:700;">肝纯片用户原声</div>
  72. ${renderVocGrid(selfEvidence, { columns: 2, accent: c.color })}
  73. </div>
  74. ${renderFindingCard({
  75. icon: '🪞',
  76. title: '自身画像核心发现',
  77. body: '肝纯片用户以<strong>应酬打工人</strong>和<strong>脂肪肝患者</strong>为主——这两类人群的需求最迫切。孝心子女是高价值但低频人群(礼品场景)。<strong style="color:' + BRAND.CORAL + ';">最大盲区</strong>:成分党/科学控对"藤茶 DMY"几乎没有认知,这是认知建设的核心任务。',
  78. accent: c.color,
  79. })}
  80. </div>
  81. </section>`;
  82. }
  83. // ============================================================
  84. // 1.2 满意 vs 不满意
  85. // ============================================================
  86. function renderSub2({ chapter: c, subIdx, sub, slideNum, slideTotal, data, meta }) {
  87. const items = data?.items || [];
  88. const selfItems = items.filter(it => {
  89. if (it.platform === 'amazon') return false; // Amazon DHM 评论不是肝纯片产品
  90. const txt = `${it.keyword || ''} ${it.product || ''} ${it.content || ''}`.toLowerCase();
  91. return /肝纯|江中.*肝|藤茶.*片|肝片|护肝片/i.test(txt);
  92. });
  93. // 用内容 regex 判断正负面(sentiment 字段推断不可靠)
  94. const selfPosRe = /有效|管用|好转|降了|见效|推荐|不错|靠谱|信赖|放心|有用的|真有用|确实有用|效果好|改善|缓解|值得/i;
  95. const selfNegRe = /没有?用(?!过)|没效|没感觉|智商税|骗|副作用|拉肚子|胃不舒服|难吃|不好用|效果不好|差评|头晕|不推荐|难受|不怎么管用|不太好用|进ICU|不降反升|伤肝|别吃/i;
  96. const posItems = selfItems.filter(it => { const c = it.content || ''; return selfPosRe.test(c) && !selfNegRe.test(c); });
  97. const negItems = selfItems.filter(it => selfNegRe.test(it.content || ''));
  98. // 好评维度
  99. const posDims = [
  100. { dim: '效果可感知', re: /有效|管用|见效|好转|转氨酶降/i, icon: '✅' },
  101. { dim: '天然/安全', re: /天然|安全|无副作用|放心|植物/i, icon: '🌿' },
  102. { dim: '品牌信任', re: /江中|大牌|老牌|信任|品牌/i, icon: '🏷️' },
  103. { dim: '送礼有面子', re: /送|礼|面子|好看|包装/i, icon: '🎁' },
  104. ];
  105. const posDimStats = posDims.map(d => ({
  106. ...d, count: posItems.filter(it => d.re.test(it.content || '')).length,
  107. }));
  108. // 差评维度
  109. const negDims = [
  110. { dim: '效果存疑', re: /没用|没效|没感觉|智商税|不确定/i, icon: '❓' },
  111. { dim: '价格偏高', re: /贵|价格|不值|性价比/i, icon: '💰' },
  112. { dim: '包装/剂型', re: /包装|药盒|片剂|难吃|不好吞/i, icon: '📦' },
  113. { dim: '认知模糊', re: /不知道|没听过|藤茶是什么|DMY/i, icon: '🤷' },
  114. ];
  115. const negDimStats = negDims.map(d => ({
  116. ...d, count: negItems.filter(it => d.re.test(it.content || '')).length,
  117. }));
  118. const SELF_CONTENT_RE2 = /护肝|肝片|肝纯|转氨酶|脂肪肝|解酒|保肝|水飞蓟|藤茶|江中|养肝|肝功|肝损|肝不好/i;
  119. const posEvidence = LA.getEvidence(posItems, { top: 3, seed: 52, minChars: 20, contentMatch: SELF_CONTENT_RE2 });
  120. const negEvidence = LA.getEvidence(negItems, { top: 3, seed: 53, minChars: 20, contentMatch: SELF_CONTENT_RE2 });
  121. return `<section class="report-section" id="${c.key}-${subIdx}" data-tone="${c.tone}" data-slide-num="${slideNum}/${slideTotal}">
  122. <div class="section-inner">
  123. ${renderSectionHead({
  124. eyebrow: `${c.num}.${subIdx} · SATISFACTION ANALYSIS`,
  125. title: sub,
  126. subtitle: '肝纯片用户"满意什么"和"不满意什么"——双面分析,不回避问题。',
  127. color: c.color,
  128. })}
  129. <div style="display:grid; grid-template-columns:1fr 1fr; gap:24px; margin-top:24px;">
  130. <!-- 好评面 -->
  131. <div style="padding:22px; background:${BRAND.JIANG_GREEN}06; border:1px solid ${BRAND.JIANG_GREEN}33; border-top:3px solid ${BRAND.JIANG_GREEN}; border-radius:var(--radius-md);">
  132. <div class="text-mono text-xs" style="color:${BRAND.JIANG_GREEN}; font-weight:700; margin-bottom:14px;">✅ 满意维度(${posItems.length} 条好评)</div>
  133. ${posDimStats.map(d => `
  134. <div style="display:flex; align-items:center; gap:10px; margin-bottom:10px;">
  135. <span style="font-size:1.1rem;">${d.icon}</span>
  136. <div style="flex:1;">
  137. <div style="display:flex; justify-content:space-between;">
  138. <span style="color:var(--text-1); font-size:0.84rem; font-weight:600;">${esc(d.dim)}</span>
  139. <span style="color:${BRAND.JIANG_GREEN}; font-size:0.78rem; font-weight:700;">${d.count}</span>
  140. </div>
  141. <div style="height:4px; background:var(--bg-2); border-radius:2px; margin-top:4px;">
  142. <div style="height:100%; background:${BRAND.JIANG_GREEN}; border-radius:2px; width:${Math.min(100, d.count / Math.max(1, posItems.length) * 200)}%;"></div>
  143. </div>
  144. </div>
  145. </div>`).join('')}
  146. ${posEvidence.length > 0 ? `<div style="margin-top:14px;">${renderVocGrid(posEvidence, { columns: 1, accent: BRAND.JIANG_GREEN, compact: true })}</div>` : ''}
  147. </div>
  148. <!-- 差评面 -->
  149. <div style="padding:22px; background:${BRAND.CORAL}06; border:1px solid ${BRAND.CORAL}33; border-top:3px solid ${BRAND.CORAL}; border-radius:var(--radius-md);">
  150. <div class="text-mono text-xs" style="color:${BRAND.CORAL}; font-weight:700; margin-bottom:14px;">❌ 不满意维度(${negItems.length} 条差评)</div>
  151. ${negDimStats.map(d => `
  152. <div style="display:flex; align-items:center; gap:10px; margin-bottom:10px;">
  153. <span style="font-size:1.1rem;">${d.icon}</span>
  154. <div style="flex:1;">
  155. <div style="display:flex; justify-content:space-between;">
  156. <span style="color:var(--text-1); font-size:0.84rem; font-weight:600;">${esc(d.dim)}</span>
  157. <span style="color:${BRAND.CORAL}; font-size:0.78rem; font-weight:700;">${d.count}</span>
  158. </div>
  159. <div style="height:4px; background:var(--bg-2); border-radius:2px; margin-top:4px;">
  160. <div style="height:100%; background:${BRAND.CORAL}; border-radius:2px; width:${Math.min(100, d.count / Math.max(1, negItems.length) * 200)}%;"></div>
  161. </div>
  162. </div>
  163. </div>`).join('')}
  164. ${negEvidence.length > 0 ? `<div style="margin-top:14px;">${renderVocGrid(negEvidence, { columns: 1, accent: BRAND.CORAL, compact: true })}</div>` : ''}
  165. </div>
  166. </div>
  167. ${renderDecisionList([
  168. '<strong>最强满意点</strong>:"效果可感知" + "天然安全"——这是核心卖点,必须放大',
  169. '<strong>最大不满</strong>:"效果存疑/智商税"——认知教育是第一优先级',
  170. '<strong>隐藏机会</strong>:"送礼有面子"好评比例高——礼品场景值得加大投入',
  171. '<strong>改进方向</strong>:包装去药盒感 + 价格感知优化(vs Swisse 便宜但用户不知道)',
  172. ], { accent: c.color, title: 'ACTION ITEMS · 自身画像启示' })}
  173. </div>
  174. </section>`;
  175. }
  176. // ============================================================
  177. // 1.3 藤茶 DMY 认知度
  178. // ============================================================
  179. function renderSub3({ chapter: c, subIdx, sub, slideNum, slideTotal, data, meta }) {
  180. const items = data?.items || [];
  181. // DMY/藤茶认知
  182. const dmyItems = items.filter(it => /DMY|二氢杨梅素|藤茶|显齿蛇葡萄/i.test(it.content || ''));
  183. const silymItems = items.filter(it => /水飞蓟|奶蓟|milk thistle|silymarin/i.test(it.content || ''));
  184. const dmyEvidence = LA.getEvidence(dmyItems, { top: 3, seed: 55, minChars: 15, contentMatch: /DMY|二氢杨梅素|藤茶|显齿蛇葡萄/i });
  185. const silymEvidence = LA.getEvidence(silymItems, { top: 3, seed: 56, minChars: 15, contentMatch: /水飞蓟|奶蓟|milk.?thistle|silymarin/i });
  186. return `<section class="report-section" id="${c.key}-${subIdx}" data-tone="${c.tone}" data-slide-num="${slideNum}/${slideTotal}">
  187. <div class="section-inner">
  188. ${renderSectionHead({
  189. eyebrow: `${c.num}.${subIdx} · DMY AWARENESS`,
  190. title: sub,
  191. subtitle: 'DMY 总黄酮 98% 是真实科学力——但用户完全不知道。',
  192. color: c.color,
  193. })}
  194. <div style="display:grid; grid-template-columns:1fr 60px 1fr; gap:0; margin-top:24px; align-items:start;">
  195. <!-- DMY/藤茶 -->
  196. <div style="padding:22px; background:${BRAND.TENGCHA_GREEN}08; border:2px solid ${BRAND.TENGCHA_GREEN}44; border-radius:var(--radius-md);">
  197. <div class="text-mono text-xs" style="color:${BRAND.TENGCHA_GREEN}; font-weight:700; margin-bottom:10px;">🌿 藤茶 / DMY 认知</div>
  198. <div style="font-family:var(--font-head); font-size:2rem; font-weight:800; color:${BRAND.TENGCHA_GREEN};">${dmyItems.length}</div>
  199. <div style="color:var(--text-3); font-size:0.72rem;">条 VOC 提及</div>
  200. <div style="color:var(--text-1); font-size:0.86rem; line-height:1.6; margin-top:12px;">
  201. <strong>现状</strong>:"藤茶"在用户心智中 = 一种茶饮,不是护肝成分<br/>
  202. <strong>"DMY"</strong>:几乎零认知,用户搜不到也念不出<br/>
  203. <strong>机会</strong>:"千年食饮史"可做安全感锚点
  204. </div>
  205. ${dmyEvidence.length > 0 ? `<div style="margin-top:12px;">${renderVocGrid(dmyEvidence, { columns: 1, accent: BRAND.TENGCHA_GREEN, compact: true })}</div>` : ''}
  206. </div>
  207. <div style="text-align:center; color:var(--text-3); font-size:1.5rem; padding-top:40px;">vs</div>
  208. <!-- 水飞蓟对比 -->
  209. <div style="padding:22px; background:${BRAND.CORAL}06; border:2px solid ${BRAND.CORAL}33; border-radius:var(--radius-md);">
  210. <div class="text-mono text-xs" style="color:${BRAND.CORAL}; font-weight:700; margin-bottom:10px;">🔴 水飞蓟 / Milk Thistle</div>
  211. <div style="font-family:var(--font-head); font-size:2rem; font-weight:800; color:${BRAND.CORAL};">${silymItems.length}</div>
  212. <div style="color:var(--text-3); font-size:0.72rem;">条 VOC 提及</div>
  213. <div style="color:var(--text-1); font-size:0.86rem; line-height:1.6; margin-top:12px;">
  214. <strong>现状</strong>:认知度高但差评多<br/>
  215. <strong>痛点</strong>:"吸收差 / no effect / 胃不舒服"<br/>
  216. <strong>教训</strong>:高认知 ≠ 高满意度
  217. </div>
  218. ${silymEvidence.length > 0 ? `<div style="margin-top:12px;">${renderVocGrid(silymEvidence, { columns: 1, accent: BRAND.CORAL, compact: true })}</div>` : ''}
  219. </div>
  220. </div>
  221. ${renderInsightHero({
  222. eyebrow: 'AWARENESS GAP',
  223. title: 'DMY 认知度近零——但这恰恰是品类创新的机会',
  224. subtitle: `水飞蓟认知高但口碑差 → 用户正在寻找替代方案。藤茶 DMY"千年食饮史 + 总黄酮 98%"的故事如果讲好,可以<strong style="color:${BRAND.TENGCHA_GREEN};">直接占据"天然护肝"的心智空位</strong>——这是特劳特说的"差异化 + 聚焦"。`,
  225. color: BRAND.TENGCHA_GREEN,
  226. })}
  227. </div>
  228. </section>`;
  229. }
  230. module.exports = { renderSub1, renderSub2, renderSub3 };