feat: 新增愈心解码整合页面 + 公共代码重构

- 新增 common.js: 从 shuzi.html/yangsheng.html 提取共享引擎(数字三角计算、八字五行、体质判别等纯函数+数据字典)
- 新增 jiema.html: 愈心解码统一入口,整合数字性格+五行体质+今日锦囊,含付费墙(模拟支付)、分享卡片、契合度测算
- shuzi.html: 引用 common.js,删重复代码,新增返回链接+URL参数预填
- yangsheng.html: 引用 common.js,删重复代码,新增返回链接+URL参数预填
- yuxingu.html: Hero下方新增愈心解码入口卡片(含生日输入+生成按钮)
- index.html: 新增愈心解码导航卡片
- CLAUDE.md: 补充项目文档和架构说明

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jackyu66git
2026-07-13 12:59:06 +08:00
co-authored by Claude
parent 33e6dffa17
commit 573095325f
7 changed files with 758 additions and 295 deletions
+336
View File
@@ -0,0 +1,336 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>愈心解码 · 一个生日读懂身与心</title>
<style>
:root{
--pri:#E54D42; --num:#C8923A; --num-d:#8a6d3b;
--ys:#5CB85C; --ys-d:#3f8f45;
--text:#333; --sub:#999;
--bg-start:#FFD1C7; --bg-end:#FFC8B5;
}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
body{font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;
color:var(--text);background:linear-gradient(160deg,var(--bg-start),var(--bg-end));
min-height:100vh;padding-bottom:80px;}
.wrap{max-width:430px;margin:0 auto;padding:0 14px;}
.top{text-align:center;padding:22px 0 10px;}
.top .t{font-size:24px;font-weight:800;letter-spacing:3px;color:#fff;
text-shadow:0 2px 8px rgba(0,0,0,.15);}
.top .s{font-size:12px;color:#fff;opacity:.9;margin-top:4px;}
.card{background:#fff;border-radius:18px;padding:20px;margin:14px 0;
box-shadow:0 8px 30px rgba(0,0,0,.08);}
.tag{display:inline-block;font-size:11px;padding:3px 10px;border-radius:20px;
color:#fff;font-weight:600;margin-bottom:10px;}
.tag-num{background:var(--num);}
.tag-ys{background:var(--ys);}
/* Part1 数字 */
.hex{width:76px;height:76px;margin:6px auto 8px;display:flex;align-items:center;
justify-content:center;font-size:34px;font-weight:800;color:#fff;
background:linear-gradient(135deg,var(--num),var(--num-d));
clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);}
.p-title{text-align:center;font-size:19px;font-weight:700;color:var(--num-d);}
.p-oneline{text-align:center;font-size:13px;color:var(--sub);margin-top:4px;}
.pyr{text-align:center;margin:16px 0;}
/* Part2 体质 */
.ys-type{text-align:center;font-size:20px;font-weight:700;color:var(--ys-d);margin:4px 0;}
.ys-dir{text-align:center;font-size:13px;color:var(--sub);}
.bars{margin:16px 0 6px;}
.bar-row{display:flex;align-items:center;gap:8px;margin:7px 0;font-size:13px;}
.bar-row .lab{width:20px;text-align:center;font-weight:700;}
.bar-track{flex:1;height:14px;background:#f0f0f0;border-radius:8px;overflow:hidden;}
.bar-fill{height:100%;border-radius:8px;transition:width .6s;}
.bar-row .val{width:34px;text-align:right;color:var(--sub);}
/* 付费墙 */
.lock{position:relative;margin-top:14px;border-radius:14px;overflow:hidden;
border:1px solid #f2e6d0;}
.lock .blur{filter:blur(5px);pointer-events:none;user-select:none;
padding:16px;font-size:13px;line-height:1.9;color:#666;}
.lock .cover{position:absolute;inset:0;background:linear-gradient(180deg,
rgba(255,255,255,.4),rgba(255,255,255,.92));display:flex;flex-direction:column;
align-items:center;justify-content:center;text-align:center;padding:16px;}
.lock .cover .lk-t{font-size:15px;font-weight:700;color:var(--num-d);}
.lock .cover .lk-d{font-size:12px;color:var(--sub);margin:6px 0 12px;}
.unlock-btn{background:var(--pri);color:#fff;border:none;padding:11px 30px;
border-radius:24px;font-size:15px;font-weight:700;cursor:pointer;
box-shadow:0 4px 14px rgba(229,77,66,.35);}
.unlocked .cover{display:none;}
.unlocked .blur{filter:none;pointer-events:auto;user-select:auto;}
/* Part3 今日锦囊 */
.jn h4{font-size:14px;color:var(--ys-d);margin-bottom:8px;}
.jn .row{font-size:13px;line-height:2;color:#555;}
.jn .row b{color:var(--ys-d);}
.jn .st{font-size:12px;color:var(--sub);margin-bottom:6px;}
/* 契合度 / 分享 */
.mini-form{display:flex;gap:6px;align-items:center;justify-content:center;
flex-wrap:wrap;margin-top:10px;}
.mini-form input{width:56px;padding:9px 4px;border:1.5px solid #eee;
border-radius:9px;text-align:center;font-size:14px;}
.mini-form button,.share-btn{background:var(--pri);color:#fff;border:none;
padding:10px 20px;border-radius:22px;font-size:14px;font-weight:600;cursor:pointer;}
.share-btn{display:block;width:100%;margin-top:6px;}
.match-score{text-align:center;font-size:32px;font-weight:800;color:var(--pri);margin:8px 0 2px;}
/* 深度入口 */
.deep{display:flex;gap:10px;margin:16px 0;}
.deep a{flex:1;text-align:center;padding:13px 6px;border-radius:14px;
color:#fff;text-decoration:none;font-size:13px;font-weight:600;}
.deep .d-num{background:linear-gradient(135deg,var(--num),var(--num-d));}
.deep .d-ys{background:linear-gradient(135deg,var(--ys),var(--ys-d));}
.disc{font-size:11px;color:#fff;opacity:.8;text-align:center;line-height:1.7;
padding:14px 8px;}
.err{text-align:center;color:#fff;padding:40px 20px;font-size:15px;}
/* 分享卡片 canvas 弹层 */
.modal{position:fixed;inset:0;background:rgba(0,0,0,.6);display:none;
align-items:center;justify-content:center;z-index:99;padding:20px;}
.modal.on{display:flex;}
.modal .m-box{background:#fff;border-radius:16px;padding:16px;max-width:340px;text-align:center;}
.modal canvas{width:100%;border-radius:10px;}
.modal .m-tip{font-size:12px;color:var(--sub);margin:10px 0;}
.modal .m-close{color:var(--pri);font-size:14px;cursor:pointer;}
</style>
</head>
<body>
<div class="wrap">
<div class="top">
<div class="t">愈心解码</div>
<div class="s">一个生日,读懂你的身与心</div>
</div>
<div id="report"></div>
<div class="disc" id="disc" style="display:none">
📋 本页面内容为文化 + 心理测评 + 健康生活方式参考,<br>
体质部分参考国标《中医体质分类与判定》,不构成医疗建议。
</div>
</div>
<!-- 分享卡片弹层 -->
<div class="modal" id="shareModal">
<div class="m-box">
<canvas id="shareCanvas" width="540" height="720"></canvas>
<div class="m-tip">长按图片保存 · 分享给好友</div>
<div class="m-close" onclick="document.getElementById('shareModal').classList.remove('on')">关闭</div>
</div>
</div>
<script src="common.js"></script>
<script>
/* ---------- 工具 ---------- */
function qp(k){return new URLSearchParams(location.search).get(k);}
function strongestEl(p){return EO.reduce((a,b)=>p[b]>p[a]?b:a,EO[0]);}
function esc(s){return (s||'').replace(/</g,'&lt;');}
/* ---------- 精简 SVG 三角图(核心数字:I,J,K,L → M,N → O ---------- */
function miniPyramid(v){
const base=[v.I,v.J,v.K,v.L], mid=[v.M,v.N], apex=v.O;
const CW=42,CH=40,GY=8,W=CW*4+GY*3,cx=W/2;
function cell(x,y,n,hl){
return '<rect x="'+x+'" y="'+y+'" width="'+CW+'" height="'+CH+'" rx="8" fill="'+(hl?'#C8923A':'#fff8ef')+'" stroke="#e0c48a"/><text x="'+(x+CW/2)+'" y="'+(y+CH/2+5)+'" text-anchor="middle" font-size="17" font-weight="700" fill="'+(hl?'#fff':'#8a6d3b')+'">'+(n!=null?n:'')+'</text>';
}
var s='<svg width="'+W+'" height="'+(CH*3+GY*2)+'" xmlns="http://www.w3.org/2000/svg">';
s+=cell(cx-CW/2,0,apex,true);
s+=cell(cx-CW-GY/2,CH+GY,mid[0])+cell(cx+GY/2,CH+GY,mid[1]);
base.forEach(function(n,i){ s+=cell(i*(CW+GY),(CH+GY)*2,n); });
s+='</svg>';
return s;
}
/* ---------- 今日锦囊 ---------- */
var SEASON_EL={0:'水',1:'水',2:'木',3:'木',4:'木',5:'火',6:'火',7:'火',8:'土',9:'金',10:'金',11:'水'};
var YI_JI={
:{yi:'早睡养肝血 · 舒展拉伸 · 绿色蔬菜',ji:'久坐 · 生闷气 · 熬夜'},
:{yi:'午休15分钟 · 菊花/莲子 · 平心静气',ji:'暴晒 · 辛辣油腻 · 过度兴奋'},
:{yi:'规律三餐 · 健脾山药 · 饭后散步',ji:'思虑过度 · 生冷 · 暴饮暴食'},
:{yi:'滋润养肺 · 白色食物 · 深呼吸',ji:'干燥受凉 · 悲忧 · 剧烈耗气'},
:{yi:'早卧晚起 · 温补黑色食物 · 护腰腹',ji:'受寒 · 过劳 · 惊恐紧张'}
};
function todaySolar(){
var now=new Date(),m=now.getMonth()+1,d=now.getDate();
var cur=ST[0];
for(var i=0;i<ST.length;i++){ var t=ST[i];if(m>t.m||(m===t.m&&d>=t.d)) cur=t; }
return cur;
}
/* ---------- 主渲染 ---------- */
function render(){
var y=+qp('y'),m=+qp('m'),d=+qp('d');
var box=document.getElementById('report');
if(!y||!m||!d||y<1900||y>2100){
box.innerHTML='<div class="err">缺少有效生日参数,请从首页重新进入 🙏</div>';return;
}
document.getElementById('disc').style.display='block';
// === 数字引擎 ===
var v=calc(y,m,d);
var mainNum=v.O;
var person=NUM[mainNum]||{title:'',pos:'',neg:'',job:'',desc:''};
// === 养生引擎(无时辰,默认午时12点) ===
var bz=getBazi(new Date(y,m-1,d),12);
var p5=calc5E(bz);
var strong=strongestEl(p5);
var cst=getConst(p5);
var emo=getEmotion(strong);
// === 今日锦囊 ===
var st=todaySolar();
var sEl=SEASON_EL[new Date().getMonth()];
var yj=YI_JI[sEl];
var paid=localStorage.getItem('jiema_paid')==='1';
box.innerHTML=
'<!-- Part1 数字性格 -->'+
'<div class="card">'+
'<span class="tag tag-num">数字性格</span>'+
'<div class="hex">'+mainNum+'</div>'+
'<div class="p-title">'+mainNum+'号人 · '+esc(person.title)+'</div>'+
'<div class="p-oneline">'+esc((person.desc||'').split(/[。.]/)[0])+'</div>'+
'<div class="pyr">'+miniPyramid(v)+'</div>'+
'<div class="lock '+(paid?'unlocked':'')+'" id="lock-num">'+
'<div class="blur">'+
'<b>天赋优势:</b>'+esc(person.pos)+'<br>'+
'<b>人生课题:</b>'+esc(person.neg)+'<br>'+
'<b>适合方向:</b>'+esc(person.job)+'<br>'+
'<b>能量解读:</b>'+esc(person.desc)+
'</div>'+
'<div class="cover">'+
'<div class="lk-t">🔒 解锁完整性格解读</div>'+
'<div class="lk-d">天赋优势 · 人生课题 · 适合职业 · 12组联合码</div>'+
'<button class="unlock-btn" onclick="unlock()">¥39.9 解锁 →</button>'+
'</div>'+
'</div>'+
'</div>'+
'<!-- Part2 五行体质 -->'+
'<div class="card">'+
'<span class="tag tag-ys">五行体质</span>'+
'<div class="ys-type">'+esc(cst.primary)+'</div>'+
'<div class="ys-dir">养生重点:养'+esc(cst.strong)+' · 需护'+esc(cst.weak)+'</div>'+
'<div class="bars">'+
EO.map(function(e){return '<div class="bar-row"><span class="lab" style="color:'+EC[e]+'">'+e+'</span><div class="bar-track"><div class="bar-fill" style="width:'+p5[e]+'%;background:'+EC[e]+'"></div></div><span class="val">'+p5[e]+'%</span></div>';}).join('')+
'</div>'+
'<div class="p-oneline">情绪画像:'+esc((emo.strength||[]).join(' · '))+'</div>'+
'<div class="lock '+(paid?'unlocked':'')+'" id="lock-ys">'+
'<div class="blur">'+
'<b>体质特征:</b>'+esc(cst.body)+'<br>'+
'<b>调养要点:</b>'+esc(cst.tips)+'<br>'+
'<b>易感倾向:</b>'+esc(cst.diseases)+'<br>'+
'<b>季节风险:</b>'+esc(cst.seasonRisk)+'<br>'+
'<b>食疗方向:</b>'+esc(cst.foodTherapy)+'<br>'+
'<b>作息节律:</b>'+esc(cst.dailyRhythm)+
'</div>'+
'<div class="cover">'+
'<div class="lk-t">🔒 解锁五行体质深度分析</div>'+
'<div class="lk-d">脏腑画像 · 易感倾向 · 食疗 · 运动作息方案</div>'+
'<button class="unlock-btn" onclick="unlock()">¥39.9 解锁 →</button>'+
'</div>'+
'</div>'+
'</div>'+
'<!-- Part3 今日养生锦囊(免费) -->'+
'<div class="card jn">'+
'<span class="tag tag-ys">今日养生锦囊</span>'+
'<div class="st">当前节气:'+st.n+' · 时令 '+sEl+' 当令</div>'+
'<h4>今日调养建议</h4>'+
'<div class="row"><b>宜:</b>'+yj.yi+'</div>'+
'<div class="row"><b>忌:</b>'+yj.ji+'</div>'+
'</div>'+
'<!-- 深度入口 -->'+
'<div class="deep">'+
'<a class="d-num" href="shuzi.html?y='+y+'&m='+m+'&d='+d+'">完整数字报告 →</a>'+
'<a class="d-ys" href="yangsheng.html?y='+y+'&m='+m+'&d='+d+'&h=12">完整养生方案 →</a>'+
'</div>'+
'<!-- 契合度(免费给分数) -->'+
'<div class="card">'+
'<span class="tag tag-num">测测你和 TA 的契合度</span>'+
'<div class="mini-form">'+
'<input type="number" id="tY" placeholder="年"><span>年</span>'+
'<input type="number" id="tM" placeholder="月"><span>月</span>'+
'<input type="number" id="tD" placeholder="日"><span>日</span>'+
'<button onclick="matchTest('+y+','+m+','+d+')">测算</button>'+
'</div>'+
'<div id="matchOut"></div>'+
'</div>'+
'<!-- 分享 -->'+
'<div class="card">'+
'<span class="tag tag-num">分享你的身心密码</span>'+
'<button class="share-btn" onclick="genShare(\''+mainNum+'号人 · '+esc(person.title)+'\',\''+esc(cst.primary)+'\',\'养'+esc(cst.strong)+'\')">📱 生成分享卡片</button>'+
'</div>';
}
/* ---------- 付费墙 ---------- */
function unlock(){
if(confirm('【模拟支付】\n\n解锁完整深度报告 ¥39.9\n\n确认支付?')){
localStorage.setItem('jiema_paid','1');
document.querySelectorAll('.lock').forEach(function(el){el.classList.add('unlocked');});
}
}
/* ---------- 契合度(免费仅分数,深度引导付费/双人报告) ---------- */
function matchTest(y1,m1,d1){
var y=+document.getElementById('tY').value,
m=+document.getElementById('tM').value,
d=+document.getElementById('tD').value;
if(!y||!m||!d){alert('请输入 TA 的完整生日');return;}
var a=calc(y1,m1,d1).O, b=calc(y,m,d).O;
var diff=Math.abs(a-b);
var score=92-diff*6+((a+b)%3)*3;
score=Math.max(60,Math.min(98,score));
document.getElementById('matchOut').innerHTML=
'<div class="match-score">'+score+' 分</div>'+
'<div class="lock" style="margin-top:8px">'+
'<div class="blur">你们在沟通节奏、能量互补、相处课题上的详细解读……</div>'+
'<div class="cover">'+
'<div class="lk-t">🔒 查看完整契合度解读</div>'+
'<div class="lk-d">关系能量图 · 相处建议 · 沟通指南</div>'+
'<button class="unlock-btn" onclick="alert(\'双人契合度报告 ¥129(模拟)\')">¥129 解锁 →</button>'+
'</div>'+
'</div>';
}
/* ---------- 分享卡片(纯 canvas,无外部库) ---------- */
function genShare(numTitle,constType,ysKey){
var c=document.getElementById('shareCanvas'),g=c.getContext('2d');
var W=c.width,H=c.height;
var grd=g.createLinearGradient(0,0,0,H);
grd.addColorStop(0,'#FF9F80');grd.addColorStop(1,'#FFC8B5');
g.fillStyle=grd;g.fillRect(0,0,W,H);
g.fillStyle='#fff';g.textAlign='center';
g.font='bold 40px sans-serif';g.fillText('愈心解码',W/2,90);
g.font='20px sans-serif';g.fillText('一个生日,读懂身与心',W/2,128);
// 卡片
g.fillStyle='rgba(255,255,255,.95)';
roundRect(g,60,180,W-120,380,24);g.fill();
g.fillStyle='#8a6d3b';g.font='bold 46px sans-serif';
g.fillText(numTitle,W/2,290);
g.fillStyle='#5CB85C';g.font='bold 40px sans-serif';
g.fillText(constType,W/2,390);
g.fillStyle='#666';g.font='24px sans-serif';
g.fillText('养生重点:'+ysKey,W/2,460);
g.fillStyle='#E54D42';g.font='20px sans-serif';
g.fillText('▶ 扫码测测你的身心密码',W/2,530);
g.fillStyle='#fff';g.font='18px sans-serif';
g.fillText('愈心谷 · 愈见魔方,遇见自己',W/2,H-40);
document.getElementById('shareModal').classList.add('on');
}
function roundRect(g,x,y,w,h,r){
g.beginPath();g.moveTo(x+r,y);g.arcTo(x+w,y,x+w,y+h,r);
g.arcTo(x+w,y+h,x,y+h,r);g.arcTo(x,y+h,x,y,r);g.arcTo(x,y,x+w,y,r);g.closePath();
}
render();
</script>
</body>
</html>