643 lines
48 KiB
HTML
643 lines
48 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<!-- Google tag (gtag.js) -->
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-LVVXH3TL04"></script>
|
||
<script>
|
||
window.dataLayer = window.dataLayer || [];
|
||
function gtag(){dataLayer.push(arguments);}
|
||
gtag('js', new Date());
|
||
gtag('config', 'G-LVVXH3TL04');
|
||
</script>
|
||
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||
<title>愈心谷数字解构</title>
|
||
<style>
|
||
@font-face { font-family:'TriangleDigits'; src:url(data:font/woff2;base64,d09GMgABAAAAAAUAAA4AAAAACHwAAASsAAIZmQAAAAAAAAAAAAAAAAAAAAAAAAAAGhYbbBxIBmAANBEQCocshhEBNgIkAxoLGAAEIAWDIgcgG9QGKC4G7Ib6hm2MRajDYhGiDhrol2EQYF1VSXrYswJPkJb83g+eA7l2QeKDmZzBKY+S2Y6GNNvdREZSoL/sv5IIQxUu06If+FX4/z+X49/WsztrTAw5kRt099ubOm5NXEAFHuBcGvAGSjDAgLDn2bZk6fIVBBISV5n1GLNAADYApcVbCydXozYtkTdtbu8OvEOS0PEgPgIdEQfiY0OwiSCOBmAPsl4AYswwdCJQA1FoSBQqZkProGuMIFPAPhuoa8oSVYX8YAQSAZpDCmDZcIkm/ZAjI0LR3A1KzY56XmlDxUYMYNhtcBARzR51kKE7KkxKozJobFeXdNJlKY3czMCYMrUMa/83F2mmEHEHkFJnDXn9YBwBCSjAHYUA3NEIBjQ0BFDLHki2t3+KqVZYkbggAFQ26ho8RWcQ3tl/htql/UbHN70BAoXUbXpAnK4F+eoWL5vNxzpnKT0L1CrUld9zyZWVebLzdRVOGASMYohloBiiuziLHrm5uQI5VmbV7EqrcnVlszArq2tWV6c5C0+s7O5L1+3WqS7Q2737TCeTufqRH9o1O3uOtCpHMUc36sxupMOcNaesYEbpnGdwwlHmrs8VKBTmstgNaLvfBrx5PQ/wj1yzJd01+3LOm+/CzOY4zhHWtXYr5PbIyREYwJnHeFm4pXu2IcxByHzZVWJ3Er3bMQkX9snibM6Y1aTyc3rkXNUJPXpz8SR3SFeH84FFWYV9bzibJvHlL0bRde6KYc9cmiIKk5+FN+NThqtvc8aBGfnF6WzIqLk1ON06sNXy3bLFuIJ8DQT/QGhPY9JrsRk3RddPID33rzz9cLGnXZjvNNQR4659v7m7f0qW1qex/MqwciHDfdsqBnOLCispr6nWU0/DmAXZBdjkTA0M/4LXawb7VDhbjduWNPaWsM25jxyH1ENRUmejPPOk33dOKZ+v4BRLNZQeriawC/Nzxb0nr7/lPdzfGvGf3kgW0N6/tXYq1Si9RA/v58kV3DTY5DgaxwV1Uw5++lzxouLrgNYX82rdHtlWXSn61Di0UAxfhc2HeamcDnfrnVra3xecFNc61xtZhSxqUlFZFQ62rTQ+w3YS4S9Z4bNHHUB7y/fxoxt9pVAyqdOZ66cPKs7Oz8sYj5f2lIpvQPQfX3t4++1V80/rnFtRkIspHBjC5WXnpReTvuTiMVkJsZFp5SVhxARkdDKQhx19XV78vjqr1UAXlvCfnhUiz41CK/6P8dI6eIab2nlH17ap48+X3P/67iJUpWdlq6vNFAQABCB9dmU3fPxwgFPdb2YhMwAvzT++ByhOmZz+3/9vizVMBYAZOVthCvnfDK9OI6rfpSMQ1O8ljbVAg/Zm6S2UNDN4K6A9UySALjrjrgTjPKoUNdG7bdIswFkQgyCYswaJI28NikwKujXQYMBXOC8yEihiaSpGlAKsZbII4YSJENhVwgyBgJQEXSDaUphohpCxTCWZFJKhBY+AiHgRfBMjhobUGOI+OYREilhp4gmpjs63SFuCvHUricIo0nYoVERiSqyLCF+MnFdHwYlnbI0JjLBYonBsPGESCHYCTx5NXJ+7DhJpNTCDOrOPjGrLzlAAAAA) format('woff2'); }
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body { background:linear-gradient(160deg,#FFD1C7,#FFC8B5); font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif; display:flex; flex-direction:column; justify-content:center; align-items:center; min-height:100vh; color:#333; padding:10px 10px 20px; -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; }
|
||
.container { position:relative; width:600px; max-width:95%; padding:12px 40px 40px; display:flex; flex-direction:column; align-items:center; background:#fff; border-radius:18px; box-shadow:0 8px 30px rgba(0,0,0,.08); margin-bottom:30px; }
|
||
.input-row { display:flex; gap:5px; align-items:center; margin-bottom:24px; font-family:sans-serif; }
|
||
.input-row input { width:56px; padding:6px 4px; border:1px solid #d9ccb6; border-radius:3px; font-size:14px; text-align:center; color:#6b5b4e; background:#fff; outline:none; }
|
||
.input-row input:focus { border-color:#a89580; }
|
||
.input-row .lbl { font-size:0.75em; color:#9b8a78; }
|
||
.btn-gen { padding:6px 12px; background:#8b7a68; color:#fff; border:none; border-radius:3px; font-size:0.75em; cursor:pointer; margin-left:2px; }
|
||
.btn-gen:active { opacity:0.8; }
|
||
.top-numbers { display:flex; flex-direction:column; align-items:center; margin-bottom:-20px; z-index:2; font-family:'TriangleDigits','Georgia','Times New Roman',serif; }
|
||
.top-numbers .num-top { font-size:2.2rem; font-weight:normal; }
|
||
.top-numbers .num-mid-row { display:flex; gap:60px; font-size:2.2rem; font-weight:normal; }
|
||
.triangle-wrapper { position:relative; width:300px; height:260px; margin:20px 0; display:flex; justify-content:center; align-items:center; overflow:visible; }
|
||
.triangle-svg { position:absolute; top:0; left:0; width:100%; height:100%; z-index:0; }
|
||
.triangle-path { fill:#f2ebdd; stroke:#d9ccb6; stroke-width:2; }
|
||
.divider-line { stroke:#d9ccb6; stroke-width:2; }
|
||
.inner-number { position:absolute; z-index:1; font-size:2.2rem; font-weight:bold; cursor:pointer; font-family:'TriangleDigits','Georgia','Times New Roman',serif; color:#5a4636; }
|
||
.red-num { color:#c47a78; top:25%; }
|
||
.mid-left { top:55%; left:30%; } .mid-right { top:55%; right:30%; }
|
||
.bot-1 { bottom:10%; left:18%; } .bot-2 { bottom:10%; left:38%; }
|
||
.bot-3 { bottom:10%; right:38%; } .bot-4 { bottom:10%; right:18%; }
|
||
.side-decorations { position:absolute; width:100%; height:100%; top:0; left:0; font-family:'TriangleDigits','Georgia','Times New Roman',serif; }
|
||
.side-num { position:absolute; font-size:2.2rem; opacity:0.65; cursor:pointer; font-family:'TriangleDigits','Georgia','Times New Roman',serif; font-weight:normal; color:#8b7e6e; }
|
||
.left-group { top:30%; left:-40px; text-align:right; line-height:1.5; }
|
||
.right-group { top:30%; right:-40px; text-align:left; line-height:1.5; }
|
||
.footer-date { margin-top:0; display:flex; gap:40px; font-size:1.8rem; letter-spacing:2px; color:#5a4636; font-family:'TriangleDigits','Georgia','Times New Roman',serif; }
|
||
.sections { width:100%; max-width:360px; margin-top:24px; font-family:sans-serif; font-size:1em; color:#6b5b4e; }
|
||
.divider { border:none; border-top:1px solid #e0d5c4; margin:12px 0; opacity:0.6; }
|
||
.codes .r { display:flex; justify-content:space-between; border-bottom:1px dotted rgba(168,144,112,0.15); padding:2px 4px; }
|
||
.codes .k { color:#9b8a78; } .codes .v { color:#6b5b4e; }
|
||
.joint-age { font-size:0.9em; color:#a89070; font-weight:600; text-align:center; margin:8px 0 2px; border-bottom:1px solid rgba(168,144,112,0.2); padding-bottom:2px; }
|
||
.joint-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:2px 10px; }
|
||
.joint-grid .jc { font-weight:700; color:#5a4636; } .joint-grid .jm { color:#9b8a78; }
|
||
.tooltip { position:fixed; padding:5px 10px; background:#6b5b4e; color:#fff; border-radius:4px; font-size:0.7em; pointer-events:none; opacity:0; transition:opacity 0.12s; z-index:999; max-width:200px; line-height:1.5; font-family:sans-serif; }
|
||
.tooltip.on { opacity:1; }
|
||
.footer { text-align:center; font-size:0.6em; color:#9b8a78; margin-top:10px; }
|
||
/* 付费墙 */
|
||
.shuzi-lock { position:relative; border-radius:10px; overflow:hidden; border:1px solid #f2e6d0; }
|
||
.shuzi-lock > .blur { filter:blur(5px); pointer-events:none; user-select:none; }
|
||
.shuzi-lock .cover { position:absolute; inset:0; z-index:2; background:linear-gradient(180deg, rgba(250,247,242,.5), rgba(250,247,242,.95)); display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding:20px; }
|
||
.shuzi-lock .cover .lk-t { font-size:1.05em; font-weight:700; color:#c47a78; }
|
||
.shuzi-lock .cover .lk-d { font-size:0.75em; color:#9b8a78; margin:8px 0 14px; }
|
||
.shuzi-lock .cover .lk-btn { background:#c47a78; color:#fff; border:none; padding:10px 28px; border-radius:20px; font-size:0.85em; font-weight:600; cursor:pointer; }
|
||
.shuzi-lock.unlocked .cover { display:none; }
|
||
.shuzi-lock.unlocked .blur { filter:none; pointer-events:auto; user-select:auto; }
|
||
.scene-3d { position:relative; display:flex; justify-content:center; margin:8px 0; cursor:grab; }
|
||
.scene-3d:active { cursor:grabbing; }
|
||
.scene-3d canvas { display:block; touch-action:none; }
|
||
.scene-hint { position:absolute; bottom:2px; left:50%; transform:translateX(-50%); font-size:0.55em; color:#b8a898; pointer-events:none; opacity:0.7; }
|
||
.freq-label { text-align:center; font-size:0.7em; color:#6b5b4e; margin-top:2px; line-height:1.8; }
|
||
.tabs-nav { display:flex; flex-wrap:wrap; gap:4px; margin-bottom:18px; justify-content:center; padding:0 4px; }
|
||
.tab-btn { padding:5px 10px; border:1px solid #d9ccb6; border-radius:3px; background:#fff; color:#9b8a78; font-size:0.7em; cursor:pointer; font-family:sans-serif; transition:all 0.15s; white-space:nowrap; }
|
||
.tab-btn:hover { border-color:#c47a78; color:#c47a78; }
|
||
.tab-btn.active { background:#c47a78; color:#fff; border-color:#c47a78; }
|
||
.tab-panel { display:none; }
|
||
.tab-panel.active { display:block; }
|
||
.tab-panel .module-title { font-size:0.82em; font-weight:600; color:#5a4636; text-align:center; margin-bottom:8px; }
|
||
.tab-panel .module-desc { font-size:0.68em; color:#9b8a78; text-align:center; margin-bottom:10px; line-height:1.6; }
|
||
.tab-panel .module-section { font-size:0.72em; color:#6b5b4e; line-height:1.75; padding:0 4px; margin-bottom:10px; }
|
||
.tab-panel .module-section b { color:#5a4636; }
|
||
.bagua-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:6px; text-align:center; margin:8px 0; }
|
||
.bagua-cell { padding:6px 4px; border-radius:4px; font-size:0.68em; line-height:1.5; }
|
||
@media (max-width:600px) {
|
||
.triangle-wrapper { width:220px; height:190px; margin:10px auto 0; }
|
||
.triangle-wrapper svg { width:220px; height:190px; }
|
||
.inner-number { font-size:1.6rem; }
|
||
.red-num { top:22%; }
|
||
.mid-left { top:52%; left:28%; } .mid-right { top:52%; right:28%; }
|
||
.bot-1 { bottom:10%; left:14%; } .bot-2 { bottom:10%; left:35%; }
|
||
.bot-3 { bottom:10%; right:35%; } .bot-4 { bottom:10%; right:14%; }
|
||
.side-num { font-size:1.6rem; }
|
||
.left-group { left:-32px; top:26%; } .right-group { right:-32px; top:26%; }
|
||
.top-numbers .num-top { font-size:1.6rem; }
|
||
.top-numbers .num-mid-row { font-size:1.6rem; gap:40px; }
|
||
.footer-date { gap:14px; font-size:1.2rem; letter-spacing:0; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div style="text-align:center;padding:20px 0 4px;">
|
||
<img src="logo.png" alt="愈心谷" style="height:36px">
|
||
</div>
|
||
<div style="max-width:600px;margin:0 auto;padding:4px 14px;">
|
||
<a href="jiema.html" style="color:rgba(255,255,255,0.8);text-decoration:none;font-size:13px;">← 返回愈心解码</a>
|
||
</div>
|
||
<div class="container">
|
||
<div style="text-align:center;margin-bottom:10px;">
|
||
<h1 style="font-size:1.4em;font-weight:800;letter-spacing:0.15em;color:#C8923A;margin:0 0 6px;">愈心谷数字解构</h1>
|
||
<div style="font-size:0.65em;color:#999;letter-spacing:0.12em;margin-top:2px;">✦ 输入公历出生年月日 ✦</div>
|
||
</div>
|
||
<div class="input-row">
|
||
<input type="number" id="inY" value="1986"><span class="lbl">年</span>
|
||
<input type="number" id="inM" value="2"><span class="lbl">月</span>
|
||
<input type="number" id="inD" value="17"><span class="lbl">日</span>
|
||
<button class="btn-gen" id="goBtn">生成</button>
|
||
</div>
|
||
<div class="top-numbers">
|
||
<div class="num-top" id="valR">3</div>
|
||
<div class="num-mid-row"><span id="valQ">4</span><span id="valP">8</span></div>
|
||
</div>
|
||
<div class="triangle-wrapper">
|
||
<svg class="triangle-svg" viewBox="0 0 300 260">
|
||
<polygon points="150,10 290,250 10,250" class="triangle-path"/>
|
||
<line x1="85" y1="130" x2="215" y2="130" class="divider-line"/>
|
||
<line x1="55" y1="190" x2="245" y2="190" class="divider-line"/>
|
||
<line x1="150" y1="130" x2="150" y2="250" class="divider-line"/>
|
||
</svg>
|
||
<div class="inner-number red-num" id="valO" style="left:50%;transform:translateX(-50%)">7</div>
|
||
<div class="inner-number mid-left" id="valM">1</div>
|
||
<div class="inner-number mid-right" id="valN">6</div>
|
||
<div class="inner-number bot-1" id="valI">8</div>
|
||
<div class="inner-number bot-2" id="valJ">2</div>
|
||
<div class="inner-number bot-3" id="valK">1</div>
|
||
<div class="inner-number bot-4" id="valL">5</div>
|
||
<div class="side-decorations">
|
||
<div class="side-num left-group" style="display:flex;flex-direction:column;align-items:center;">
|
||
<div id="valU">3</div>
|
||
<div style="display:flex;gap:8px"><span id="valT">9</span><span id="valS">3</span></div>
|
||
</div>
|
||
<div class="side-num right-group" style="display:flex;flex-direction:column;align-items:center;">
|
||
<div id="valX">9</div>
|
||
<div style="display:flex;gap:8px"><span id="valV">7</span><span id="valW">2</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="footer-date">
|
||
<span id="dateD">17</span><span id="dateM">02</span><span id="dateY">1986</span>
|
||
</div>
|
||
<div class="sections">
|
||
<div class="tabs-nav">
|
||
<button class="tab-btn active" data-tab="shuzi">✨ 数字报告</button>
|
||
<button class="tab-btn" data-tab="meihua">🪷 梅花易数</button>
|
||
<button class="tab-btn" data-tab="xiaoliuren">🔮 小六壬</button>
|
||
<button class="tab-btn" data-tab="daliuren">🌌 大六壬</button>
|
||
<button class="tab-btn" data-tab="qimen">🏯 奇门遁甲</button>
|
||
<button class="tab-btn" data-tab="xingzuo">⭐ 星座</button>
|
||
<button class="tab-btn" data-tab="wuxing">☯️ 五行八卦</button>
|
||
</div>
|
||
<div class="tab-panel active" id="shuzi-panel">
|
||
<div class="missing" id="missingBlock"></div>
|
||
<div class="missing-short" id="missingMsg"></div>
|
||
<hr class="divider">
|
||
<div class="codes" id="codesBlock"></div>
|
||
<div class="joint" id="jointBlock"></div>
|
||
</div>
|
||
<div class="tab-panel" id="meihua-panel"></div>
|
||
<div class="tab-panel" id="xiaoliuren-panel"></div>
|
||
<div class="tab-panel" id="daliuren-panel"></div>
|
||
<div class="tab-panel" id="qimen-panel"></div>
|
||
<div class="tab-panel" id="xingzuo-panel"></div>
|
||
<div class="tab-panel" id="wuxing-panel"></div>
|
||
<div class="footer">内在探索 · 心灵成长</div>
|
||
</div>
|
||
</div>
|
||
<div class="tooltip" id="tip"></div>
|
||
|
||
<script src="common.js"></script>
|
||
<script>
|
||
const NUM_CLR={
|
||
1:{top:[232,160,160],front:[196,122,120],right:[168,96,96]},
|
||
2:{top:[240,200,160],front:[232,168,124],right:[208,144,96]},
|
||
3:{top:[238,208,128],front:[224,184,88],right:[200,152,64]},
|
||
4:{top:[160,216,112],front:[112,173,71],right:[88,136,48]},
|
||
5:{top:[144,200,240],front:[91,155,213],right:[64,120,176]},
|
||
6:{top:[240,168,176],front:[212,135,142],right:[176,104,112]},
|
||
7:{top:[184,168,216],front:[139,122,181],right:[104,88,152]},
|
||
8:{top:[160,144,128],front:[107,91,78],right:[80,64,48]},
|
||
9:{top:[244,236,224],front:[232,220,200],right:[208,192,168]},
|
||
};
|
||
|
||
// ===== Dimetric 投影 + Z 轴旋转 —— 底座天然水平 =====
|
||
let rotZ = -0.55; // Z 轴旋转角(弧度)
|
||
let dragActive=false, dragPX=0;
|
||
let currentFreq={};
|
||
|
||
function proj(x,y,z,rz) {
|
||
// Z 轴旋转 + 45° dimetric 投影
|
||
const cr=Math.cos(rz), sr=Math.sin(rz);
|
||
const xr=x*cr-y*sr, yr=x*sr+y*cr;
|
||
return { sx:yr-xr, sy:-(xr+yr)+z*0.7, depth:-(xr+yr)+z };
|
||
}
|
||
|
||
function faceVis(face, rz) {
|
||
const cr=Math.cos(rz), sr=Math.sin(rz);
|
||
switch(face) {
|
||
case 'right': return cr+sr>0;
|
||
case 'left': return cr+sr<0;
|
||
case 'front': return cr-sr>0;
|
||
case 'back': return cr-sr<0;
|
||
case 'top': return true;
|
||
case 'bottom':return false;
|
||
}
|
||
}
|
||
|
||
function faceCorns(cx,cy,cz,hs,face) {
|
||
const h=hs;
|
||
switch(face) {
|
||
case 'top': return [[cx-h,cy-h,cz+h],[cx+h,cy-h,cz+h],[cx+h,cy+h,cz+h],[cx-h,cy+h,cz+h]];
|
||
case 'bottom': return [[cx-h,cy-h,cz-h],[cx+h,cy-h,cz-h],[cx+h,cy+h,cz-h],[cx-h,cy+h,cz-h]];
|
||
case 'front': return [[cx-h,cy+h,cz-h],[cx+h,cy+h,cz-h],[cx+h,cy+h,cz+h],[cx-h,cy+h,cz+h]];
|
||
case 'back': return [[cx-h,cy-h,cz-h],[cx+h,cy-h,cz-h],[cx+h,cy-h,cz+h],[cx-h,cy-h,cz+h]];
|
||
case 'right': return [[cx+h,cy-h,cz-h],[cx+h,cy+h,cz-h],[cx+h,cy+h,cz+h],[cx+h,cy-h,cz+h]];
|
||
case 'left': return [[cx-h,cy-h,cz-h],[cx-h,cy+h,cz-h],[cx-h,cy+h,cz+h],[cx-h,cy-h,cz+h]];
|
||
}
|
||
}
|
||
|
||
function renderScene(canvas, freq, rz) {
|
||
const dpr=window.devicePixelRatio||1;
|
||
const mob=window.innerWidth<=600;
|
||
const CS=mob?20:26;
|
||
const STEP=CS*2+(mob?2:4);
|
||
const DH=CS*2+(mob?1:2);
|
||
const PAD=mob?30:40;
|
||
|
||
const cols={};
|
||
for(let n=1;n<=9;n++){
|
||
const row=2-Math.floor((n-1)/3), col=(n-1)%3;
|
||
cols[n]={wx:(col-1)*STEP,wy:(row-1)*STEP};
|
||
}
|
||
|
||
// 计算包围盒
|
||
let mnX=Infinity,mxX=-Infinity,mnY=Infinity,mxY=-Infinity;
|
||
for(let n=1;n<=9;n++){
|
||
const {wx,wy}=cols[n];
|
||
const layers=Math.max(1,freq[n]||1);
|
||
for(let l=0;l<layers;l++){
|
||
const wz=l*DH;
|
||
const cs=[[wx-CS,wy-CS,wz],[wx+CS,wy-CS,wz],[wx+CS,wy+CS,wz],[wx-CS,wy+CS,wz],
|
||
[wx-CS,wy-CS,wz+CS*2],[wx+CS,wy-CS,wz+CS*2],[wx+CS,wy+CS,wz+CS*2],[wx-CS,wy+CS,wz+CS*2]];
|
||
cs.forEach(c=>{const p=proj(c[0],c[1],c[2],rz);mnX=Math.min(mnX,p.sx);mxX=Math.max(mxX,p.sx);mnY=Math.min(mnY,p.sy);mxY=Math.max(mxY,p.sy);});
|
||
}
|
||
}
|
||
|
||
// 底座平台包围盒
|
||
const bw=STEP*2+CS*2+16, bz=-CS-3;
|
||
[[-bw,-bw,bz],[bw,-bw,bz],[bw,bw,bz],[-bw,bw,bz]].forEach(c=>{
|
||
const p=proj(c[0],c[1],c[2],rz);mnX=Math.min(mnX,p.sx);mxX=Math.max(mxX,p.sx);mnY=Math.min(mnY,p.sy);mxY=Math.max(mxY,p.sy);
|
||
});
|
||
|
||
const viewW=Math.max(mxX-mnX+PAD*2,mob?300:400);
|
||
const viewH=Math.max(mxY-mnY+PAD*2,mob?320:420);
|
||
canvas.width=Math.ceil(viewW*dpr);canvas.height=Math.ceil(viewH*dpr);
|
||
canvas.style.width=Math.ceil(viewW)+'px';canvas.style.height=Math.ceil(viewH)+'px';
|
||
const ctx=canvas.getContext('2d');ctx.scale(dpr,dpr);ctx.clearRect(0,0,viewW,viewH);
|
||
|
||
const centerX=(mxX+mnX)/2, ox=viewW/2-centerX, oy=viewH-PAD-mxY;
|
||
const faces=[];
|
||
const AF=['top','bottom','front','back','right','left'];
|
||
|
||
// 底座平台(厚块)
|
||
(()=>{
|
||
const bt=mob?4:5, bzTop=-CS-2, bzBot=bzTop-bt;
|
||
const bclr=[170,155,135];
|
||
[
|
||
{t:'top', c:[[-bw,-bw,bzTop],[bw,-bw,bzTop],[bw,bw,bzTop],[-bw,bw,bzTop]],clr:bclr},
|
||
{t:'front', c:[[-bw,bw,bzBot],[bw,bw,bzBot],[bw,bw,bzTop],[-bw,bw,bzTop]],clr:bclr.map(v=>Math.floor(v*0.85))},
|
||
{t:'right', c:[[bw,-bw,bzBot],[bw,bw,bzBot],[bw,bw,bzTop],[bw,-bw,bzTop]],clr:bclr.map(v=>Math.floor(v*0.7))},
|
||
].forEach(fb=>{
|
||
const pts=fb.c.map(c=>proj(c[0],c[1],c[2],rz));
|
||
const avgZ=pts.reduce((s,p)=>s+p.depth,0)/4;
|
||
const projPts=pts.map(p=>[ox+p.sx,oy-p.sy]);
|
||
faces.push({z:avgZ,proj:projPts,color:fb.clr,isTop:fb.t==='top',num:0});
|
||
});
|
||
})();
|
||
|
||
// 方块面
|
||
for(let n=1;n<=9;n++){
|
||
const {wx,wy}=cols[n];
|
||
const layers=Math.max(1,freq[n]||1);
|
||
const clr=NUM_CLR[n];
|
||
const fc={top:clr.top,bottom:clr.top,front:clr.front,back:clr.front,right:clr.right,left:clr.right};
|
||
for(let l=0;l<layers;l++){
|
||
const wz=l*DH;
|
||
for(const face of AF){
|
||
if(!faceVis(face,rz))continue;
|
||
const crns=faceCorns(wx,wy,wz,CS,face);
|
||
const pts=crns.map(c=>proj(c[0],c[1],c[2],rz));
|
||
const avgZ=pts.reduce((s,p)=>s+p.depth,0)/4;
|
||
const projPts=pts.map(p=>[ox+p.sx,oy-p.sy]);
|
||
const cnt=proj(wx,wy,wz+CS,rz);
|
||
faces.push({z:avgZ,proj:projPts,color:fc[face],isTop:face==='top',num:n,cx:ox+cnt.sx,cy:oy-cnt.sy});
|
||
}
|
||
}
|
||
}
|
||
|
||
faces.sort((a,b)=>a.z-b.z);
|
||
const alpha=0.82;
|
||
|
||
for(const f of faces){
|
||
const [r,g,b]=f.color;
|
||
ctx.fillStyle=`rgba(${r},${g},${b},${alpha})`;
|
||
ctx.beginPath();ctx.moveTo(f.proj[0][0],f.proj[0][1]);
|
||
for(let i=1;i<4;i++)ctx.lineTo(f.proj[i][0],f.proj[i][1]);
|
||
ctx.closePath();ctx.fill();
|
||
if(f.isTop&&f.num){
|
||
ctx.fillStyle='rgba(255,255,255,0.92)';
|
||
const fs=mob?11:14;ctx.font=`bold ${fs}px Georgia,"Noto Serif SC",serif`;
|
||
ctx.textAlign='center';ctx.textBaseline='middle';
|
||
ctx.shadowColor='rgba(0,0,0,0.25)';ctx.shadowBlur=2;
|
||
ctx.fillText(f.num,f.cx,f.cy);
|
||
ctx.shadowColor='transparent';ctx.shadowBlur=0;
|
||
}
|
||
}
|
||
|
||
// 底部 2D 横条
|
||
(()=>{
|
||
const bh=mob?18:22,by=viewH-bh;
|
||
const grad=ctx.createLinearGradient(0,by,0,viewH);
|
||
grad.addColorStop(0,'rgba(180,165,145,0.5)');
|
||
grad.addColorStop(0.3,'rgba(160,145,125,0.35)');
|
||
grad.addColorStop(1,'rgba(140,125,105,0.1)');
|
||
ctx.fillStyle=grad;ctx.fillRect(0,by,viewW,bh);
|
||
ctx.strokeStyle='rgba(140,125,105,0.45)';ctx.lineWidth=1;
|
||
ctx.beginPath();ctx.moveTo(0,by);ctx.lineTo(viewW,by);ctx.stroke();
|
||
})();
|
||
}
|
||
|
||
function drawScene(){
|
||
const canvas=document.querySelector('#scene3d canvas');
|
||
if(!canvas)return;
|
||
renderScene(canvas,currentFreq,rotZ);
|
||
}
|
||
|
||
function setupRotation(){
|
||
const el=document.querySelector('#scene3d');if(!el)return;
|
||
function getX(e){return e.touches&&e.touches.length?e.touches[0].clientX:e.clientX}
|
||
function onStart(e){dragActive=true;dragPX=getX(e);e.preventDefault()}
|
||
function onMove(e){
|
||
if(!dragActive)return;
|
||
const cx=getX(e),dx=cx-dragPX;dragPX=cx;
|
||
rotZ+=dx*0.008;drawScene();e.preventDefault();
|
||
}
|
||
function onEnd(){dragActive=false}
|
||
el.addEventListener('mousedown',onStart);
|
||
el.addEventListener('touchstart',onStart,{passive:false});
|
||
window.addEventListener('mousemove',onMove);
|
||
window.addEventListener('touchmove',onMove,{passive:false});
|
||
window.addEventListener('mouseup',onEnd);
|
||
window.addEventListener('touchend',onEnd);
|
||
}
|
||
|
||
// ===== 解读模块生成器 =====
|
||
|
||
const GUA64=['','乾为天','天泽履','天火同人','天雷无妄','天风姤','天水讼','天山遁','天地否','泽天夬','兑为泽','泽火革','泽雷随','泽风大过','泽水困','泽山咸','泽地萃','火天大有','火泽睽','离为火','火雷噬嗑','火风鼎','火水未济','火山旅','火地晋','雷天大壮','雷泽归妹','雷火丰','震为雷','雷风恒','雷水解','雷山小过','雷地豫','风天小畜','风泽中孚','风火家人','风雷益','巽为风','风水涣','风山渐','风地观','水天需','水泽节','水火既济','水雷屯','水风井','坎为水','水山蹇','水地比','山天大畜','山泽损','山火贲','山雷颐','山风蛊','山水蒙','艮为山','山地剥','地天泰','地泽临','地火明夷','地雷复','地风升','地水师','地山谦','坤为地'];
|
||
const GUA64_DESC={'乾为天':'刚健中正,纯阳之卦。运势旺盛,宜主动进取。','坤为地':'柔顺包容,厚德载物。耐心守成,终得善果。','水雷屯':'万事起头难。创业维艰,宜稳扎稳打。','山水蒙':'蒙昧初开。宜虚心求教,不可自作聪明。','水天需':'等待时机。耐心守候,时机未到不可强求。','天水讼':'争执诉讼之象。退一步海阔天空。','地水师':'统兵出征。纪律严明,以正制邪。','水地比':'亲附和合。广结善缘,必得助力。','地天泰':'天地交泰。万事亨通,上下和合。','天地否':'闭塞不通。宜隐忍守正,静待时机。','天火同人':'志同道合。同心协力可成大事。','火天大有':'丰收大有。顺天应时,财源广进。','雷天大壮':'强盛壮大。力量充沛但切忌恃强凌弱。','火地晋':'旭日东升。逐步晋升,光明在前。','地火明夷':'光明受损。韬光养晦,等待天明。','风火家人':'家庭和乐。修身齐家,家和万事兴。','火泽睽':'乖离不合。求同存异,小事可成。','水山蹇':'艰难险阻。退守求稳,不可强闯。','雷水解':'困难解除。柳暗花明,危机化解。','山泽损':'损下益上。有舍有得,吃亏是福。','风雷益':'增益有利。抓住机遇,积极作为。','泽天夬':'决断果断。当断则断,不受其乱。','天风姤':'不期而遇。随缘而处,不可强求。','泽地萃':'聚集荟萃。人气旺盛,利于合作。','地风升':'步步高升。循序渐进,终达目标。','泽水困':'困顿之象。坚守正道,终可脱困。','水风井':'修德养民。滋养根本,源远流长。','泽火革':'变革之时。顺势而变,除旧布新。','火风鼎':'鼎新革故。稳固根基,创新求变。','震为雷':'震动警醒。临危不乱,化险为夷。','艮为山':'知止不殆。适可而止,安守本分。','风山渐':'循序渐进。按部就班,水到渠成。','雷泽归妹':'婚嫁之象。以诚相待,终成眷属。','雷火丰':'丰盛之时。月满则亏,知足常乐。','火山旅':'行旅之象。随遇而安,莫问归期。','巽为风':'柔顺渗透。以柔克刚,润物无声。','兑为泽':'喜悦沟通。以和为贵,广结善缘。','风水涣':'涣散离散。聚拢人心,凝聚力量。','水泽节':'节制有度。合理规划,量力而行。','风泽中孚':'诚信感召。以诚待人,金石为开。','雷山小过':'小有过失。宜下不宜上,宜小不宜大。','水火既济':'事已成就。居安思危,防微杜渐。','火水未济':'未竟之业。持之以恒,终将成功。','地山谦':'谦逊受益。虚怀若谷,众望所归。','雷地豫':'安乐愉悦。居安思危,不可懈怠。','泽雷随':'随顺时势。灵活应变,顺势而为。','山风蛊':'蛊坏整治。拨乱反正,振弊起衰。','地泽临':'居高临下。亲近下属,恩威并施。','风地观':'观览体察。审时度势,明察秋毫。','火雷噬嗑':'咬合刑罚。明断是非,刚正不阿。','山火贲':'文饰美化。返璞归真,内在为重。','山地剥':'剥落凋零。守正待时,顺势而为。','地雷复':'一阳来复。否极泰来,新生在望。','天雷无妄':'真实无妄。顺其自然,不妄作为。','山天大畜':'蓄积力量。厚积薄发,大器晚成。','山雷颐':'颐养之道。养生养德,自求口实。','泽风大过':'过度之象。刚柔相济,中庸为贵。','坎为水':'重重险难。坚守诚信,终可出险。','离为火':'光明依附。柔顺中正,照亮四方。'};
|
||
|
||
function meihuaHTML(y,m,d){
|
||
const dz=['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'];
|
||
const dzNum={子:1,丑:2,寅:3,卯:4,辰:5,巳:6,午:7,未:8,申:9,酉:10,戌:11,亥:12};
|
||
const tg=['甲','乙','丙','丁','戊','己','庚','辛','壬','癸'];
|
||
const guaName=['','乾 ☰','兑 ☱','离 ☲','震 ☳','巽 ☴','坎 ☵','艮 ☶','坤 ☷'];
|
||
const guaEle=['','金','金','火','木','木','水','土','土'];
|
||
const ndz=dz[(y-4)%12],ntg=tg[(y-4)%10],nDZ=dzNum[ndz];
|
||
const upNum=nDZ%8||8,downNum=(m+d)%8||8,dongY=(nDZ+m+d)%6||6;
|
||
const benGuaIdx=(upNum-1)*8+downNum;
|
||
const benName=GUA64[benGuaIdx]||(guaName[upNum]+'+'+guaName[downNum]);
|
||
const varUp=dongY<=3?upNum:((upNum^5)||8),varDown=dongY<=3?((downNum^5)||8):downNum;
|
||
const varIdx=(varUp-1)*8+varDown;
|
||
const varName=GUA64[varIdx]||(guaName[varUp]+'+'+guaName[varDown]);
|
||
const desc=GUA64_DESC[benName]||'卦象已显,静心体悟其中玄机。';
|
||
const dongYaoNames=['初爻','二爻','三爻','四爻','五爻','上爻'];
|
||
const ue=guaEle[upNum],de=guaEle[downNum];
|
||
const shengKe={'金':'木','木':'土','土':'水','水':'火','火':'金'};
|
||
let tiYong;
|
||
if(upNum===downNum)tiYong='体用比和,万事顺遂';
|
||
else if(shengKe[ue]===de)tiYong='体克用,事可成但需费心力';
|
||
else if(shengKe[de]===ue)tiYong='用克体,宜守不宜攻,等待时机';
|
||
else tiYong='体用相生,遇贵人之象,万事可成';
|
||
return `<div class="module-title">✦ ${benName} ✦</div>
|
||
<div class="module-desc">${ntg}${ndz}年 · 上卦${guaName[upNum]} 下卦${guaName[downNum]} · 动在${dongYaoNames[dongY-1]}</div>
|
||
<div class="module-section"><b>▸ 本卦:${benName}</b><br><span style="color:#9b8a78">${desc}</span><br><br><b>▸ 变卦:${varName}</b><br><span style="color:#9b8a78">${GUA64_DESC[varName]||'变动已生,观其变化而知吉凶。'}</span><br><br><b>▸ 体用生克</b><br>上卦属${ue}·下卦属${de} — ${tiYong}</div>`;
|
||
}
|
||
|
||
const XLR_NAMES=['','大安','留连','速喜','赤口','小吉','空亡'];
|
||
const XLR_DESC={'大安':'大吉。光明正大,平安顺遂。求财向东南,凡事安稳。','留连':'凶。事难成就,去者未归。宜静不宜动,急则生变。','速喜':'大吉。喜事将至,向南吉利,行人有信至。','赤口':'凶。口舌是非,宜守不宜攻,失物难寻。','小吉':'大吉。好事将近,路遇贵人,向西南吉利。','空亡':'大凶。谋事落空,宜静待时机,强求反遭祸。'};
|
||
|
||
function xiaoLiuRenHTML(y,m,d){
|
||
const mo=m>12?m-12:m,shi=7;let pos=1;
|
||
for(let i=1;i<mo;i++)pos=pos%6+1;
|
||
for(let i=1;i<d;i++)pos=pos%6+1;
|
||
for(let i=1;i<shi;i++)pos=pos%6+1;
|
||
const name=XLR_NAMES[pos],isGood=name==='大安'||name==='速喜'||name==='小吉';
|
||
return `<div class="module-title">✦ 小六壬 掌诀:${name} ✦</div>
|
||
<div class="module-desc">月上起日,日上起时(午时)→ 最终落位</div>
|
||
<div class="module-section"><span style="font-size:1.6em;font-weight:700;color:${isGood?'#70ad47':'#c47a78'}">${name}</span><br><span style="color:#9b8a78">${XLR_DESC[name]}</span><br><br><b>▸ 六掌速查</b><br><span style="color:#70ad47">大安</span> · <span style="color:#c47a78">留连</span> · <span style="color:#70ad47">速喜</span> · <span style="color:#c47a78">赤口</span> · <span style="color:#70ad47">小吉</span> · <span style="color:#c47a78">空亡</span></div>`;
|
||
}
|
||
|
||
function daLiuRenHTML(y,m,d){
|
||
const dz=['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'];
|
||
const ydz=dz[(y-4)%12],yueJiangMap={1:'子',2:'亥',3:'戌',4:'酉',5:'申',6:'未',7:'午',8:'巳',9:'辰',10:'卯',11:'寅',12:'丑'};
|
||
return `<div class="module-title">✦ 大六壬 课式概要 ✦</div>
|
||
<div class="module-desc">${y}年(${ydz}年)· ${m}月 月将${yueJiangMap[m]||'午'} · 占时午</div>
|
||
<div class="module-section"><b>▸ 简介</b><br><span style="color:#9b8a78">六壬为三式之首,以月将加占时起天地盘,排四课发三传断吉凶。演算极精(12天将+12神煞+遁干),此处展示基础课式。</span><br><br><b>▸ 天地盘</b><br><span style="color:#9b8a78">地盘:子丑寅卯辰巳午未申酉戌亥(固定)<br>天盘:月将加临占时之上,顺布十二辰</span><br><br><b>▸ 四课</b><br><span style="color:#9b8a78">第一课日干阳神 · 第二课日干阴神 · 第三课日支阳神 · 第四课日支阴神</span><br><br><b>▸ 三传</b><br><span style="color:#9b8a78">初传(发用·起始)→ 中传(移易·过程)→ 末传(归计·结局)</span><br><br><b>▸ 九宗门</b><br><span style="color:#9b8a78">贼克·比用·涉害·遥克·昴星·别责·八专·伏吟·反吟</span><br><br><span style="color:#b8a898;font-size:0.95em">※ 完整排盘需配合具体时辰与日干支,建议请六壬师详断。</span></div>`;
|
||
}
|
||
|
||
function qiMenHTML(y,m,d){
|
||
const dz=['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'];
|
||
const tg=['甲','乙','丙','丁','戊','己','庚','辛','壬','癸'];
|
||
const mingGongMap={1:'丑',2:'寅',3:'卯',4:'辰',5:'巳',6:'午',7:'未',8:'申',9:'酉',10:'戌',11:'亥',12:'子'};
|
||
return `<div class="module-title">✦ 奇门遁甲 命盘概要 ✦</div>
|
||
<div class="module-desc">${tg[(y-4)%10]}${dz[(y-4)%12]}年 · 命宫:${mingGongMap[m]||'午'}</div>
|
||
<div class="module-section"><b>▸ 简介</b><br><span style="color:#9b8a78">奇门合天(九星)、地(九宫)、人(八门)、神(八神)四层于一体。排盘需节气+时辰+用局,极为精密。</span><br><br><b>▸ 地盘九宫</b><br><span style="color:#9b8a78">戴九履一·左三右七·二四为肩·六八为足·五居中央<br>坎一水·坤二土·震三木·巽四木·中五土·乾六金·兑七金·艮八土·离九火</span><br><br><b>▸ 八门(人事)</b><br><span style="color:#9b8a78">开门(吉)·休门(吉)·生门(吉)·伤门(凶)·杜门(平)·景门(平)·死门(凶)·惊门(凶)</span><br><br><b>▸ 九星(天时)</b><br><span style="color:#9b8a78">天蓬·天任·天冲·天辅·天英·天芮·天柱·天心·天禽</span><br><br><span style="color:#b8a898;font-size:0.95em">※ 全面排盘需根据具体时辰和节气确定阳遁/阴遁几局,建议请奇门师详断。</span></div>`;
|
||
}
|
||
|
||
const ZODIAC=[
|
||
{name:'摩羯座',emoji:'♑',elem:'土',from:[12,22],to:[1,19],trait:'坚韧务实,目标明确,大器晚成',lucky:'深绿·黑'},
|
||
{name:'水瓶座',emoji:'♒',elem:'风',from:[1,20],to:[2,18],trait:'独立创新,思维超前,人道主义',lucky:'蓝·银'},
|
||
{name:'双鱼座',emoji:'♓',elem:'水',from:[2,19],to:[3,20],trait:'浪漫敏感,富有同情心,艺术天赋',lucky:'紫·海蓝'},
|
||
{name:'白羊座',emoji:'♈',elem:'火',from:[3,21],to:[4,19],trait:'热情勇敢,行动力强,开拓先锋',lucky:'红·金'},
|
||
{name:'金牛座',emoji:'♉',elem:'土',from:[4,20],to:[5,20],trait:'稳健可靠,审美出众,坚定执着',lucky:'粉·绿'},
|
||
{name:'双子座',emoji:'♊',elem:'风',from:[5,21],to:[6,21],trait:'机智灵活,善于沟通,双面魅力',lucky:'黄·银'},
|
||
{name:'巨蟹座',emoji:'♋',elem:'水',from:[6,22],to:[7,22],trait:'温柔顾家,情感丰富,保护欲强',lucky:'白·银'},
|
||
{name:'狮子座',emoji:'♌',elem:'火',from:[7,23],to:[8,22],trait:'自信大方,领导力强,光芒四射',lucky:'金·橙'},
|
||
{name:'处女座',emoji:'♍',elem:'土',from:[8,23],to:[9,22],trait:'细致严谨,追求完美,服务精神',lucky:'灰·米'},
|
||
{name:'天秤座',emoji:'♎',elem:'风',from:[9,23],to:[10,23],trait:'优雅公正,善于平衡,社交达人',lucky:'粉·蓝'},
|
||
{name:'天蝎座',emoji:'♏',elem:'水',from:[10,24],to:[11,22],trait:'深沉敏锐,意志坚定,极致深情',lucky:'深红·黑'},
|
||
{name:'射手座',emoji:'♐',elem:'火',from:[11,23],to:[12,21],trait:'乐观自由,探索精神,哲学思维',lucky:'紫·深蓝'},
|
||
];
|
||
|
||
function xingZuoHTML(y,m,d){
|
||
let z=ZODIAC.find(x=>(m===x.from[0]&&d>=x.from[1])||(m===x.to[0]&&d<=x.to[1]));
|
||
if(!z){if((m===12&&d>=22)||(m===1&&d<=19))z=ZODIAC[0];else if(m===1)z=ZODIAC[1];else z=ZODIAC.find(x=>m===x.from[0]&&d<x.from[1])||ZODIAC[0];}
|
||
const et={火:'热情主动,充满生命力,敢于冒险',土:'踏实稳重,注重现实,可靠可信',风:'思维敏捷,善于交流,适应力强',水:'情感深邃,直觉敏锐,富有创造力'};
|
||
const ec={火:'#c47a78',土:'#8b7a68',风:'#91a3b0',水:'#6b9eb3'};
|
||
return `<div class="module-title">✦ ${z.emoji} ${z.name} ✦</div>
|
||
<div class="module-desc">${z.elem}象星座 · 幸运色:${z.lucky}</div>
|
||
<div class="module-section"><span style="font-size:2em">${z.emoji}</span><br><b>▸ 性格特质</b><br><span style="color:#9b8a78">${z.trait}</span><br><br><b>▸ 元素能量</b><br><span style="color:#9b8a78">${et[z.elem]}</span><br><br><b>▸ 十二星座</b><br>${ZODIAC.map(x=>`<span style="color:${ec[x.elem]}">${x.emoji}</span>`).join(' ')}</div>`;
|
||
}
|
||
|
||
const BAGUA=[
|
||
{name:'乾 ☰',xiang:'天',elem:'金',clr:'#d4c5a0',txt:'#8b7355',desc:'刚健·创造'},
|
||
{name:'兑 ☱',xiang:'泽',elem:'金',clr:'#e8d5c8',txt:'#a08070',desc:'喜悦·沟通'},
|
||
{name:'离 ☲',xiang:'火',elem:'火',clr:'#e8c8c0',txt:'#b06050',desc:'光明·智慧'},
|
||
{name:'震 ☳',xiang:'雷',elem:'木',clr:'#c8d8b0',txt:'#5a7a3a',desc:'行动·震动'},
|
||
{name:'巽 ☴',xiang:'风',elem:'木',clr:'#b8d0b8',txt:'#4a7a4a',desc:'渗透·柔顺'},
|
||
{name:'坎 ☵',xiang:'水',elem:'水',clr:'#a8c8d8',txt:'#3a6a8a',desc:'险陷·智慧'},
|
||
{name:'艮 ☶',xiang:'山',elem:'土',clr:'#d0c8b0',txt:'#7a6a4a',desc:'静止·坚守'},
|
||
{name:'坤 ☷',xiang:'地',elem:'土',clr:'#e0d8c0',txt:'#8a7a5a',desc:'柔顺·包容'},
|
||
];
|
||
|
||
function wuXingHTML(y,m,d){
|
||
const yElem=['金','水','木','火','土'][Math.floor(((y-4)%10)/2)];
|
||
const mElem=['木','木','土','火','火','土','金','金','土','水','水','土'][m-1];
|
||
const dElem=['木','火','土','金','水'][d%5];
|
||
const ec={金:'#d4c5a0',水:'#a8c8d8',木:'#b8d0b8',火:'#e8c8c0',土:'#e0d8c0'};
|
||
return `<div class="module-title">✦ 五行八卦 能量图谱 ✦</div>
|
||
<div class="module-desc">年柱${yElem} · 月柱${mElem} · 日柱${dElem}</div>
|
||
<div class="module-section"><b>▸ 五行</b><br>
|
||
<div style="display:flex;gap:4px;margin:6px 0">${['金','水','木','火','土'].map(e=>`<span style="flex:1;text-align:center;padding:4px;background:${ec[e]};color:#5a4636;border-radius:3px;font-size:0.95em"><b>${e}</b></span>`).join('')}</div>
|
||
<span style="color:#9b8a78">金(义)·水(智)·木(仁)·火(礼)·土(信)<br>相生:金→水→木→火→土→金<br>相克:金→木→土→水→火→金</span><br><br><b>▸ 八卦</b><br>
|
||
<div class="bagua-grid">${BAGUA.map(b=>`<div class="bagua-cell" style="background:${b.clr};color:${b.txt}"><b>${b.name}</b><br><span style="font-size:0.92em">${b.elem}·${b.xiang}<br>${b.desc}</span></div>`).join('')}</div>
|
||
<span style="color:#9b8a78">八卦歌诀:乾三连·坤六断·震仰盂·艮覆碗·离中虚·坎中满·兑上缺·巽下断</span></div>`;
|
||
}
|
||
|
||
// ===== Tab 切换 =====
|
||
function initTabs(){
|
||
const nav=document.querySelector('.tabs-nav');
|
||
if(!nav)return;
|
||
nav.addEventListener('click',e=>{
|
||
const btn=e.target.closest('.tab-btn');
|
||
if(!btn)return;
|
||
const tab=btn.dataset.tab;
|
||
nav.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
document.querySelectorAll('.tab-panel').forEach(p=>p.classList.remove('active'));
|
||
const panel=document.getElementById(tab+'-panel');
|
||
if(panel)panel.classList.add('active');
|
||
});
|
||
}
|
||
|
||
function update(v,y,m,d){
|
||
document.getElementById('valR').textContent=v.R;
|
||
document.getElementById('valQ').textContent=v.Q;
|
||
document.getElementById('valP').textContent=v.P;
|
||
document.getElementById('valO').textContent=v.O;
|
||
document.getElementById('valM').textContent=v.M;
|
||
document.getElementById('valN').textContent=v.N;
|
||
document.getElementById('valI').textContent=v.I;
|
||
document.getElementById('valJ').textContent=v.J;
|
||
document.getElementById('valK').textContent=v.K;
|
||
document.getElementById('valL').textContent=v.L;
|
||
document.getElementById('valU').textContent=v.U;
|
||
document.getElementById('valT').textContent=v.T;
|
||
document.getElementById('valS').textContent=v.S;
|
||
document.getElementById('valX').textContent=v.X;
|
||
document.getElementById('valV').textContent=v.V;
|
||
document.getElementById('valW').textContent=v.W;
|
||
document.getElementById('dateD').textContent=String(d).padStart(2,'0');
|
||
document.getElementById('dateM').textContent=String(m).padStart(2,'0');
|
||
document.getElementById('dateY').textContent=y;
|
||
|
||
const allNums=[0,1,2,3,4,5,6,7,8,9];
|
||
const inner=new Set([v.O,v.M,v.N,v.I,v.J,v.K,v.L]);
|
||
const present=new Set([...inner,v.Q,v.P,v.R,v.T,v.S,v.U,v.V,v.W,v.X,v.AB[0],v.AB[1],v.CD[0],v.CD[1],v.EF[0],v.EF[1],v.GH[0],v.GH[1]]);
|
||
const miss={inner:allNums.filter(n=>!inner.has(n)),outer:allNums.filter(n=>![v.Q,v.P,v.R,v.T,v.S,v.U,v.V,v.W,v.X].includes(n)),both:allNums.filter(n=>!present.has(n))};
|
||
const n=NUM[v.O]||{};
|
||
|
||
const freq={};
|
||
for(let i=1;i<=9;i++)freq[i]=0;
|
||
const allVals=[v.O,v.M,v.N,v.I,v.J,v.K,v.L,v.Q,v.P,v.R,v.T,v.S,v.U,v.V,v.W,v.X,
|
||
v.AB[0],v.AB[1],v.CD[0],v.CD[1],v.EF[0],v.EF[1],v.GH[0],v.GH[1]];
|
||
allVals.forEach(x=>{if(x>=1&&x<=9)freq[x]++;});
|
||
currentFreq=freq;
|
||
const freqArr=Object.entries(freq).sort((a,b)=>b[1]-a[1]);
|
||
const most=freqArr[0],least=freqArr.filter(([,c])=>c===freqArr[freqArr.length-1][1]);
|
||
|
||
let freeHtml=`<div style="text-align:center;margin-bottom:18px;">`;
|
||
freeHtml+=`<div style="font-size:2.4em;font-weight:700;color:#c47a78;line-height:1;margin-bottom:4px;">${v.O}号人</div>`;
|
||
freeHtml+=`<div style="font-size:0.85em;font-weight:600;color:#5a4636;margin-bottom:6px;">${n.title||''}</div>`;
|
||
freeHtml+=`<div style="font-size:0.75em;color:#6b5b4e;line-height:1.7;max-width:340px;margin:0 auto;text-align:left;">${n.desc||''}</div>`;
|
||
freeHtml+=`</div>`;
|
||
let premiumHtml=``;
|
||
premiumHtml+=`<div style="font-size:0.7em;color:#9b8a78;margin-top:8px;line-height:1.7;text-align:left;max-width:340px;margin-left:auto;margin-right:auto;">`;
|
||
premiumHtml+=`<b>✦ 天赋优势</b>:${n.pos||''}<br><b>✦ 人生课题</b>:${n.neg||''}<br><b>✦ 五行属性</b>:${n.elem||''}<br><b>✦ 适合职业</b>:${n.job||''}</div></div>`;
|
||
|
||
premiumHtml+=`<hr class="divider">`;
|
||
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:8px;">✦ 数字能量图谱 ✦</div>`;
|
||
premiumHtml+=`<div style="font-size:0.7em;color:#6b5b4e;text-align:center;margin-bottom:0;">你的生命三角共汇聚了 <b>${allVals.filter(x=>x>=1).length}</b> 个能量数字</div>`;
|
||
premiumHtml+=`<div class="scene-3d" id="scene3d"><canvas></canvas><div class="scene-hint">↻ 左右旋转</div></div>`;
|
||
premiumHtml+=`<div class="freq-label">🔥 能量最强:<b>${most[0]}</b>(出现 ${most[1]} 次),是你生命中最闪耀的特质</div>`;
|
||
if(least.length>0)premiumHtml+=`<div class="freq-label" style="margin-top:0;">💧 能量最弱:${least.map(([n])=>`<b>${n}</b>`).join('、')}(仅 ${least[0][1]} 次),值得你用心浇灌</div>`;
|
||
|
||
premiumHtml+=`<hr class="divider">`;
|
||
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:6px;">✦ 三角内外——真实自我与外界眼光 ✦</div>`;
|
||
premiumHtml+=`<div style="font-size:0.7em;line-height:1.7;color:#6b5b4e;padding:0 4px;">`;
|
||
premiumHtml+=`<div><b>▸ 三角内部</b>:代表你内在真实的自我——潜意识的驱动、与生俱来的性格特质、不为人知的内心世界。</div>`;
|
||
premiumHtml+=`<div style="margin-top:3px;"><b>▸ 三角外部</b>:代表外界对你的认知——你在工作、家庭、社交中呈现出的样子,以及他人眼中的你。</div>`;
|
||
premiumHtml+=`<div style="margin-top:3px;"><b>▸ 下方基因</b>(父母遗传):代表来自父亲和母亲的先天遗传基因,是你性格的底层土壤。</div></div>`;
|
||
|
||
premiumHtml+=`<hr class="divider">`;
|
||
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:6px;">✦ 性格密码深度解读 ✦</div>`;
|
||
premiumHtml+=`<div style="font-size:0.7em;line-height:1.8;color:#6b5b4e;padding:0 4px;">`;
|
||
premiumHtml+=`<div style="margin-bottom:4px;"><b>潜意识码:${v.I}${v.J}${v.K}${v.L}</b></div>`;
|
||
premiumHtml+=`<div style="color:#9b8a78;margin-bottom:8px;">你内心深处的真实驱动力,最本能的反应模式。四个数字分别主宰:思维、情感、行动、人际。</div>`;
|
||
premiumHtml+=`<div style="margin-bottom:4px;"><b>内心码:${v.M}${v.N}</b></div>`;
|
||
premiumHtml+=`<div style="color:#9b8a78;margin-bottom:8px;">深层情感模式与核心价值观。理性行动 vs 感性人际——两者的平衡就是你面对压力时的姿态。</div>`;
|
||
premiumHtml+=`<div style="margin-bottom:4px;"><b>坐镇码:${v.I}${v.M}${v.O}</b></div>`;
|
||
premiumHtml+=`<div style="color:#9b8a78;margin-bottom:8px;">性格核心轴线:潜意识→内心→主性格。三环相扣,是你从内驱力到外在呈现的完整链条,也是你最稳定的底色。</div>`;
|
||
premiumHtml+=`<div style="margin-bottom:4px;"><b>父亲基因:${v.EF.join('')} ${v.GH.join('')}</b> · <b>母亲基因:${v.AB.join('')} ${v.CD.join('')}</b></div>`;
|
||
premiumHtml+=`<div style="color:#9b8a78;">父亲基因 ← 年份 ${v.EF.join('')}${v.GH.join('')})承载家族传承与事业基因<br>母亲基因 ← 月${v.CD.join('')} 日${v.AB.join('')})影响情感模式与人际底色</div></div>`;
|
||
|
||
premiumHtml+=`<hr class="divider">`;
|
||
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:6px;">✦ 数字缺失与能量过剩 ✦</div>`;
|
||
premiumHtml+=`<div style="font-size:0.7em;line-height:1.7;color:#6b5b4e;padding:0 4px;">`;
|
||
if(miss.both.length>0){premiumHtml+=`<div style="margin-bottom:4px;"><b>⚠ 缺失数字</b></div>`;miss.both.forEach(n=>{premiumHtml+=`<div style="margin-bottom:3px;">· <b>缺${n}</b>:${MISS_MSG[n]||''}</div>`;});}
|
||
else premiumHtml+=`<div style="margin-bottom:4px;color:#9b8a78;">✦ 你的数字分布完整,能量均衡。</div>`;
|
||
const over=[];for(let i=1;i<=9;i++){if(freq[i]>=4&&!miss.both.includes(i))over.push(i);}
|
||
if(over.length>0){premiumHtml+=`<div style="margin-top:6px;margin-bottom:4px;"><b>⚡ 能量过剩</b></div>`;over.forEach(n=>{premiumHtml+=`<div style="margin-bottom:3px;">· <b>多${n}</b>(×${freq[n]}):${MISS_STRONG[n]||''}</div>`;});}
|
||
premiumHtml+=`</div>`;
|
||
|
||
const joints=[['I','J'],['J','M'],['M','I'],['K','L'],['L','N'],['N','K'],['M','O'],['O','N'],['M','N'],['Q','P'],['Q','O'],['P','O']].map(([a,b])=>{const k=''+v[a]+v[b];const jk=Object.keys(JOINT).find(x=>x.startsWith(k));return {code:k,label:jk?JOINT[jk]:'—'};});
|
||
premiumHtml+=`<hr class="divider">`;
|
||
premiumHtml+=`<div style="font-size:0.82em;font-weight:600;color:#5a4636;text-align:center;margin-bottom:6px;">✦ 12组人生联合码 ✦</div>`;
|
||
premiumHtml+=`<div style="font-size:0.68em;color:#9b8a78;text-align:center;margin-bottom:8px;">相邻数字组合,解密你不同人生阶段的内在剧本</div>`;
|
||
const ages=[
|
||
{label:'21—40岁 · 工作和朋友',codes:joints.slice(0,4),desc:'由潜意识码主导,反映你在职场上升期和社交圈中的表现模式。'+(v.I+v.J+v.M>=10?'能量较强,事业心旺盛,社交活跃。':'能量内敛,更注重深度而非广度。')},
|
||
{label:'41—60岁 · 儿女和下属',codes:joints.slice(4,8),desc:'由内心码和主性格主导,体现你对下一代和下级的培养方式及中年价值观。'+(v.K+v.L+v.N>=10?'有较强的责任感和支配欲。':'倾向于给予空间,放手让他人成长。')},
|
||
{label:'61岁至晚年 · 晚年和家庭',codes:joints.slice(8,12),desc:'由外心码主导,展现你晚年的生活智慧和家庭关系的最终呈现。'+(v.M+v.N+v.O>=10?'晚年活跃,持续发挥影响力。':'晚年宁静,享受内在平和。')},
|
||
];
|
||
ages.forEach(ag=>{
|
||
premiumHtml+=`<div class="joint-age">${ag.label}</div>`;
|
||
premiumHtml+=`<div style="font-size:0.65em;color:#9b8a78;text-align:center;margin:-2px 0 6px;line-height:1.5;">${ag.desc}</div>`;
|
||
premiumHtml+=`<div class="joint-grid">`;
|
||
ag.codes.forEach(jc=>{premiumHtml+=`<div><span class="jc">${jc.code}</span> <span class="jm">${jc.label}</span></div>`;});
|
||
premiumHtml+=`</div>`;
|
||
});
|
||
|
||
const paid=localStorage.getItem('jiema_paid');
|
||
const lockEl=document.getElementById('missingBlock');
|
||
if(paid){
|
||
lockEl.innerHTML=freeHtml+premiumHtml;
|
||
}else{
|
||
lockEl.innerHTML=freeHtml+'<div class="shuzi-lock" id="shuziLock">'+premiumHtml+'</div>';
|
||
const lock=document.getElementById('shuziLock');
|
||
Array.from(lock.children).forEach(c=>c.classList.add('blur'));
|
||
const cover=document.createElement('div');cover.className='cover';
|
||
cover.innerHTML='<div class="lk-t">🔒 解锁你的完整数字报告</div><div class="lk-d">天赋优势 · 能量分布 · 性格编码 · 12组联合码</div>';
|
||
const btn=document.createElement('button');btn.className='lk-btn';btn.textContent='¥39.9 立即解锁 →';
|
||
btn.addEventListener('click',unlockShuzi);cover.appendChild(btn);lock.appendChild(cover);
|
||
}
|
||
setTimeout(()=>{
|
||
const canvas=document.querySelector('#scene3d canvas');
|
||
if(canvas){renderScene(canvas,freq,rotZ);setupRotation();}
|
||
},30);
|
||
document.getElementById('missingMsg').textContent='';
|
||
document.getElementById('codesBlock').innerHTML='';
|
||
document.getElementById('jointBlock').innerHTML='';
|
||
|
||
const tipEl=document.getElementById('tip');
|
||
['valR','valQ','valP','valO','valM','valN','valI','valJ','valK','valL','valU','valT','valS','valX','valV','valW'].forEach(id=>{
|
||
const el=document.getElementById(id);if(!el)return;el.style.cursor='pointer';
|
||
const k=id.replace('val','');
|
||
el.onpointerenter=()=>{const f=tips[k]?tips[k](v):'';tipEl.innerHTML=f||k;tipEl.classList.add('on')};
|
||
el.onpointermove=e=>{tipEl.style.left=(e.clientX+14)+'px';tipEl.style.top=(e.clientY-10)+'px'};
|
||
});
|
||
|
||
// 填充其他解读面板
|
||
document.getElementById('meihua-panel').innerHTML=meihuaHTML(y,m,d);
|
||
document.getElementById('xiaoliuren-panel').innerHTML=xiaoLiuRenHTML(y,m,d);
|
||
document.getElementById('daliuren-panel').innerHTML=daLiuRenHTML(y,m,d);
|
||
document.getElementById('qimen-panel').innerHTML=qiMenHTML(y,m,d);
|
||
document.getElementById('xingzuo-panel').innerHTML=xingZuoHTML(y,m,d);
|
||
document.getElementById('wuxing-panel').innerHTML=wuXingHTML(y,m,d);
|
||
}
|
||
|
||
function unlockShuzi(){localStorage.setItem("jiema_paid","1");const l=document.getElementById("shuziLock");l.querySelectorAll(".blur").forEach(c=>c.classList.remove("blur"));l.classList.add("unlocked");}
|
||
function go(){const y=+document.getElementById('inY').value,m=+document.getElementById('inM').value,d=+document.getElementById('inD').value;if(!y||!m||!d)return;update(calc(y,m,d),y,m,d)}
|
||
document.getElementById('goBtn').addEventListener('click',go);
|
||
document.querySelectorAll('.input-row input').forEach(i=>i.addEventListener('keydown',e=>{if(e.key==='Enter')go()}));
|
||
setTimeout(go,150);
|
||
initTabs();
|
||
|
||
// URL 参数预填(从 jiema.html 跳转过来)
|
||
(function(){
|
||
const p=new URLSearchParams(location.search);
|
||
const y=p.get('y'),m=p.get('m'),d=p.get('d');
|
||
if(y&&m&&d){
|
||
document.getElementById('inY').value=y;
|
||
document.getElementById('inM').value=m;
|
||
document.getElementById('inD').value=d;
|
||
setTimeout(go,200);
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html> |