2457e23271
技术栈: Vite + 原生HTML/JS/CSS + swisseph-wasm 功能模块: - 排盘引擎: 行星/宫位/Dasha/Yoga/相位/燃烧检测/130+城市 - 高级计算: Karaka/Arudha/16分盘/Ashtakavarga/Shadbala/Panchanga/Chara Dasha - 73个Yoga识别 (Pancha Mahapurusha + 扩展A/B) - 生时校正v2.0: K.N.Rao方法论, 多维评分 - Transit v2.0: 日期选择/全行星/AV评分/Sade Sati - 深度分析7子模块 + 扩展分析5子模块 - 导出v2.0: JSON 100%覆盖Python 13模块 + SVG/PNG - i18n中英双语 + 点读机95词条 + AI聊天面板 - 认证+订阅 (JWT/Apple Sign-In/IAP) - 浅色极简主题 (fatetell.com风格)
232 lines
15 KiB
JavaScript
232 lines
15 KiB
JavaScript
/**
|
||
* Deep Analysis Renderers v1.0
|
||
* 渲染: Raman功能表 · PACDARES · 宫位互影响 · Vargottama · 频率 · 三角验证 · Raman评级
|
||
*/
|
||
import { PLANET_CN, PLANET_SYMBOLS, SIGNS_CN, SIGNS } from './jyotish-engine.js';
|
||
import { RAMAN_TABLES, HOUSE_DOMAINS } from './analysis-deep.js';
|
||
import { t, signName, planetName, houseLabel } from './i18n.js';
|
||
|
||
const $ = id => document.getElementById(id);
|
||
|
||
// ============================================================================
|
||
// 1. Raman 功能吉凶星表
|
||
// ============================================================================
|
||
export function renderFunctionalNature(ascSign) {
|
||
const c = $('raman-fn-table'); if (!c) return;
|
||
const t = RAMAN_TABLES[ascSign]; if (!t) { c.innerHTML = '<p>无数据</p>'; return; }
|
||
const FN_LABEL = {
|
||
best_benefic: { text: '最佳吉星', cls: 'fn-best' },
|
||
benefic: { text: '吉星', cls: 'fn-good' },
|
||
yogakaraka: { text: 'Yogakaraka', cls: 'fn-yk' },
|
||
neutral: { text: '中性', cls: 'fn-neutral' },
|
||
malefic: { text: '凶星', cls: 'fn-bad' },
|
||
worst: { text: '最凶', cls: 'fn-worst' },
|
||
};
|
||
const mkBadges = (list, key) => list.map(p =>
|
||
`<span class="fn-badge ${FN_LABEL[key].cls}">${PLANET_SYMBOLS[p]||''} ${PLANET_CN[p]}</span>`
|
||
).join('');
|
||
|
||
let html = `<div class="fn-row fn-best-row"><span class="fn-label">最佳吉星</span><div class="fn-badges">${mkBadges(t.best,'best_benefic')}</div></div>`;
|
||
if (t.yk) html += `<div class="fn-row fn-yk-row"><span class="fn-label">Yogakaraka</span><div class="fn-badges"><span class="fn-badge fn-yk">${PLANET_SYMBOLS[t.yk]||''} ${PLANET_CN[t.yk]}</span></div></div>`;
|
||
html += `<div class="fn-row fn-good-row"><span class="fn-label">吉星</span><div class="fn-badges">${mkBadges(t.good,'benefic')}</div></div>`;
|
||
html += `<div class="fn-row fn-neutral-row"><span class="fn-label">中性</span><div class="fn-badges">${mkBadges(t.neutral,'neutral')}</div></div>`;
|
||
html += `<div class="fn-row fn-bad-row"><span class="fn-label">凶星</span><div class="fn-badges">${mkBadges(t.bad,'malefic')}</div></div>`;
|
||
if (t.worst.length) html += `<div class="fn-row fn-worst-row"><span class="fn-label">最凶</span><div class="fn-badges">${mkBadges(t.worst,'worst')}</div></div>`;
|
||
html += `<div class="fn-row fn-maraka-row"><span class="fn-label">Maraka</span><div class="fn-badges">${mkBadges(t.maraka,'worst')}</div></div>`;
|
||
c.innerHTML = html;
|
||
}
|
||
|
||
// ============================================================================
|
||
// 2. PACDARES 八维分析
|
||
// ============================================================================
|
||
export function renderPACDARES(pac) {
|
||
const c = $('pacdares-grid'); if (!c) return;
|
||
const SECTIONS = [
|
||
{ key:'P', title:'P · Position 位置', icon:'P', desc:'行星本位:落宫·星座·状态·功能属性' },
|
||
{ key:'A', title:'A · Aspect 相位', icon:'A', desc:'行星接收的相位影响' },
|
||
{ key:'C', title:'C · Conjunction 合相', icon:'C', desc:'同宫行星合相关系与能量污染' },
|
||
{ key:'D', title:'D · Dhana 财富', icon:'D', desc:'财富Yoga检测' },
|
||
{ key:'Ar', title:'Ar · Arishta 凶象', icon:'!', desc:'凶象检测' },
|
||
{ key:'R', title:'R · Raja 王者', icon:'R', desc:'Raja Yoga & Yogakaraka' },
|
||
{ key:'E', title:'E · Exchange 互换', icon:'E', desc:'Parivartana 宫主星互换' },
|
||
{ key:'S', title:'S · Special 特殊', icon:'S', desc:'逆行·燃烧·入旺·落陷' },
|
||
];
|
||
let html = '';
|
||
for (const s of SECTIONS) {
|
||
const items = pac[s.key] || [];
|
||
const count = items.length;
|
||
html += `<div class="pac-section"><div class="pac-header"><span class="pac-icon">${s.icon}</span><span class="pac-title">${s.title}</span><span class="pac-count">${count}</span></div><div class="pac-desc">${s.desc}</div>`;
|
||
if (count === 0) {
|
||
html += `<div class="pac-empty">未检测到</div>`;
|
||
} else {
|
||
html += `<div class="pac-items">`;
|
||
for (const it of items) html += renderPACItem(s.key, it);
|
||
html += `</div>`;
|
||
}
|
||
html += `</div>`;
|
||
}
|
||
c.innerHTML = html;
|
||
}
|
||
|
||
function renderPACItem(key, it) {
|
||
switch(key) {
|
||
case 'P': return `<div class="pac-item pac-pos"><span class="pi-planet">${PLANET_SYMBOLS[it.planet]||''} ${it.pcn}</span><span class="pi-detail">${it.scn} H${it.house} ${it.status||''} ${it.retro?'℞':''} ${it.combust?'[燃]':''}</span><span class="pi-fn fn-${fnCls(it.fn)}">${fnLabel(it.fn)}</span><span class="pi-hr">主管H${it.hr.join('/')}</span></div>`;
|
||
case 'A': return `<div class="pac-item pac-asp"><span class="pi-planet">${PLANET_SYMBOLS[it.planet]||''} ${it.pcn} (H${it.house})</span>${it.received.map(r=>`<span class="pi-recv ${r.impact==='吉'?'recv-good':r.impact==='凶'?'recv-bad':'recv-neut'}">${PLANET_CN[r.from]} ${r.type} → ${r.impact}</span>`).join('')}</div>`;
|
||
case 'C': return `<div class="pac-item pac-conj${it.pollution?' pac-poll':''}"><span class="pi-planets">${it.p1cn} + ${it.p2cn}</span><span class="pi-house">H${it.house}</span>${it.pollution?'<span class="pi-poll-badge">[!] 能量污染</span>':''}<span class="pi-fn fn-${fnCls(it.f1)}">${fnLabel(it.f1)}</span><span class="pi-fn fn-${fnCls(it.f2)}">${fnLabel(it.f2)}</span></div>`;
|
||
case 'D': return `<div class="pac-item pac-dhana"><span class="pi-type">${it.type}</span><span class="pi-lords">${it.lcn}</span><span class="pi-house">H${it.house}</span><span class="pi-str">${it.str}</span></div>`;
|
||
case 'Ar': return `<div class="pac-item pac-arishta"><span class="pi-type">${it.type}</span><span class="pi-desc">${it.desc}</span></div>`;
|
||
case 'R': return `<div class="pac-item pac-raja"><span class="pi-type">${it.type}</span><span class="pi-lords">${it.lcn}</span><span class="pi-house">H${it.house}</span><span class="pi-str">${it.str}</span></div>`;
|
||
case 'E': return `<div class="pac-item pac-exchg"><span class="pi-type">${it.type} (${it.nature})</span><span class="pi-desc">${it.desc}</span></div>`;
|
||
case 'S': return `<div class="pac-item pac-special"><span class="pi-type">${it.type}</span><span class="pi-desc">${it.desc}</span></div>`;
|
||
default: return '';
|
||
}
|
||
}
|
||
|
||
function fnCls(fn) { return fn==='yogakaraka'?'yk':fn==='best_benefic'?'best':fn==='benefic'?'good':fn==='malefic'?'bad':fn==='worst'?'worst':'neut'; }
|
||
function fnLabel(fn) { return fn==='yogakaraka'?'YK':fn==='best_benefic'?'大吉':fn==='benefic'?'吉':fn==='malefic'?'凶':fn==='worst'?'大凶':'中'; }
|
||
|
||
// ============================================================================
|
||
// 3. 宫位互影响矩阵
|
||
// ============================================================================
|
||
export function renderHouseInfluence(matrix) {
|
||
const c = $('house-influence-grid'); if (!c) return;
|
||
let html = '';
|
||
for (const h of matrix) {
|
||
const vd = h.verdict;
|
||
const vc = vd==='强力'?'vd-strong':vd==='吉'?'vd-good':vd==='中'?'vd-neut':vd==='弱'?'vd-weak':'vd-afflicted';
|
||
html += `<div class="hi-card ${vc}"><div class="hi-header"><span class="hi-num">H${h.house}</span><span class="hi-sign">${h.scn}</span><span class="hi-lord">主: ${h.lcn}</span></div><div class="hi-score ${vc}">${h.total>0?'+':''}${h.total}</div><div class="hi-verdict ${vc}">${h.verdict}</div><div class="hi-items">`;
|
||
for (const it of h.items) {
|
||
const ic = it.sc > 0 ? 'hi-pos' : it.sc < 0 ? 'hi-neg' : 'hi-zero';
|
||
html += `<div class="hi-influence ${ic}"><span class="hi-src">${it.src}</span><span class="hi-sc">${it.sc>0?'+':''}${it.sc}</span></div>`;
|
||
}
|
||
html += `</div></div>`;
|
||
}
|
||
c.innerHTML = html;
|
||
}
|
||
|
||
// ============================================================================
|
||
// 4. Vargottama 检测
|
||
// ============================================================================
|
||
export function renderVargottama(vgList) {
|
||
const c = $('vargottama-section'); if (!c) return;
|
||
if (!vgList.length) { c.innerHTML = '<div class="vg-empty">未检测到 Vargottama 行星</div>'; return; }
|
||
let html = '<div class="vg-grid">';
|
||
for (const v of vgList) {
|
||
html += `<div class="vg-card"><span class="vg-planet">${PLANET_SYMBOLS[v.planet]||''} ${v.pcn}</span><span class="vg-badge">Vargottama</span><span class="vg-sign">${v.d1}</span></div>`;
|
||
}
|
||
html += '</div>';
|
||
html += '<div class="vg-note">Vargottama:行星在本命盘(D1)和九分盘(D9)落入同一星座,能量倍增。无论吉凶,该行星能量都会被放大。</div>';
|
||
c.innerHTML = html;
|
||
}
|
||
|
||
// ============================================================================
|
||
// 5. 行星频率分析
|
||
// ============================================================================
|
||
export function renderFrequency(freq) {
|
||
const c = $('frequency-grid'); if (!c) return;
|
||
let html = '';
|
||
for (const [pn, f] of Object.entries(freq)) {
|
||
const lc = f.pct>=50?'freq-vhigh':f.pct>=40?'freq-high':f.pct>=30?'freq-mid':'freq-low';
|
||
html += `<div class="freq-card"><div class="freq-header"><span class="freq-planet">${PLANET_SYMBOLS[pn]||''} ${f.pcn}</span><span class="freq-pct ${lc}">${f.pct}%</span></div><div class="freq-top">${f.topScn} (${f.count}/${16})</div><div class="freq-level ${lc}">${f.level}</div><div class="freq-bar-wrap"><div class="freq-bar" style="width:${f.pct}%"></div></div><div class="freq-dist">${f.dist.map(d=>`${d.scn} ${d.p}%`).join(' · ')}</div></div>`;
|
||
}
|
||
c.innerHTML = html;
|
||
}
|
||
|
||
// ============================================================================
|
||
// 6. D1 × D9 × D10 三角验证
|
||
// ============================================================================
|
||
export function renderTriangle(tri) {
|
||
const c = $('triangle-table'); if (!c) return;
|
||
let html = `<table class="tri-table"><thead><tr><th>行星</th><th>D1</th><th>D1状态</th><th>D9</th><th>D9状态</th><th>D10</th><th>D10状态</th><th>Vg</th><th>判定</th></tr></thead><tbody>`;
|
||
for (const t of tri) {
|
||
const vc = t.verdict.includes('双重强势')?'tri-best':t.verdict.includes('未兑现')?'tri-break':t.verdict.includes('反击')?'tri-comeback':t.verdict.includes('双重弱势')?'tri-worst':'tri-ok';
|
||
html += `<tr><td>${PLANET_SYMBOLS[t.planet]||''} ${t.pcn}</td><td>${t.d1sign}</td><td class="${stCls(t.d1st)}">${t.d1st}</td><td>${t.d9sign}</td><td class="${stCls(t.d9st)}">${t.d9st}</td><td>${t.d10sign}</td><td class="${stCls(t.d10st)}">${t.d10st}</td><td>${t.vargottama?'✓':'—'}</td><td class="${vc}">${t.verdict}</td></tr>`;
|
||
}
|
||
html += '</tbody></table>';
|
||
c.innerHTML = html;
|
||
}
|
||
|
||
function stCls(st) { return st==='入旺'||st==='入庙'?'st-good':st==='落陷'?'st-bad':'st-neut'; }
|
||
|
||
// ============================================================================
|
||
// 7. Raman 宫位评级(六步法)
|
||
// ============================================================================
|
||
export function renderRamanGrades(scores) {
|
||
const c = $('raman-grades-grid'); if (!c) return;
|
||
let html = '';
|
||
for (const s of scores) {
|
||
const gc = s.grade==='A'?'grade-a':s.grade==='B'?'grade-b':s.grade==='C'?'grade-c':s.grade==='D'?'grade-d':'grade-f';
|
||
const domain = HOUSE_DOMAINS[s.house];
|
||
html += `<div class="rg-card ${gc}"><div class="rg-top"><span class="rg-num">H${s.house}</span><span class="rg-sign">${s.scn}</span><span class="rg-grade ${gc}">${s.grade}</span></div><div class="rg-domain">${domain?domain.name:''}</div><div class="rg-scores"><span class="rg-pos">+${s.pos}</span> / <span class="rg-neg">-${s.neg}</span> = <span class="rg-net">${s.net>0?'+':''}${s.net}</span></div><div class="rg-lord">宫主: ${s.lcn}</div><div class="rg-details">`;
|
||
for (const d of s.details) html += `<div class="rg-detail ${d.startsWith('✓')?'rd-pos':d.startsWith('✗')?'rd-neg':'rd-neut'}">${d}</div>`;
|
||
html += '</div></div>';
|
||
}
|
||
c.innerHTML = html;
|
||
}
|
||
|
||
// ============================================================================
|
||
// 8. Trikona-Kendra 三方四正映射渲染
|
||
// ============================================================================
|
||
export function renderTrikonaKendra(data) {
|
||
const c = document.getElementById('trikona-kendra-grid');
|
||
if (!c || !data) return;
|
||
const { houseLords, trikonaConnections, kendraConnections, crossConnections, overallRating, hasRaja } = data;
|
||
|
||
let html = `<div class="tk-rating">${overallRating}</div>`;
|
||
|
||
// 关键宫位宫主星一览
|
||
html += `<div class="tk-section"><h5 class="tk-subtitle">关键宫位宫主星</h5><div class="tk-lords-grid">`;
|
||
const keyHouses = [1, 4, 5, 7, 9, 10];
|
||
const houseTag = { 1: '命宫', 4: '家庭', 5: '创意', 7: '婚姻', 9: '命运', 10: '事业' };
|
||
const groupTag = h => [1,5,9].includes(h) ? '三方' : '四正';
|
||
for (const h of keyHouses) {
|
||
const hl = houseLords[h];
|
||
const tag = houseTag[h] || '';
|
||
const grp = groupTag(h);
|
||
html += `<div class="tk-lord-card">
|
||
<div class="tk-lord-house">H${h} <small>${tag}</small> <span class="tk-badge tk-badge-${grp === '三方' ? 'trikona' : 'kendra'}">${grp}</span></div>
|
||
<div class="tk-lord-name">${hl.lord_cn} (${hl.lord})</div>
|
||
<div class="tk-lord-in">→ H${hl.lordInHouse || '?'} ${hl.lordStatus || ''} ${hl.lordRetro ? '℞' : ''}</div>
|
||
</div>`;
|
||
}
|
||
html += '</div></div>';
|
||
|
||
// 三方连接
|
||
if (trikonaConnections.length > 0) {
|
||
html += `<div class="tk-section"><h5 class="tk-subtitle">Trikona 三方连接 (1-5-9)</h5><div class="tk-connections">`;
|
||
for (const conn of trikonaConnections) {
|
||
const qClass = conn.quality === 'excellent' ? 'tk-exc' : conn.quality === 'strong' ? 'tk-str' : 'tk-good';
|
||
html += `<div class="tk-conn ${qClass}"><span class="tk-conn-icon">${conn.quality === 'excellent' ? '★' : conn.quality === 'strong' ? '◆' : '→'}</span> ${conn.desc}</div>`;
|
||
}
|
||
html += '</div></div>';
|
||
} else {
|
||
html += `<div class="tk-section"><h5 class="tk-subtitle">Trikona 三方连接 (1-5-9)</h5><div class="tk-empty">三方宫主星之间无直接连接</div></div>`;
|
||
}
|
||
|
||
// 四正连接
|
||
if (kendraConnections.length > 0) {
|
||
html += `<div class="tk-section"><h5 class="tk-subtitle">Kendra 四正连接 (1-4-7-10)</h5><div class="tk-connections">`;
|
||
for (const conn of kendraConnections) {
|
||
const qClass = conn.quality === 'excellent' ? 'tk-exc' : conn.quality === 'strong' ? 'tk-str' : 'tk-good';
|
||
html += `<div class="tk-conn ${qClass}"><span class="tk-conn-icon">${conn.quality === 'excellent' ? '★' : conn.quality === 'strong' ? '◆' : '→'}</span> ${conn.desc}</div>`;
|
||
}
|
||
html += '</div></div>';
|
||
} else {
|
||
html += `<div class="tk-section"><h5 class="tk-subtitle">Kendra 四正连接 (1-4-7-10)</h5><div class="tk-empty">四正宫主星之间无直接连接</div></div>`;
|
||
}
|
||
|
||
// 三方×四正交叉
|
||
if (crossConnections.length > 0) {
|
||
html += `<div class="tk-section"><h5 class="tk-subtitle">Trikona × Kendra 交叉连接 (Raja Yoga)</h5><div class="tk-connections">`;
|
||
for (const conn of crossConnections) {
|
||
const qClass = conn.quality === 'maha-raja' ? 'tk-maha' : 'tk-raja';
|
||
html += `<div class="tk-conn ${qClass}"><span class="tk-conn-icon">${conn.quality === 'maha-raja' ? '★★' : '★'}</span> ${conn.desc}</div>`;
|
||
}
|
||
html += '</div></div>';
|
||
} else {
|
||
html += `<div class="tk-section"><h5 class="tk-subtitle">Trikona × Kendra 交叉连接</h5><div class="tk-empty">三方与四正之间无交叉 Raja Yoga 连接</div></div>`;
|
||
}
|
||
|
||
c.innerHTML = html;
|
||
}
|