dsh-metaphysics 0.68.0 → 0.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,8 +57,8 @@ header{display:flex;flex-direction:column;align-items:stretch;gap:12px;margin-bo
57
57
  transition:background .16s ease,color .16s ease,border-color .16s ease,box-shadow .16s ease}
58
58
  .tab:hover{background:var(--panel);border-color:var(--line);color:var(--ink)}
59
59
  .tab.on{background:linear-gradient(145deg,var(--accent-bg),var(--accent-bg2));border-color:transparent;color:var(--on-accent);font-weight:600;box-shadow:0 8px 18px -12px var(--gold)}
60
- /* 首屏按「想干什么」分组:19 个 tab 平铺时,第一次来的人得先猜「梅花」「称骨」是什么。
61
- 卡片只是另一套入口,点击仍走同一个 setTab;熟练用户可一键回到平铺(19 个 tab 原样保留)。 */
60
+ /* 首屏按「想干什么」分组:22 个 tab 平铺时,第一次来的人得先猜「梅花」「称骨」是什么。
61
+ 卡片只是另一套入口,点击仍走同一个 setTab;熟练用户可一键回到平铺(22 个 tab 原样保留)。 */
62
62
  .view-switch{display:flex;align-items:center;gap:8px}
63
63
  .view-switch .hint{font-size:12px;color:var(--dim)}
64
64
  .view-switch .seg button{padding:5px 11px;font-size:12.5px}
@@ -73,26 +73,26 @@ header{display:flex;flex-direction:column;align-items:stretch;gap:12px;margin-bo
73
73
  transition:border-color .14s ease,background .14s ease}
74
74
  .rc:hover{border-color:var(--gold);background:var(--panel)}
75
75
  .rc i{font-style:normal;font-size:11.5px;color:var(--dim)}
76
- .groups{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
76
+ .groups{display:grid;grid-template-columns:repeat(auto-fit,minmax(268px,1fr));gap:12px}
77
77
  .tgroup{padding:14px 14px 12px;border:1px solid var(--line);border-radius:14px;
78
78
  background:linear-gradient(180deg,var(--panel),color-mix(in srgb,var(--panel) 88%,var(--bg)));box-shadow:var(--shadow)}
79
79
  .tgroup-head h2{display:flex;align-items:center;gap:8px;margin:0;font-size:15.5px;font-weight:600;color:var(--ink);letter-spacing:.06em}
80
80
  .tgroup-head h2::before{content:"";flex:none;width:7px;height:7px;border-radius:2px;background:var(--gold)}
81
81
  .tgroup-head p{margin:4px 0 11px;font-size:12.5px;line-height:1.6;color:var(--dim)}
82
- .ttools{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}
82
+ .tgroup:not(.open) .ttools>.tool:nth-child(n+5){display:none}
83
+ .ttools{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;grid-auto-rows:1fr}
83
84
  .tool{display:flex;flex-direction:column;gap:1px;padding:8px 10px;text-align:left;border:1px solid var(--line);border-radius:9px;
84
85
  background:color-mix(in srgb,var(--panel2) 72%,transparent);color:var(--ink);font-family:inherit;cursor:pointer;
85
86
  transition:border-color .14s ease,background .14s ease,box-shadow .14s ease}
86
87
  .tool b{font-size:13.5px;font-weight:600;letter-spacing:.02em}
87
- .tool span{font-size:11.5px;line-height:1.4;color:var(--dim)}
88
+ .tool span{font-size:11.5px;line-height:1.4;color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
88
89
  .tool:hover{border-color:var(--gold);background:var(--panel)}
89
90
  .tool.on{border-color:transparent;background:linear-gradient(145deg,var(--accent-bg),var(--accent-bg2));box-shadow:0 8px 18px -12px var(--gold)}
90
91
  .tool.on b{color:var(--on-accent)}
91
92
  .tool.on span{color:var(--on-accent-soft)}
92
- /* 奇数个的那一组:末项铺满整行,避免右下留一个孤格 */
93
- .tool.wide{grid-column:1/-1}
93
+ /* 奇数个的那一组:窄屏末项铺满整行,避免右下留一个孤格(大屏三列时不铺) */
94
94
  /* 手机端每组先露 4 个,其余折在「还有 N 个」后面:三组全展开会把表单挤到第二屏 */
95
- .tmore{display:none;grid-column:1/-1;align-items:center;justify-content:center;gap:6px;padding:8px;border:1px dashed var(--line);border-radius:9px;
95
+ .tmore{display:flex;grid-column:1/-1;align-items:center;justify-content:center;gap:6px;padding:8px;border:1px dashed var(--line);border-radius:9px;
96
96
  background:transparent;color:var(--dim);font-family:inherit;font-size:12.5px;cursor:pointer}
97
97
  .tmore:hover{color:var(--gold);border-color:var(--gold)}
98
98
  body.view-group .tabs{display:none}
@@ -268,10 +268,9 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
268
268
  .tool{padding:9px 10px;min-height:52px}
269
269
  .tool b{font-size:14px}
270
270
  .tool span{font-size:11px}
271
- .tgroup:not(.open) .ttools>.tool:nth-child(n+5){display:none}
272
- .tmore{display:flex}
271
+ .tool.wide{grid-column:1/-1}
273
272
  .rc{min-height:36px}
274
- /* 19 个 tab 铺网格要占掉大半个首屏,改成单行横滑:44px 触摸目标、滚动条藏起来、
273
+ /* 22 个 tab 铺网格要占掉大半个首屏,改成单行横滑:44px 触摸目标、滚动条藏起来、
275
274
  左右各留 12px 呼吸位(padding 与 .wrap 等宽,首尾 tab 不会被切口)*/
276
275
  .tabs{display:flex;flex-wrap:nowrap;gap:8px;overflow-x:auto;overscroll-behavior-x:contain;
277
276
  margin:0 -12px;padding:2px 12px 6px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
@@ -362,7 +361,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
362
361
  <div class="wrap">
363
362
  <header>
364
363
  <div class="brand-row">
365
- <div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.68.0</span><small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></span></div>
364
+ <div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.70.0</span><small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></span></div>
366
365
  <div class="view-switch">
367
366
  <span class="hint">熟练了可以换回平铺</span>
368
367
  <span class="seg" role="group" aria-label="首屏样式">
@@ -411,40 +410,38 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
411
410
  <section class="tgroup">
412
411
  <div class="tgroup-head"><h2>问一件事</h2><p>心里有一件具体的事,起一卦再决定</p></div>
413
412
  <div class="ttools">
414
- <button type="button" class="tool" data-tab="liuyao"><b>六爻</b><span>摇六次,问一件事</span></button>
415
- <button type="button" class="tool" data-tab="meihua"><b>梅花</b><span>见闻起卦,看当下</span></button>
416
- <button type="button" class="tool" data-tab="tarot"><b>塔罗</b><span>抽牌,看关系与选择</span></button>
417
- <button type="button" class="tool" data-tab="qimen"><b>奇门</b><span>看方位、时机与取舍</span></button>
418
- <button type="button" class="tool" data-tab="daliuren"><b>六壬</b><span>占事,断来意与结果</span></button>
419
- <button type="button" class="tool" data-tab="xiaoliuren"><b>小六壬</b><span>掐指一算,快速断</span></button>
413
+ <button type="button" class="tool" data-tab="liuyao" title="摇六次问事"><b>六爻</b><span>摇六次问事</span></button>
414
+ <button type="button" class="tool" data-tab="tarot" title="抽牌看选择"><b>塔罗</b><span>抽牌看选择</span></button>
415
+ <button type="button" class="tool" data-tab="meihua" title="见闻起卦"><b>梅花</b><span>见闻起卦</span></button>
416
+ <button type="button" class="tool" data-tab="qimen" title="看方位时机"><b>奇门</b><span>看方位时机</span></button>
417
+ <button type="button" class="tool" data-tab="daliuren" title="占事断来意"><b>六壬</b><span>占事断来意</span></button>
418
+ <button type="button" class="tool" data-tab="xiaoliuren" title="掐指一算"><b>小六壬</b><span>掐指一算</span></button>
420
419
  <button type="button" class="tmore" aria-expanded="false"></button>
421
420
  </div>
422
421
  </section>
423
422
  <section class="tgroup">
424
- <div class="tgroup-head"><h2>看一个人</h2><p>看自己或身边人的性情、格局与运程</p></div>
423
+ <div class="tgroup-head"><h2>看一个人</h2><p>看自己或身边人的性情与格局</p></div>
425
424
  <div class="ttools">
426
- <button type="button" class="tool" data-tab="bazi"><b>八字</b><span>四柱看一生格局</span></button>
427
- <button type="button" class="tool" data-tab="ziwei"><b>紫微</b><span>十二宫细看</span></button>
428
- <button type="button" class="tool" data-tab="hepan"><b>合盘</b><span>两个人合不合</span></button>
429
- <button type="button" class="tool" data-tab="mbti"><b>人格</b><span>16 型性格问卷</span></button>
430
- <button type="button" class="tool" data-tab="constitution"><b>体质</b><span>九种体质自评,45 题</span></button>
431
- <button type="button" class="tool" data-tab="wuyunliuqi"><b>运气</b><span>五运六气,看一年大势</span></button>
432
- <button type="button" class="tool" data-tab="taiyi"><b>太乙</b><span>积年推局,太乙落宫与八门</span></button>
433
- <button type="button" class="tool" data-tab="chenggu"><b>称骨</b><span>按生辰称命重</span></button>
434
- <button type="button" class="tool" data-tab="numerology"><b>数字</b><span>生日数字看性格</span></button>
435
- <button type="button" class="tool wide" data-tab="trend"><b>人生K</b><span>一生高低走势</span></button>
425
+ <button type="button" class="tool" data-tab="bazi" title="四柱看格局"><b>八字</b><span>四柱看格局</span></button>
426
+ <button type="button" class="tool" data-tab="ziwei" title="十二宫细看"><b>紫微</b><span>十二宫细看</span></button>
427
+ <button type="button" class="tool" data-tab="hepan" title="两人合不合"><b>合盘</b><span>两人合不合</span></button>
428
+ <button type="button" class="tool" data-tab="mbti" title="16 型问卷"><b>人格</b><span>16 型问卷</span></button>
429
+ <button type="button" class="tool" data-tab="constitution" title="九种体质"><b>体质</b><span>九种体质</span></button>
430
+ <button type="button" class="tool" data-tab="chenggu" title="生辰称命重"><b>称骨</b><span>生辰称命重</span></button>
431
+ <button type="button" class="tool wide" data-tab="trend" title="一生走势"><b>人生K</b><span>一生走势</span></button>
436
432
  <button type="button" class="tmore" aria-expanded="false"></button>
437
433
  </div>
438
434
  </section>
439
435
  <section class="tgroup">
440
- <div class="tgroup-head"><h2>查日子</h2><p>挑时间、换农历,顺带看看家里和名字</p></div>
436
+ <div class="tgroup-head"><h2>查日子</h2><p>挑时间、换农历,看一年的气与方位</p></div>
441
437
  <div class="ttools">
442
- <button type="button" class="tool" data-tab="almanac"><b>黄历</b><span>今天宜忌、时辰吉凶</span></button>
443
- <button type="button" class="tool" data-tab="zeri"><b>择日</b><span>挑个办事的好日子</span></button>
444
- <button type="button" class="tool" data-tab="convert"><b>农历</b><span>公历农历互转</span></button>
445
- <button type="button" class="tool" data-tab="star"><b>星座</b><span>星座性格与今日运</span></button>
446
- <button type="button" class="tool" data-tab="fengshui"><b>风水</b><span>房屋朝向与布置</span></button>
447
- <button type="button" class="tool" data-tab="name"><b>起名</b><span>按八字选字</span></button>
438
+ <button type="button" class="tool" data-tab="almanac" title="今日宜忌"><b>黄历</b><span>今日宜忌</span></button>
439
+ <button type="button" class="tool" data-tab="zeri" title="挑好日子"><b>择日</b><span>挑好日子</span></button>
440
+ <button type="button" class="tool" data-tab="convert" title="公历农历"><b>农历</b><span>公历农历</span></button>
441
+ <button type="button" class="tool" data-tab="wuyunliuqi" title="一年大势"><b>运气</b><span>一年大势</span></button>
442
+ <button type="button" class="tool" data-tab="taiyi" title="积年推局"><b>太乙</b><span>积年推局</span></button>
443
+ <button type="button" class="tool" data-tab="fengshui" title="房屋朝向"><b>风水</b><span>房屋朝向</span></button>
444
+ <button type="button" class="tool" data-tab="name" title="八字选字"><b>起名</b><span>八字选字</span></button>
448
445
  <button type="button" class="tmore" aria-expanded="false"></button>
449
446
  </div>
450
447
  </section>
@@ -682,7 +679,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
682
679
  <h3>对拍:把典籍当期望值</h3>
683
680
  <ul><li>六爻:京房八宫卦序与世应,64 卦全表;旬空六旬表</li><li>六壬:日干寄宫、中气换将;紫微:纳音定五行局、紫微天府相照</li><li>卦例:《增删卜易》9 条 +《卜筮正宗》128 条(93 成对 + 35 静卦),核本变卦 / 动爻数 / 卦宫 / 缺爻 / 旬空</li><li>奇门:20 个时辰 × 9 宫,核四柱 / 局数 / 值符 / 值使 / 星门神 / 天盘干</li></ul>
684
681
  <h3>工程验证</h3>
685
- <ul><li>测试:177 个测试文件 / 9879 条断言;七道闸(回归 · 断言基线 · 测试可失败自检 · HTML 注入面 · 工程约定 · 产物宿主形态 · 随机扫射)</li><li>可复现:seed / asOf 显式;同一输入同一输出</li><li>口径:晚子时、真太阳时、奇门三流派、闰月归月都可切换,并有字段级差异对照</li></ul>
682
+ <ul><li>测试:177 个测试文件 / 10072 条断言;七道闸(回归 · 断言基线 · 测试可失败自检 · HTML 注入面 · 工程约定 · 产物宿主形态 · 随机扫射)</li><li>可复现:seed / asOf 显式;同一输入同一输出</li><li>口径:晚子时、真太阳时、奇门三流派、闰月归月都可切换,并有字段级差异对照</li></ul>
686
683
 
687
684
  <h3>已知边界(不猜)</h3>
688
685
  <ul><li>六爻应期(具体哪天应验)不做;卦例只录动爻个数,不录爻位</li><li>财富/健康只给结构判断与档位,不给金额区间、不作诊断</li><li>紫微飞星已做「单一支化逐宫追到成环」与「三方四正 16 条按落宫归堆」,但都未叠大限流年四化、不折吉凶;八字交运日已能算到日/时,但未与第三方排盘案例批量对拍</li></ul>
@@ -19271,11 +19268,22 @@ __mods.taiyi = (function () {
19271
19268
  // 6. 文昌:积年 mod 18,阳局自武德(申)起、阴局自吕申(寅)起,顺行十六神,
19272
19269
  // 遇阴德(乾)、大武(坤)各数两次
19273
19270
  //
19274
- // 没有做的(scope 里写明,别在文案里假装有):计神、始击、定目、主算 / 客算、
19275
- // 主客大小将、三基(君基 / 臣基 / 民基)、五福、十精,以及掩迫关囚击格等格局判定。
19276
- // 这些各有独立起例,互相对不上时整套盘会自相矛盾,必须单独一轮对着《太乙金镜式经》
19277
- // 与《太乙统宗宝鉴》逐条对拍,不在这层混进来。
19271
+ // 7. 计神:积年 mod 60 得六十甲子序,从寅起逆数十二支
19272
+ // 8. 始击:计神加和德(艮)之宫,天目(文昌)随盘移一位,即始击
19273
+ // 9. 主算 / 客算:沿九宫环顺行累加宫数,天目在正宫按本数、在间神先计一,
19274
+ // 数到太乙宫前一位为止
19275
+ // 10. 大将 = 算数个位(得十置一),参将 = 大将 × 3 的个位
19276
+ // 11. 掩、迫、囚、格、关五种位置关系
19277
+ //
19278
+ // 12. 定目、三基、五福、大游、十精、八种格局、阴阳数和
19279
+ // 13. 月计 / 日计 / 时计:按《太乙金镜式经》卷一的积月、积日、时实三套推法
19280
+ // 14. 古法吉凶:按卷一《推太公考时法》——八种相犯全无、主客数和,算和顺;
19281
+ // 命中任何一犯,古法算相犯。这是古籍的占断口径,不是预测,文案里必须写明。
19282
+ //
19283
+ // 没有做的(scope 里写明,别在文案里假装有):四神拆成本身与绛宫、明堂、玉堂
19284
+ // 十二位全序;胜负断辞与三旗五将。
19278
19285
 
19286
+ const { termInstantJd, toJDN, jdToParts, dayGanzhiIndex, STEMS } = (__mods.calendar || {});
19279
19287
  const { assertCivil } = (__mods.validate || {});
19280
19288
  const { assertObject } = (__mods.validate || {});
19281
19289
 
@@ -19333,6 +19341,210 @@ const FIVE_YUAN = ['甲子元', '丙子元', '戊子元', '庚子元', '壬子
19333
19341
  /** 三理:太乙在每一宫理天、理地、理人各一年 */
19334
19342
  const THREE_LI = ['理天', '理地', '理人'];
19335
19343
 
19344
+ /** 《太乙金镜式经》卷一的天文常数:章岁、章月、日法、月法 */
19345
+ const ZHANG_SUI = 657;
19346
+ const ZHANG_YUE = 8726;
19347
+ const RI_FA = 49;
19348
+ const YUE_FA = 2447;
19349
+
19350
+ /** 二十四局一周 → 宫序(起一宫顺行八宫、不游中五)与入宫第几期 */
19351
+ function palaceFromR24(r24) {
19352
+ const k = Math.ceil(r24 / 3);
19353
+ const inPalace = r24 - (k - 1) * 3 || 3;
19354
+ return { k, palace: YANG_WALK[k - 1], inPalace };
19355
+ }
19356
+
19357
+ /** 从某支起、逆行第 n 步(n 取 1..12,1 就是起点) */
19358
+ function branchWalk(startIdx, step) {
19359
+ const idx = (((startIdx - (step - 1)) % 12) + 12) % 12;
19360
+ return { idx, branch: BRANCH_NAMES[idx] };
19361
+ }
19362
+
19363
+ /** 十六神顺行第 n 步:遇阴德(乾)、大武(坤)各数两次,故十八步一周 */
19364
+ function sixteenStep(startGod, rest18) {
19365
+ const start = SIXTEEN.findIndex((x) => x.god === startGod);
19366
+ const steps = [];
19367
+ for (let i = 0; i < SIXTEEN.length; i += 1) {
19368
+ const cur = SIXTEEN[(start + i) % SIXTEEN.length];
19369
+ steps.push(cur);
19370
+ if (cur.pos === '乾' || cur.pos === '坤') steps.push(cur);
19371
+ }
19372
+ return steps[rim(rest18, 18) - 1];
19373
+ }
19374
+
19375
+ /** 月计:积月 = ⌊积年 × 章月 ÷ 章岁⌋,其余数称闰余 */
19376
+ function monthJiOf(jinian) {
19377
+ const jiyue = Number((BigInt(jinian) * BigInt(ZHANG_YUE)) / BigInt(ZHANG_SUI));
19378
+ const r24 = rim(jiyue, 24);
19379
+ const t = palaceFromR24(r24);
19380
+ const mu = sixteenStep('武德', rim(jiyue, 18));
19381
+ const js = branchWalk(2, rim(rim(jiyue, 60), 12));
19382
+ return {
19383
+ jiyue,
19384
+ taiyi: { rest24: r24, palace: t.palace, palaceName: PALACES[t.palace].name, unitInPalace: t.inPalace },
19385
+ mu: { pos: mu.pos, god: mu.god, palace: mu.num },
19386
+ jishen: js,
19387
+ };
19388
+ }
19389
+
19390
+ /** 日计:积日 = ⌊积月 × 月法 ÷ 日法⌋ */
19391
+ function dayJiOf(jinian) {
19392
+ const jiyue = Number((BigInt(jinian) * BigInt(ZHANG_YUE)) / BigInt(ZHANG_SUI));
19393
+ const jiri = Number((BigInt(jiyue) * BigInt(YUE_FA)) / BigInt(RI_FA));
19394
+ const r24 = rim(jiri, 24);
19395
+ const t = palaceFromR24(r24);
19396
+ const mu = sixteenStep('武德', rim(jiri, 18));
19397
+ const js = branchWalk(2, rim(rim(jiri, 60), 12));
19398
+ return {
19399
+ jiri,
19400
+ taiyi: { rest24: r24, palace: t.palace, palaceName: PALACES[t.palace].name, unitInPalace: t.inPalace },
19401
+ mu: { pos: mu.pos, god: mu.god, palace: mu.num },
19402
+ jishen: js,
19403
+ };
19404
+ }
19405
+
19406
+ /** 时计:以上年冬至为天正、十二时一辰,时实 = (冬至积日 − 1) × 12 + 时辰序 */
19407
+ function hourJiOf(datetime) {
19408
+ const { year, month, day, hour } = datetime;
19409
+ const wp = jdToParts(termInstantJd(year - 1, 23));
19410
+ const winterJdn = toJDN(wp.year, wp.month, wp.day);
19411
+ const summerJd = termInstantJd(year, 11);
19412
+ const nowJd = toJDN(year, month, day) - 0.5 + (hour * 60) / 1440;
19413
+ const dun = nowJd >= summerJd ? 'yin' : 'yang';
19414
+ const hIdx = Math.floor(((hour + 1) % 24) / 2);
19415
+ const shiShi = (winterJdn - 1) * 12 + hIdx;
19416
+ const r24 = rim(shiShi, 24);
19417
+ const t = palaceFromR24(r24);
19418
+ const start = dun === 'yang' ? 2 : 8;
19419
+ const js = branchWalk(start, rim(rim(shiShi, 60), 12));
19420
+ return {
19421
+ shiShi,
19422
+ dun,
19423
+ taiyi: { rest24: r24, palace: t.palace, palaceName: PALACES[t.palace].name, unitInPalace: t.inPalace },
19424
+ jishen: js,
19425
+ note: '时计用现代节气定冬至与夏至,不用唐代气法常数;与卷一的古历口径会有几日差。',
19426
+ };
19427
+ }
19428
+
19429
+ /** 古法吉凶:按卷一《推太公考时法》的位置判据,只判「相犯与否」与「数和不和」 */
19430
+ function jiXiongOf(o) {
19431
+ const items = (o.geju && o.geju.list) || [];
19432
+ const xiangFan = items.length > 0;
19433
+ const zhuHe = !!(o.heshu && o.heshu.zhu && o.heshu.zhu.he);
19434
+ const keHe = !!(o.heshu && o.heshu.ke && o.heshu.ke.he);
19435
+ const he = zhuHe && keHe;
19436
+ const gate = (o.gate && o.gate.gate) || '';
19437
+ // 卷一「吉道谓开休生三门」,年家只值一门,能判的就到这里
19438
+ const jiDao = gate === '开' || gate === '休' || gate === '生';
19439
+ // 用词照《太乙金镜式经》:凶、不和、吉、大吉;不自造档位
19440
+ let grade = 'ji';
19441
+ if (xiangFan) grade = 'xiong';
19442
+ else if (!he) grade = 'buhe';
19443
+ else if (jiDao) grade = 'daji';
19444
+ const label = grade === 'xiong' ? '凶' : grade === 'buhe' ? '不和' : grade === 'daji' ? '大吉' : '吉';
19445
+ const basis = xiangFan
19446
+ ? '命中' + items.join('、') + ',不满足卷一「上下无掩击迫囚关格对、并不相犯」'
19447
+ : !he
19448
+ ? '不相犯,但' + (zhuHe ? '客算' : '主算') + '落在不和'
19449
+ : jiDao
19450
+ ? '阴阳和顺、不相犯,八门又值' + gate + '(卷一所称吉道)'
19451
+ : '阴阳和顺、不相犯,八门值' + gate + ',不在开休生之内';
19452
+ const text = basis + '。';
19453
+ const note = '卷一另有「大利」「利以行兵」「先吉后凶」,要五将与神将同参,这一层没有做。';
19454
+ return { xiangFan, items, he, gate, grade, label, text, note };
19455
+ }
19456
+
19457
+ /* ── 神将层(第五层)─────────────────────────────────────────────
19458
+ 卷一《推太乙当时法》:「以日度加时因步六壬式,知天乙成败之分」——
19459
+ 借六壬十二神看四将与文昌、始击落在吉神还是凶神下。口径由本盘自定,写在这里备查:
19460
+ 1) 十二神用六壬序(贵人、螣蛇、朱雀、六合、勾陈、青龙、天后、太阴、玄武、太常、白虎、天空);
19461
+ 2) 贵人按日干起(甲戊庚丑未 / 乙己子申 / 丙丁亥酉 / 壬癸巳卯 / 辛午寅),卯至申用昼贵、酉至寅用夜贵;
19462
+ 3) 贵人临亥子丑寅卯辰顺行、临巳午未申酉戌逆行;
19463
+ 4) 四将与文昌、始击的卦位按后天八卦取一支(乾亥、坎子、艮丑、震卯、巽巳、离午、坤未、兑酉),
19464
+ 再取该支上的神;太乙九宫一宫两支,取生支这一支,是本盘唯一能自洽的一档。
19465
+ 这一层只给「古法怎么判」,不给成不成。 */
19466
+
19467
+ const TWELVE_GODS = ['贵人', '螣蛇', '朱雀', '六合', '勾陈', '青龙', '天后', '太阴', '玄武', '太常', '白虎', '天空'];
19468
+ const GOD_GOOD = ['贵人', '六合', '青龙', '太阴', '太常'];
19469
+ const GOD_BAD = ['螣蛇', '朱雀', '勾陈', '玄武', '白虎', '天空'];
19470
+ /** 后天八卦取支:一宫两支时取生支(与十六神位里同向那一支一致) */
19471
+ const TRIGRAM_TO_BRANCH = { 乾: '亥', 坎: '子', 艮: '丑', 震: '卯', 巽: '巳', 离: '午', 坤: '未', 兑: '酉' };
19472
+ /** 十六神位名 → 地支:卦位取生支,支位原样 */
19473
+ const POS_TO_BRANCH = { ...TRIGRAM_TO_BRANCH, 子: '子', 丑: '丑', 寅: '寅', 卯: '卯', 辰: '辰', 巳: '巳', 午: '午', 未: '未', 申: '申', 酉: '酉', 戌: '戌', 亥: '亥' };
19474
+ const GUI_REN = { 甲: '丑', 戊: '丑', 庚: '丑', 乙: '子', 己: '子', 丙: '亥', 丁: '亥', 壬: '巳', 癸: '巳', 辛: '午' };
19475
+ const GUI_REN_NIGHT = { 甲: '未', 戊: '未', 庚: '未', 乙: '申', 己: '申', 丙: '酉', 丁: '酉', 壬: '卯', 癸: '卯', 辛: '寅' };
19476
+
19477
+ /** 当天的日干 */
19478
+ function dayStemOf(year, month, day) {
19479
+ const idx = dayGanzhiIndex(toJDN(year, month, day));
19480
+ return STEMS[((idx % 10) + 10) % 10];
19481
+ }
19482
+
19483
+ /** 起十二神:昼贵 / 夜贵按卯~申、酉~寅分;反回 { stem, day, startBranch, dir, table } */
19484
+ function twelveGodsOf(stem, hour) {
19485
+ const h = typeof hour === 'number' ? hour : 0;
19486
+ const bi = Math.floor(((h + 1) % 24) / 2);
19487
+ const day = bi >= 2 && bi <= 7;
19488
+ const start = (day ? GUI_REN : GUI_REN_NIGHT)[stem] || '丑';
19489
+ const si = BRANCH_NAMES.indexOf(start);
19490
+ const dir = ['亥', '子', '丑', '寅', '卯', '辰'].includes(start) ? 1 : -1;
19491
+ const table = {};
19492
+ TWELVE_GODS.forEach((g, k) => {
19493
+ const bi2 = ((si + dir * k) % 12 + 12) % 12;
19494
+ table[BRANCH_NAMES[bi2]] = g;
19495
+ });
19496
+ return { stem, day, startBranch: start, dir, table };
19497
+ }
19498
+
19499
+ /** 四将与文昌、始击各落哪一神下 */
19500
+ function shenJiangOf(o) {
19501
+ const t = twelveGodsOf(o.dayStem, o.hour);
19502
+ const b2b = POS_TO_BRANCH;
19503
+ const rows = [
19504
+ ['主大将', o.jiang.zhuDaName],
19505
+ ['主参将', o.jiang.zhuCanName],
19506
+ ['客大将', o.jiang.keDaName],
19507
+ ['客参将', o.jiang.keCanName],
19508
+ ['文昌', o.wenchang && o.wenchang.pos],
19509
+ ['始击', o.shiji && o.shiji.pos],
19510
+ ].map(([who, gua]) => {
19511
+ const br = b2b[gua] || '';
19512
+ const god = br ? t.table[br] || '' : '';
19513
+ const kind = GOD_GOOD.includes(god) ? 'good' : GOD_BAD.includes(god) ? 'bad' : 'mid';
19514
+ return { who, gua, branch: br, god, kind };
19515
+ });
19516
+ const goods = rows.filter((x) => x.kind === 'good').map((x) => x.who + '在' + x.god);
19517
+ const bads = rows.filter((x) => x.kind === 'bad').map((x) => x.who + '在' + x.god);
19518
+ const mids = rows.filter((x) => x.kind === 'mid').map((x) => x.who + '在' + (x.god || '无名'));
19519
+ return { ...t, rows, goods, bads, mids };
19520
+ }
19521
+
19522
+ /**
19523
+ * 位置层 + 神将层合成卷一的判辞:凶 / 不和 / 吉 / 大吉 / 大利 / 先吉后凶。
19524
+ * 卷一判语:门具将发遇吉神则大吉;门杜闭塞遇吉神守固大利;门杜闭塞遇凶神则先吉后凶。
19525
+ * 位置层已相犯时古法认定「不相犯」不成立,不再往上抬。
19526
+ */
19527
+ function verdictOf(o) {
19528
+ const pos = o.jixiong || {};
19529
+ const sj = o.shenjiang || {};
19530
+ const gate = (o.gate && o.gate.gate) || '';
19531
+ const jiDao = gate === '开' || gate === '休' || gate === '生';
19532
+ const rows = sj.rows || [];
19533
+ const allGood = rows.length > 0 && (sj.bads || []).length === 0 && (sj.mids || []).length === 0;
19534
+ const anyBad = (sj.bads || []).length > 0;
19535
+ let grade = pos.grade || 'ji';
19536
+ let label = pos.label || '吉';
19537
+ if (grade !== 'xiong' && allGood) {
19538
+ grade = jiDao ? 'daji' : 'dali';
19539
+ label = jiDao ? '大吉' : '大利';
19540
+ } else if (grade !== 'xiong' && anyBad) {
19541
+ grade = jiDao ? 'xianji' : 'xiong';
19542
+ label = jiDao ? '先吉后凶' : '凶';
19543
+ }
19544
+ return { grade, label, jiDao, allGood, anyBad, posGrade: pos.grade, text: pos.text };
19545
+ }
19546
+
19547
+ /** 《太乙金镜式经》这一层覆盖的算法清单(面板与文案都从这里取) */
19336
19548
  const TAIYI_SCOPE = {
19337
19549
  covered: [
19338
19550
  '太乙积年与五元六纪',
@@ -19341,14 +19553,23 @@ const TAIYI_SCOPE = {
19341
19553
  '太乙落宫(三年一宫、不入中五)',
19342
19554
  '八门(三十年一转)',
19343
19555
  '文昌(十八年一周,遇乾、坤各数两次)',
19556
+ '计神(积年 mod 60,从寅起逆数)',
19557
+ '始击(计神加和德,天目随移)',
19558
+ '主算、客算与主客大小将、参将',
19559
+ '掩、击、格、对、提、迫、囚、关八种位置关系',
19560
+ '定目(年支合神移至太岁宫)',
19561
+ '三基(君基、臣基、民基)',
19562
+ '五福、大游',
19563
+ '十精其余(天乙、地乙、直符、四神、小游)',
19564
+ '阴阳数和(重阳、重阴、上和、次和、下和)',
19565
+ '月计、日计、时计(积月、积日、时实三套推法)',
19566
+ '古法吉凶倾向(相犯与否 + 数和不和)',
19344
19567
  ],
19345
19568
  notCovered: [
19346
- '计神、始击、定目',
19347
- '主算、客算与主客大小将参将',
19348
- '三基(君基、臣基、民基)、五福、十精',
19349
- '掩、迫、关、囚、击、格等格局判定',
19569
+ '四神拆成本身与绛宫、明堂、玉堂的十二位全序',
19570
+ '胜负断辞、三旗五将',
19350
19571
  ],
19351
- note: '这一层只到「太乙、八门、文昌」三个落点;主客算与格局需要另一套起例,未收录。',
19572
+ note: '这一层做到太乙、八门、文昌、计神、始击、主客算与四将、八种格局、定目、三基、五福、大游、十精、阴阳数和、月日时三计、古法吉凶与神将判辞;阴阳遁按冬至夏至交节判;四神十二位全序、胜负断辞不做。',
19352
19573
  };
19353
19574
 
19354
19575
  /** 取模成 1..n(余数 0 当 n) */
@@ -19390,7 +19611,11 @@ function yuanJiOf(rest360) {
19390
19611
  */
19391
19612
  function dunOf(jd) {
19392
19613
  if (typeof jd !== 'number' || !Number.isFinite(jd)) return { dun: 'yang', by: 'default' };
19393
- return { dun: 'yang', by: 'jd' };
19614
+ const p = jdToParts(jd);
19615
+ const summer = termInstantJd(p.year, 11); // 当年夏至
19616
+ const winter = termInstantJd(p.year, 23); // 当年冬至
19617
+ const yin = jd >= summer && jd < winter;
19618
+ return { dun: yin ? 'yin' : 'yang', by: 'jd', summer, winter };
19394
19619
  }
19395
19620
 
19396
19621
  /** 太乙落宫:局数 mod 24,三年一宫 */
@@ -19438,6 +19663,226 @@ function wenChang(jinian, dun) {
19438
19663
  return { rest18: r, pos: hit.pos, god: hit.god, num: hit.num, palaceName: PALACES[hit.num].name };
19439
19664
  }
19440
19665
 
19666
+ /** 八卦正宫名(十六神里 pos 落在这八个上就是正宫,其余是间神) */
19667
+ const GUA_NAMES = ['乾', '兑', '离', '震', '巽', '坎', '艮', '坤'];
19668
+
19669
+ /** 九宫环顺行:坎八 → 艮三 → 震四 → 巽九 → 离二 → 坤七 → 兑六 → 乾一 */
19670
+ const PALACE_RING = [8, 3, 4, 9, 2, 7, 6, 1];
19671
+
19672
+ /** 十二支名 */
19673
+ const BRANCH_NAMES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];
19674
+
19675
+ /** 地支序 → 十六神索引(子→地主、丑→阳德、寅→吕申……) */
19676
+ const BRANCH_TO_SIXTEEN = [2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 1];
19677
+
19678
+ /** 对宫:一乾对九巽、二离对八坎、三艮对七坤、四震对六兑,中五无对 */
19679
+ const OPPOSITE_PALACE = { 1: 9, 9: 1, 2: 8, 8: 2, 3: 7, 7: 3, 4: 6, 6: 4, 5: 5 };
19680
+
19681
+ /** 九宫环上的下一宫 */
19682
+ function nextPalace(palace) {
19683
+ const i = PALACE_RING.indexOf(palace);
19684
+ return PALACE_RING[(i + 1) % PALACE_RING.length];
19685
+ }
19686
+
19687
+ /** 九宫环上的上一宫(顺行的「前一宫」,即太乙左右) */
19688
+ function prevPalace(palace) {
19689
+ const i = PALACE_RING.indexOf(palace);
19690
+ return PALACE_RING[(i - 1 + PALACE_RING.length) % PALACE_RING.length];
19691
+ }
19692
+
19693
+ /** 六合:与某支相合的那一支(子丑、寅亥、卯戌、辰酉、巳申、午未) */
19694
+ const LIU_HE = [1, 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2];
19695
+
19696
+ /**
19697
+ * 定目:淘金歌「为客最难详定计,便以合神加太岁」——把合神搬到太岁所在处,
19698
+ * 盘整体旋转,原先天目(文昌)落到的位置就是定目。
19699
+ */
19700
+ function dingMuOf(wenChangIdx, yearBranchIdx) {
19701
+ const heIdx = LIU_HE[yearBranchIdx];
19702
+ const taiSui16 = BRANCH_TO_SIXTEEN[yearBranchIdx];
19703
+ const he16 = BRANCH_TO_SIXTEEN[heIdx];
19704
+ const idx16 = ((wenChangIdx + (taiSui16 - he16)) % 16 + 16) % 16;
19705
+ const item = SIXTEEN[idx16];
19706
+ return { shift: taiSui16 - he16, idx16, pos: item.pos, god: item.god, palace: item.num, palaceName: PALACES[item.num].name };
19707
+ }
19708
+
19709
+ /** 三基:君基三十年一移起午、臣基三年一移起午、民基一年一移起戌,顺行十二支 */
19710
+ function sanJiOf(jinian) {
19711
+ const step = (base, period, start) => BRANCH_NAMES[(start + Math.floor((jinian - 1) / period)) % 12];
19712
+ return {
19713
+ jun: step('jun', 30, 6),
19714
+ chen: step('chen', 3, 6),
19715
+ min: step('min', 1, 10),
19716
+ note: '君基三十年一移、臣基三年一移,都从午起;民基一年一移,从戌起,顺行十二支。',
19717
+ };
19718
+ }
19719
+
19720
+ /** 五福:四十五年移一位,上元甲子起一宫,乾一 → 艮三 → 巽九 → 坤七 → 中五 */
19721
+ const WUFU_ORDER = [1, 3, 9, 7, 5];
19722
+ function wuFuOf(jinian) {
19723
+ const i = Math.floor((jinian - 1) / 45) % WUFU_ORDER.length;
19724
+ const palace = WUFU_ORDER[i];
19725
+ return { index: i, palace, palaceName: PALACES[palace].name };
19726
+ }
19727
+
19728
+ /** 大游:三十六年移一位,上元甲子起七宫,逆数 七→六→四→三→二→一→九→八 */
19729
+ const DAYOU_ORDER = [7, 6, 4, 3, 2, 1, 9, 8];
19730
+ function daYouOf(jinian) {
19731
+ const i = Math.floor((jinian - 1) / 36) % DAYOU_ORDER.length;
19732
+ const palace = DAYOU_ORDER[i];
19733
+ return { index: i, palace, palaceName: PALACES[palace].name };
19734
+ }
19735
+
19736
+ /** 十二支上的位移取位(起点按地支索引,三年/三十年一移) */
19737
+ function branchStep(startIdx, period, jinian) {
19738
+ return { index: (startIdx + Math.floor((jinian - 1) / period)) % 12, name: BRANCH_NAMES[(startIdx + Math.floor((jinian - 1) / period)) % 12] };
19739
+ }
19740
+
19741
+ /**
19742
+ * 十精里的四个「十二宫」神:
19743
+ * 天乙「甲子上元从六起,三年一徙顺行踪」(第六位 = 巳)
19744
+ * 地乙「上元甲子九宫九,顺行十二宫中序,三年亦易」
19745
+ * 直符「上元甲子元从五,十二宫中顺数详」(第五位 = 辰 → 按九宫数五 = 中宫,这里按十二支第五位辰起)
19746
+ * 小游:三年一移,起一宫。
19747
+ */
19748
+ function shiJingOf(jinian) {
19749
+ const tianYi = branchStep(5, 3, jinian);
19750
+ const diYi = branchStep(8, 3, jinian);
19751
+ const zhiFu = branchStep(4, 3, jinian);
19752
+ const SI_SHEN_RING = ['一宫', '二宫', '三宫', '四宫', '五宫', '六宫', '七宫', '八宫', '九宫', '绛宫', '明堂', '玉堂'];
19753
+ const siShen = SI_SHEN_RING[Math.floor((jinian - 1) / 3) % 12];
19754
+ const xiaoYou = PALACES[YANG_WALK[Math.floor((jinian - 1) / 3) % 8]].name;
19755
+ return {
19756
+ tianyi: tianYi.name,
19757
+ diyi: diYi.name,
19758
+ zhifu: zhiFu.name,
19759
+ sishen: siShen,
19760
+ xiaoyou: xiaoYou,
19761
+ note: '天乙、地乙、直符、四神、小游都按上元甲子起例、三年一移;十精的另一半是五福、君基、臣基、民基、大游。',
19762
+ };
19763
+ }
19764
+
19765
+ /**
19766
+ * 阴阳和不和(张良经 / 卷二):太乙在阳宫(八三四九)得奇数为重阳,得偶数为和;
19767
+ * 太乙在阴宫(二七六一)得偶数为重阴,得奇数为和。这里只判这一段,不做胜负推断。
19768
+ */
19769
+ function heShuOf(taiyiPalace, suan) {
19770
+ const YANG = [8, 3, 4, 9];
19771
+ const yin = !YANG.includes(taiyiPalace);
19772
+ const odd = suan % 2 === 1;
19773
+ const chongYang = !yin && odd;
19774
+ const chongYin = yin && !odd;
19775
+ const he = !chongYang && !chongYin;
19776
+ const SHANG = [14, 18];
19777
+ const CI = [23, 29, 32];
19778
+ const XIA = [12, 16, 27, 34, 38];
19779
+ const grade = SHANG.includes(suan) ? '上和' : CI.includes(suan) ? '次和' : XIA.includes(suan) ? '下和' : '';
19780
+ return {
19781
+ grade,
19782
+ yang: !yin,
19783
+ odd,
19784
+ he,
19785
+ chongYang,
19786
+ chongYin,
19787
+ text: he
19788
+ ? `太乙在${yin ? '阴' : '阳'}宫、算得${odd ? '奇' : '偶'}数,为阴阳和${grade ? '(' + grade + ')' : ''}。`
19789
+ : chongYang
19790
+ ? '太乙在阳宫、算得奇数,为重阳,按经文属不和。'
19791
+ : '太乙在阴宫、算得偶数,为重阴,按经文属不和。',
19792
+ };
19793
+ }
19794
+
19795
+
19796
+ /**
19797
+ * 计神:积年 mod 60 得六十甲子第几年(1..60),从寅起逆数十二支。
19798
+ * 甲子年(序 1)计神在寅;寅年(序 3)计神在子,即「太岁在寅,计神在子」。
19799
+ */
19800
+ function jiShenOf(jinian) {
19801
+ const r = rim(jinian, 60);
19802
+ const bi = (((2 - (r - 1)) % 12) + 12) % 12;
19803
+ const idx16 = BRANCH_TO_SIXTEEN[bi];
19804
+ const item = SIXTEEN[idx16];
19805
+ return { r, branch: BRANCH_NAMES[bi], idx16, god: item.god, palace: item.num, palaceName: PALACES[item.num].name };
19806
+ }
19807
+
19808
+ /**
19809
+ * 始击:计神加和德(艮,十六神索引 4)之宫,天目随盘整体移动。
19810
+ * 位移 = 和德索引 − 计神索引;文昌落位顺移同一位移。
19811
+ */
19812
+ function shiJiOf(wenChangIdx, jiIdx16) {
19813
+ const HE_DE = 4;
19814
+ const shift = HE_DE - jiIdx16;
19815
+ const idx16 = ((wenChangIdx + shift) % 16 + 16) % 16;
19816
+ const item = SIXTEEN[idx16];
19817
+ return { shift, idx16, pos: item.pos, god: item.god, palace: item.num, palaceName: PALACES[item.num].name };
19818
+ }
19819
+
19820
+ /**
19821
+ * 主算 / 客算:从某位天目所在处起,沿九宫环顺行累加宫数。
19822
+ * 天目在正宫按本宫数起;在间神先计一,再从该间神所属的正宫继续。
19823
+ * 数到太乙宫前一位为止(不含太乙宫本身)。
19824
+ */
19825
+ function suanOf(idx16, taiyiPalace) {
19826
+ const item = SIXTEEN[idx16];
19827
+ const isJian = !GUA_NAMES.includes(item.pos);
19828
+ let total = isJian ? 1 : 0;
19829
+ let cur = item.num;
19830
+ for (let i = 0; i < PALACE_RING.length; i += 1) {
19831
+ if (cur === taiyiPalace) break;
19832
+ total += cur;
19833
+ cur = nextPalace(cur);
19834
+ }
19835
+ return total === 0 ? 1 : total;
19836
+ }
19837
+
19838
+ /** 大将宫数:算数个位,整十按「得十置一」归一宫 */
19839
+ function generalOf(n) {
19840
+ const g = n % 10;
19841
+ return g === 0 ? 1 : g;
19842
+ }
19843
+
19844
+ /** 参将宫数:大将 × 3 的个位,整十同样归一宫 */
19845
+ function canJiangOf(g) {
19846
+ const c = (g * 3) % 10;
19847
+ return c === 0 ? 1 : c;
19848
+ }
19849
+
19850
+ /** 掩迫囚格关:只判位置关系,不掺吉凶 */
19851
+ function gejuOf(o) {
19852
+ const { taiyiPalace, shiJiPalace, wenChangPalace, zhuDa, keDa, zhuCan, keCan } = o;
19853
+ const near = [nextPalace(taiyiPalace), prevPalace(taiyiPalace)];
19854
+ const yan = shiJiPalace === taiyiPalace;
19855
+ const ji = near.includes(shiJiPalace);
19856
+ const ge = shiJiPalace === OPPOSITE_PALACE[taiyiPalace];
19857
+ const dui = wenChangPalace === OPPOSITE_PALACE[taiyiPalace];
19858
+ const ti = keDa === wenChangPalace;
19859
+ const poAt = [];
19860
+ if (near.includes(wenChangPalace)) poAt.push('文昌');
19861
+ if (near.includes(zhuDa)) poAt.push('主大将');
19862
+ if (near.includes(keDa)) poAt.push('客大将');
19863
+ if (near.includes(zhuCan)) poAt.push('主参将');
19864
+ if (near.includes(keCan)) poAt.push('客参将');
19865
+ const qiuAt = [['主大将', zhuDa], ['客大将', keDa], ['主参将', zhuCan], ['客参将', keCan]]
19866
+ .filter((x) => x[1] === taiyiPalace).map((x) => x[0]);
19867
+ const cross = [
19868
+ ['主大将', zhuDa, '客大将', keDa],
19869
+ ['主大将', zhuDa, '客参将', keCan],
19870
+ ['客大将', keDa, '主参将', zhuCan],
19871
+ ['主参将', zhuCan, '客参将', keCan],
19872
+ ];
19873
+ const guan = cross.filter((x) => x[1] === x[3]).map((x) => x[0] + '与' + x[2] + '同宫');
19874
+ const list = [];
19875
+ if (yan) list.push('掩:始击与太乙同宫');
19876
+ if (ji) list.push('击:始击在太乙左右');
19877
+ if (ge) list.push('格:太乙与始击相望(对宫)');
19878
+ if (dui) list.push('对:文昌冲太乙宫');
19879
+ if (ti) list.push('提:客大将与文昌同宫');
19880
+ if (poAt.length) list.push('迫:' + poAt.join('、') + '在太乙前后');
19881
+ if (qiuAt.length) list.push('囚:' + qiuAt.join('、') + '与太乙同宫');
19882
+ if (guan.length) list.push('关:' + guan.join(','));
19883
+ return { yan, ji, ge, dui, ti, po: poAt, qiu: qiuAt, guan, list };
19884
+ }
19885
+
19441
19886
  /** 主入口 */
19442
19887
  function buildTaiyi(input) {
19443
19888
  assertObject(input, '太乙神数');
@@ -19449,12 +19894,52 @@ function buildTaiyi(input) {
19449
19894
  const yuanji = yuanJiOf(rest360);
19450
19895
  const gate = eightGate(year);
19451
19896
 
19452
- // 年家默认阳遁;给了具体日期时,口径仍写在 meta 里,方便以后接交节判定
19453
- const dun = 'yang';
19897
+ // 阳遁 / 阴遁按交节判:冬至到次年夏至为阳,夏至到冬至为阴。
19898
+ // 这一盘总要落到某一天,所以直接按日期判,不再默认阳遁。
19899
+ const hourNum = typeof input.hour === 'number' ? input.hour : 0;
19900
+ const nowJd = toJDN(year, month, day) - 0.5 + hourNum / 24;
19901
+ const dunInfo = dunOf(nowJd);
19902
+ const dun = dunInfo.dun;
19454
19903
 
19455
19904
  const t = taiyiPalace(ju, dun);
19456
19905
  const wc = wenChang(jinian, dun);
19457
19906
 
19907
+ const wcIdx16 = SIXTEEN.findIndex((x) => x.pos === wc.pos && x.god === wc.god);
19908
+ const js = jiShenOf(jinian);
19909
+ const sj = shiJiOf(wcIdx16, js.idx16);
19910
+ const zhuSuan = suanOf(wcIdx16, t.palace);
19911
+ const keSuan = suanOf(sj.idx16, t.palace);
19912
+ const zhuDa = generalOf(zhuSuan);
19913
+ const keDa = generalOf(keSuan);
19914
+ const zhuCan = canJiangOf(zhuDa);
19915
+ const keCan = canJiangOf(keDa);
19916
+ const geju = gejuOf({
19917
+ taiyiPalace: t.palace,
19918
+ shiJiPalace: sj.palace,
19919
+ wenChangPalace: wc.num,
19920
+ zhuDa,
19921
+ keDa,
19922
+ zhuCan,
19923
+ keCan,
19924
+ });
19925
+ const yearBranchIdx = (((year - 4) % 12) + 12) % 12;
19926
+ const dm = dingMuOf(wcIdx16, yearBranchIdx);
19927
+ const heZhu = heShuOf(t.palace, zhuSuan);
19928
+ const heKe = heShuOf(t.palace, keSuan);
19929
+ const heshu = { zhu: heZhu, ke: heKe };
19930
+ const jixiong = jiXiongOf({ geju, heshu, gate });
19931
+ const dayStem = dayStemOf(year, month, day);
19932
+ const jiangObj = {
19933
+ zhuDa, keDa, zhuCan, keCan,
19934
+ zhuDaName: PALACES[zhuDa].name, keDaName: PALACES[keDa].name,
19935
+ zhuCanName: PALACES[zhuCan].name, keCanName: PALACES[keCan].name,
19936
+ };
19937
+ const shenjiang = shenJiangOf({ dayStem, hour: typeof input.hour === 'number' ? input.hour : 0, jiang: jiangObj, wenchang: wc, shiji: sj });
19938
+ const verdict = verdictOf({ jixiong, shenjiang, gate });
19939
+ const monthJi = monthJiOf(jinian);
19940
+ const dayJi = dayJiOf(jinian);
19941
+ const hourJi = hourJiOf({ year, month, day, hour: typeof input.hour === 'number' ? input.hour : 0 });
19942
+
19458
19943
  return {
19459
19944
  system: 'taiyi',
19460
19945
  meta: {
@@ -19465,18 +19950,45 @@ function buildTaiyi(input) {
19465
19950
  ju,
19466
19951
  dun,
19467
19952
  dunText: dun === 'yin' ? '阴遁' : '阳遁',
19953
+ dunBy: dunInfo.by,
19468
19954
  epoch: TAIYI_EPOCH,
19469
19955
  },
19470
19956
  year: { ...yuanji, rest360 },
19471
19957
  taiyi: t,
19472
19958
  gate,
19473
19959
  wenchang: wc,
19960
+ jishen: js,
19961
+ shiji: sj,
19962
+ suan: { zhu: zhuSuan, ke: keSuan },
19963
+ jiang: {
19964
+ zhuDa,
19965
+ keDa,
19966
+ zhuCan,
19967
+ keCan,
19968
+ zhuDaName: PALACES[zhuDa].name,
19969
+ keDaName: PALACES[keDa].name,
19970
+ zhuCanName: PALACES[zhuCan].name,
19971
+ keCanName: PALACES[keCan].name,
19972
+ },
19973
+ geju,
19974
+ dingmu: dm,
19975
+ sanji: sanJiOf(jinian),
19976
+ wufu: wuFuOf(jinian),
19977
+ dayou: daYouOf(jinian),
19978
+ shijing: shiJingOf(jinian),
19979
+ heshu,
19980
+ jixiong,
19981
+ verdict,
19982
+ shenjiang,
19983
+ month: monthJi,
19984
+ day: dayJi,
19985
+ hour: hourJi,
19474
19986
  scope: TAIYI_SCOPE,
19475
19987
  };
19476
19988
  }
19477
19989
 
19478
19990
 
19479
- return { TAIYI_EPOCH, PALACES, SIXTEEN, YANG_WALK, YIN_WALK, EIGHT_GATES, GATE_BASE_YEAR, GATE_PERIOD, FIVE_YUAN, THREE_LI, TAIYI_SCOPE, taiyiJinian, taiyiRound, yuanJiOf, dunOf, taiyiPalace, eightGate, wenChang, buildTaiyi };
19991
+ return { TAIYI_EPOCH, PALACES, SIXTEEN, YANG_WALK, YIN_WALK, EIGHT_GATES, GATE_BASE_YEAR, GATE_PERIOD, FIVE_YUAN, THREE_LI, ZHANG_SUI, ZHANG_YUE, RI_FA, YUE_FA, palaceFromR24, branchWalk, sixteenStep, monthJiOf, dayJiOf, hourJiOf, jiXiongOf, TWELVE_GODS, GOD_GOOD, GOD_BAD, TRIGRAM_TO_BRANCH, POS_TO_BRANCH, dayStemOf, twelveGodsOf, shenJiangOf, verdictOf, TAIYI_SCOPE, taiyiJinian, taiyiRound, yuanJiOf, dunOf, taiyiPalace, eightGate, wenChang, GUA_NAMES, PALACE_RING, BRANCH_NAMES, BRANCH_TO_SIXTEEN, OPPOSITE_PALACE, nextPalace, prevPalace, LIU_HE, dingMuOf, sanJiOf, WUFU_ORDER, wuFuOf, DAYOU_ORDER, daYouOf, shiJingOf, heShuOf, jiShenOf, shiJiOf, suanOf, generalOf, canJiangOf, gejuOf, buildTaiyi };
19480
19992
  })();
19481
19993
 
19482
19994
  __mods.xiaoliuren = (function () {
@@ -29116,9 +29628,36 @@ function taiyiSummary(r) {
29116
29628
  h: '文昌在哪',
29117
29629
  t: `文昌在${r.wenchang.pos}(${r.wenchang.god},${r.wenchang.palaceName}宫)。文昌十八年一周,阳局从申起、阴局从寅起,路上遇乾、坤各数两次,所以要数满十八步才回到原点。`,
29118
29630
  },
29631
+ {
29632
+ h: '计神、始击与主客算',
29633
+ t: `计神在${r.jishen.branch},始击在${r.shiji.pos}(${r.shiji.god})。主算 ${r.suan.zhu}、客算 ${r.suan.ke}:大将按算数的个位落宫(整十归一),参将是大将乘三的个位。四个将分别落在${r.jiang.zhuDaName}、${r.jiang.keDaName}、${r.jiang.zhuCanName}、${r.jiang.keCanName}宫。`,
29634
+ },
29635
+ {
29636
+ h: '定目、三基与五福',
29637
+ t: `定目在${r.dingmu.pos}(${r.dingmu.god}):淘金歌讲「以合神加太岁」,把合神搬到太岁处,天目跟着转过去,落点就是定目。三基——君基${r.sanji.jun}(三十年一移)、臣基${r.sanji.chen}(三年一移)、民基${r.sanji.min}(一年一移);五福在${r.wufu.palaceName}宫(四十五年一移),大游在${r.dayou.palaceName}宫(三十六年一移、逆数)。十精另五位:天乙${r.shijing.tianyi}、地乙${r.shijing.diyi}、直符${r.shijing.zhifu}、四神${r.shijing.sishen}、小游${r.shijing.xiaoyou}。`,
29638
+ },
29639
+ {
29640
+ h: '阴阳数和',
29641
+ t: `主算:${r.heshu.zhu.text}客算:${r.heshu.ke.text}这一段只说「和不和」,上和、次和、下和是算数落在特定数上的分级,不据此断胜负。`,
29642
+ },
29643
+ {
29644
+ h: '卦象吉凶',
29645
+ t: `${r.jixiong.label}。${r.jixiong.text}${r.jixiong.note}判据出自卷一《推太公考时法》,只标吉凶,不推成与不成。`,
29646
+ },
29647
+ {
29648
+ h: '神将与判辞',
29649
+ t: (() => {
29650
+ const sj = r.shenjiang;
29651
+ if (!sj || !sj.rows) return '这一盘没有排神将。';
29652
+ const goods = sj.goods && sj.goods.length ? '在吉神下的:' + sj.goods.join('、') : '没有将落在吉神下';
29653
+ const bads = sj.bads && sj.bads.length ? '在凶神下的:' + sj.bads.join('、') : '没有将落在凶神下';
29654
+ const v = r.verdict ? '合起来判「' + r.verdict.label + '」。' : '';
29655
+ return '按日干起十二神(' + sj.stem + '日、' + (sj.day ? '昼贵' : '夜贵') + '、贵人临' + sj.startBranch + (sj.dir > 0 ? '顺' : '逆') + '行),' + goods + ';' + bads + '。' + v + '这一层是古人拿十二神看四将落位的办法,只说明古法怎么判,不是对事情的预测。';
29656
+ })(),
29657
+ },
29119
29658
  {
29120
29659
  h: '这一盘算到哪一层',
29121
- t: `积年 ${r.meta.jinian},残年 ${r.meta.rest360},${r.meta.dunText}${r.meta.ju}局。太乙、八门、文昌三个落点是齐的;${r.scope.notCovered.slice(0, 2).join('、')}这几项没有收录,盘面上也不显示。`,
29660
+ t: `积年 ${r.meta.jinian},残年 ${r.meta.rest360},${r.meta.dunText}${r.meta.ju}局。太乙、八门、文昌、计神、始击、主客算与四将、掩迫囚格关、定目、三基、五福、大游、十精、阴阳数和、月日时三计、古法吉凶都在;${r.scope.notCovered.join('、')}这几项没有收录,盘面上也不显示。`,
29122
29661
  },
29123
29662
  ];
29124
29663
  return {
@@ -29132,7 +29671,7 @@ function taiyiSummary(r) {
29132
29671
  `八门十年一变的说法常被混用,这里按三十年一转的口径——${r.gate.gate}值这三十年,不是今年才轮到。`,
29133
29672
  '太乙是象数盘,给的是位置的对应关系,不是「今年会发生什么」的判决。',
29134
29673
  ],
29135
- caveat: `这一层只到太乙、八门、文昌三个落点;${r.scope.notCovered.join(';')}都未收录,别按它们解读。`,
29674
+ caveat: `这一层到太乙、八门、文昌、计神、始击、主客算与四将、八种格局、定目、三基、五福、大游、十精与阴阳数和;${r.scope.notCovered.join(';')}都未收录,别按它们解读。`,
29136
29675
  footer: '太乙年家用积年推局,与八字按立春换年、运气按大寒分年都不同口径,三套不要互相印证。',
29137
29676
  };
29138
29677
  }
@@ -30853,7 +31392,7 @@ function computeRaw(args = {}) {
30853
31392
  }
30854
31393
  if (system === 'taiyi') {
30855
31394
  const dt = parseDateTime(args.datetime);
30856
- const result = buildTaiyi({ year: dt.year, month: dt.month, day: dt.day });
31395
+ const result = buildTaiyi({ year: dt.year, month: dt.month, day: dt.day, hour: dt.hour });
30857
31396
  return { ...result, summary: taiyiText(result) };
30858
31397
  }
30859
31398
  if (system === 'constitution') {
@@ -31117,7 +31656,25 @@ function taiyiText(r) {
31117
31656
  L.push(`太乙在${r.taiyi.palaceName}宫(第${r.taiyi.palace}宫,${r.taiyi.dir}),第${r.taiyi.yearInPalace}年,${r.taiyi.li}。`);
31118
31657
  L.push(`八门:${r.gate.gate}。`);
31119
31658
  L.push(`文昌在${r.wenchang.pos}(${r.wenchang.god},${r.wenchang.palaceName}宫)。`);
31120
- L.push(`这一层只算到太乙、八门、文昌三个落点;${r.scope.notCovered.join('、')}。`);
31659
+ L.push(`计神在${r.jishen.branch}(${r.jishen.god}),始击在${r.shiji.pos}(${r.shiji.god},${r.shiji.palaceName}宫)。`);
31660
+ L.push(`主算 ${r.suan.zhu}:主大将${r.jiang.zhuDaName}宫、主参将${r.jiang.zhuCanName}宫;客算 ${r.suan.ke}:客大将${r.jiang.keDaName}宫、客参将${r.jiang.keCanName}宫。`);
31661
+ L.push(r.geju.list.length ? `格局:${r.geju.list.join(';')}。` : '四将之间不相犯,没有掩、迫、囚、格、关。');
31662
+ L.push(`定目在${r.dingmu.pos}(${r.dingmu.god},${r.dingmu.palaceName}宫)。`);
31663
+ L.push(`三基:君基${r.sanji.jun}、臣基${r.sanji.chen}、民基${r.sanji.min};五福在${r.wufu.palaceName}宫,大游在${r.dayou.palaceName}宫。`);
31664
+ L.push(`十精:天乙${r.shijing.tianyi}、地乙${r.shijing.diyi}、直符${r.shijing.zhifu}、四神${r.shijing.sishen}、小游${r.shijing.xiaoyou}。`);
31665
+ L.push(`数和-主算:${r.heshu.zhu.text} 客算:${r.heshu.ke.text}`);
31666
+ const sj = r.shenjiang || {};
31667
+ if (sj.rows) {
31668
+ const goods = sj.goods && sj.goods.length ? sj.goods.join('、') : '无';
31669
+ const bads = sj.bads && sj.bads.length ? sj.bads.join('、') : '无';
31670
+ L.push(`神将:${sj.stem}日(${sj.day ? '昼贵' : '夜贵'})起${sj.startBranch}、${sj.dir > 0 ? '顺' : '逆'}行;在吉神下的有 ${goods};在凶神下的有 ${bads}。`);
31671
+ }
31672
+ if (r.verdict) L.push(`判辞:${r.verdict.label}。`);
31673
+ L.push(`月计:太乙在${r.month.taiyi.palaceName}宫(第${r.month.taiyi.unitInPalace}月),天目${r.month.mu.pos}(${r.month.mu.god}),计神在${r.month.jishen.branch}。`);
31674
+ L.push(`日计:太乙在${r.day.taiyi.palaceName}宫(第${r.day.taiyi.unitInPalace}日),天目${r.day.mu.pos}(${r.day.mu.god}),计神在${r.day.jishen.branch}。`);
31675
+ L.push(`时计:太乙在${r.hour.taiyi.palaceName}宫(第${r.hour.taiyi.unitInPalace}时),计神在${r.hour.jishen.branch}。${r.hour.note}`);
31676
+ L.push(`卦象:${r.jixiong.label}——${r.jixiong.text}`);
31677
+ L.push(`这一层到太乙、八门、文昌、计神、始击、主客算与四将、八种格局、定目、三基、五福、大游、十精、阴阳数和、月日时三计与古法吉凶;${r.scope.notCovered.join('、')}未收录。`);
31121
31678
  return L.join('\n');
31122
31679
  }
31123
31680
 
@@ -31431,7 +31988,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, parseDate
31431
31988
  })();
31432
31989
 
31433
31990
  window.Engine = __mods.index;
31434
- window.__MP_VER = "0.68.0";
31991
+ window.__MP_VER = "0.70.0";
31435
31992
  </script>
31436
31993
  <script>
31437
31994
  // 两个 UI 共用的表单规则:宿主面板(src/app.js)与独立页(src/web-ui.js)。
@@ -31552,7 +32109,7 @@ window.__MP_VER = "0.68.0";
31552
32109
  --tri:#eef0ea;--soul:#f7ece9;--sel:#f5efe9;--link:#f0efe9;
31553
32110
  --red:#a02c26;--red-rgb:160,44,38;--lu:#3d5a52;--lu-rgb:61,90,82;
31554
32111
  --quan:#6e5a2e;--quan-rgb:110,90,46;--ke:#3a5568;--ke-rgb:58,85,104;--ji:#a02c26;
31555
- --br-good:#4c7a5c;--br-bad:#9c5b56;--on-accent:#fff;--wx-metal:#8a6b1f;
32112
+ --br-good:#4c7a5c;--br-bad:#9c5b56;--on-accent:var(--on-accent);--wx-metal:#8a6b1f;
31556
32113
  --tg-bi:#4e5d6b;--tg-shi:#55685c;--tg-cai:#6e5a2e;--tg-guan:#8a4a42;--tg-yin:#5d5570;
31557
32114
  /* 之前 mp-cli / mp-qt / mp-cl / 起名卡里引用了 --ink3、--fx、--sans,却从未定义:
31558
32115
  var() 取不到值 → 整条声明作废,字色与字形全靠继承,楷体、弱化灰都成了摆设。 */
@@ -32161,6 +32718,77 @@ window.__MP_VER = "0.68.0";
32161
32718
  /* 三柱盘提示:表下一行,别让人以为漏画了一列 */
32162
32719
  .pp-warn{margin:8px 0 0;padding:7px 10px;border:1px solid color-mix(in srgb,var(--quan) 34%,var(--line));border-radius:8px;background:color-mix(in srgb,var(--quan) 10%,transparent);color:var(--ink2);font-size:11.5px;line-height:1.55}
32163
32720
  /* 顶部人话总结:第一屏唯一的「先说结论」块,边框与留白都比盘面重一档 */
32721
+ .mp-wl-h{display:flex;flex-wrap:wrap;gap:8px;padding-bottom:7px}
32722
+ .mp-wl-y{font-size:15px;font-weight:700}
32723
+ .mp-wl-z{font-weight:600;color:var(--lu)}
32724
+ .mp-wl-m,.mp-wl-tm,.mp-wl-tg,.mp-wl-no{font-size:11px;color:var(--label)}
32725
+ .mp-wl-tag{display:inline-block;margin:0 6px 4px 0;padding:1px 8px;border-radius:999px;background:var(--band)}
32726
+ .mp-wl-tag.on{background:var(--lu);color:var(--on-accent)}
32727
+ .mp-wl-sec,.mp-wl-note{font-size:13px;line-height:1.6;padding-bottom:5px}
32728
+ .mp-wl-sec em{font-style:normal;margin-right:6px}
32729
+ .mp-wl-steps{display:flex;flex-direction:column;gap:3px}
32730
+ .mp-wl-step{display:grid;grid-template-columns:16px 1fr 34px auto;gap:7px;font-size:12px;padding:3px 7px;border-radius:7px}
32731
+ .mp-wl-step.on{background:var(--band);font-weight:600}
32732
+ .mp-ty-h{display:flex;flex-wrap:wrap;gap:8px;align-items:baseline;padding-bottom:7px}
32733
+ .mp-ty-y{font-size:15px;font-weight:700}
32734
+ .mp-ty-j{font-weight:600;color:var(--lu)}
32735
+ .mp-ty-m{font-size:11px;color:var(--label)}
32736
+ .mp-ty-plain{padding:9px 2px 10px;border-top:1px solid var(--hair);margin-top:8px}
32737
+ .mp-ty-plain p{margin:0 0 6px;font-size:13px;line-height:1.65;color:var(--ink2)}
32738
+ .mp-ty-plain .mp-ty-lead{font-size:14px;font-weight:600;color:var(--ink)}
32739
+ .mp-ty-plain .mp-ty-close{font-size:12px;color:var(--label);margin-bottom:0}
32740
+ .mp-ty-det{margin-top:4px}
32741
+ .mp-ty-det summary{cursor:pointer;font-size:12px;color:var(--label);padding:4px 0}
32742
+ .mp-ty-g{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;margin:2px 0 8px}
32743
+ .mp-ty-cell{position:relative;border-radius:8px;background:var(--band);padding:7px 6px;text-align:center;font-size:12px;min-height:50px}
32744
+ .mp-ty-cell b{display:block;font-size:13px}
32745
+ .mp-ty-cell em{font-style:normal;font-size:11px;color:var(--label)}
32746
+ .mp-ty-cell.on{background:var(--lu);color:var(--on-accent)}
32747
+ .mp-ty-cell.on em{color:rgba(255,255,255,.82)}
32748
+ .mp-ty-cell.mid{opacity:.5}
32749
+ .mp-ty-mark{position:absolute;top:3px;right:4px;font-style:normal;font-size:10px;padding:0 4px;border-radius:999px;background:var(--on-accent);color:var(--lu)}
32750
+ .mp-ty-jx{font-weight:600}
32751
+ .mp-ty-jx.xiong{color:var(--red)}
32752
+ .mp-ty-jx.buhe{color:var(--quan)}
32753
+ .mp-ty-jx.daji{color:var(--lu);font-weight:700}
32754
+ .mp-ty-jx.ji{color:var(--lu)}
32755
+ .mp-ty-mark.s{top:19px;background:var(--band);color:var(--ink2)}
32756
+ .mp-ty-mark.w{right:auto;left:4px;color:var(--ink2)}
32757
+ .mp-ty-sec{font-size:13px;line-height:1.6;padding-bottom:4px}
32758
+ .mp-ty-sec em{font-style:normal;margin-right:6px;color:var(--label)}
32759
+ .mp-ty-note{font-size:11px;line-height:1.6;color:var(--label)}
32760
+ .mp-cs{border-radius:12px;overflow:hidden;background:var(--label);border:1px solid var(--hair)}
32761
+ .mp-cs-h{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 12px;border-bottom:1px solid var(--hair)}
32762
+ .mp-cs-main{font-size:20px;font-weight:800;letter-spacing:.04em}
32763
+ .mp-cs-meta{display:flex;flex-direction:column;gap:1px;flex:1 1 160px;min-width:0}
32764
+ .mp-cs-meta b{font-size:13px;font-weight:600;line-height:1.5}
32765
+ .mp-cs-meta i{font-size:12px;font-style:normal;color:var(--ink2)}
32766
+ .mp-cs-count{font-size:12px;color:var(--ink2);white-space:nowrap}
32767
+ .mp-cs-bars{display:flex;flex-direction:column;gap:5px;padding:10px 12px 8px}
32768
+ .mp-cs-row{display:grid;grid-template-columns:52px 1fr 30px 52px;align-items:center;gap:8px;font-size:12px;line-height:1.4}
32769
+ .mp-cs-row.main{font-weight:700}
32770
+ .mp-cs-n{white-space:nowrap}
32771
+ .mp-cs-track{position:relative;height:8px;border-radius:999px;background:var(--band)}
32772
+ .mp-cs-track i{display:block;height:100%;border-radius:999px;background:var(--dimline)}
32773
+ .mp-cs-track i.on{background:var(--lu)}
32774
+ .mp-cs-tick{position:absolute;top:0;bottom:0;width:1px;background:var(--label)}
32775
+ .mp-cs-v{text-align:right;color:var(--ink)}
32776
+ .mp-cs-l{color:var(--ink2);font-size:11px}
32777
+ .mp-cs-sec{padding:2px 12px 6px;font-size:13px;line-height:1.7}
32778
+ .mp-cs-sec em{display:inline-block;margin-right:6px;padding:0 6px;border-radius:4px;font-style:normal;font-size:11px;background:var(--band);color:var(--ink2)}
32779
+ .mp-cs-care{padding:4px 12px 8px;font-size:13px;line-height:1.7}
32780
+ .mp-cs-care b{display:block;margin-bottom:2px}
32781
+ .mp-cs-care ul{margin:0;padding-left:18px}
32782
+ .mp-cs-note{padding:6px 12px 10px;font-size:12px;line-height:1.6;color:var(--ink2)}
32783
+ .mp-cs-paper{padding:8px 12px;font-size:13px;line-height:1.7}
32784
+ .mp-cs-paper ol{margin:6px 0;padding-left:20px}
32785
+ .mp-cs-paper li{margin:2px 0}
32786
+ .mp-cs-no{display:inline-block;min-width:22px;color:var(--ink2);font-variant-numeric:tabular-nums}
32787
+ .mp-cs-paper li em{margin-left:6px;font-style:normal;font-size:11px;color:var(--ink2)}
32788
+ .mp-cs-paper .mp-cs-h{display:flex;align-items:center;gap:10px;padding:0 0 6px}
32789
+ .mp-cs-paper .mp-cs-h i{font-size:12px;font-style:normal;color:var(--ink2)}
32790
+ .mp-cs-paper .mp-cs-count{font-size:12px;color:var(--ink2)}
32791
+ .mp-cs-paper .mp-cs-note{font-size:12px;color:var(--ink2)}
32164
32792
  .mp-br{margin:0 0 12px;padding:14px 16px 12px;border:1px solid color-mix(in srgb,var(--red) 26%,var(--line));border-radius:12px;
32165
32793
  background:linear-gradient(180deg,color-mix(in srgb,var(--red) 6%,var(--card)),var(--card));color:var(--ink)}
32166
32794
  .mp-br-h{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:6px}
@@ -35610,34 +36238,109 @@ window.__MP_VER = "0.68.0";
35610
36238
  // 分数是数值,直接插;文字一律走 esc(check-html-sinks 按「调用了 esc」核对)。
35611
36239
  // 太乙神数:九宫地盘 + 太乙/文昌落点 + 八门 + 五元六纪。
35612
36240
  // 地盘按「南上北下」排:巽离坤 / 震中兑 / 艮坎乾。中五宫太乙不入,只作方位补全。
35613
- // 只有太乙、八门、文昌三个落点是算实的,其余项目(主客算、格局)不在盘上出现。
36241
+ // 太乙、八门、文昌、计神、始击、主客算与四将都是算实的;定目、三基五福十精、击格不在盘上出现。
35614
36242
  pp.taiyiHTML = function (r) {
35615
36243
  if (!r || !r.taiyi || !r.meta) return '';
35616
36244
  const t = r.taiyi;
35617
36245
  const wc = r.wenchang || {};
36246
+ const sj = r.shiji || {};
36247
+ const js = r.jishen || {};
36248
+ const su = r.suan || {};
36249
+ const jj = r.jiang || {};
36250
+ const gj = r.geju || {};
35618
36251
  const grid = [[9, '巽'], [2, '离'], [7, '坤'], [4, '震'], [5, '中'], [6, '兑'], [3, '艮'], [8, '坎'], [1, '乾']];
35619
36252
  const cells = grid.map((c) => {
35620
36253
  const num = c[0];
35621
36254
  const nm = c[1];
35622
36255
  const on = t.palace === num;
35623
36256
  const w = wc.num === num;
35624
- const marks = (on ? '<i class="mp-ty-mark">太乙</i>' : '') + (w ? '<i class="mp-ty-mark w">文昌</i>' : '');
36257
+ const sjOn = sj.palace === num;
36258
+ const marks = (on ? '<i class="mp-ty-mark">太乙</i>' : '') + (sjOn ? '<i class="mp-ty-mark s">始击</i>' : '') + (w ? '<i class="mp-ty-mark w">文昌</i>' : '');
35625
36259
  return `<div class="mp-ty-cell${on ? ' on' : ''}${nm === '中' ? ' mid' : ''}"><b>${esc(nm)}</b><em>${num}</em>${marks}</div>`;
35626
36260
  }).join('');
35627
36261
  const nc = (r.scope && r.scope.notCovered) || [];
36262
+ const mo = r.month || {};
36263
+ const da = r.day || {};
36264
+ const ho = r.hour || {};
36265
+ const monthN = (mo.taiyi && mo.taiyi.palaceName) || '';
36266
+ const monthU = String((mo.taiyi && mo.taiyi.unitInPalace) || '');
36267
+ const monthMu = mo.mu ? mo.mu.pos + '(' + mo.mu.god + ')' : '';
36268
+ const monthJs = (mo.jishen && mo.jishen.branch) || '';
36269
+ const dayN = (da.taiyi && da.taiyi.palaceName) || '';
36270
+ const dayU = String((da.taiyi && da.taiyi.unitInPalace) || '');
36271
+ const dayMu = da.mu ? da.mu.pos + '(' + da.mu.god + ')' : '';
36272
+ const dayJs = (da.jishen && da.jishen.branch) || '';
36273
+ const hourN = (ho.taiyi && ho.taiyi.palaceName) || '';
36274
+ const hourU = String((ho.taiyi && ho.taiyi.unitInPalace) || '');
36275
+ const hourJs = (ho.jishen && ho.jishen.branch) || '';
36276
+ const jx = r.jixiong || {};
36277
+ const vd = r.verdict || {};
36278
+ const vdGrade = vd.grade || jx.grade || 'xiong';
36279
+ const vdLabel = vd.label || jx.label || '凶';
36280
+ const sjj = r.shenjiang || {};
36281
+ const sjLine = sjj.rows
36282
+ ? `${sjj.stem}日、${sjj.day ? '昼贵' : '夜贵'}起${sjj.startBranch}${sjj.dir > 0 ? '顺' : '逆'}行;吉神下:${(sjj.goods || []).join('、') || '无'};凶神下:${(sjj.bads || []).join('、') || '无'}`
36283
+ : '未排';
36284
+ const jxGrade = jx.grade || 'xiong';
36285
+ const jxLabel = jx.label || '凶';
36286
+ const gateName = (r.gate && r.gate.gate) || '';
36287
+ // 八种格局翻成日常话,一个词只翻一次
36288
+ const SAY = {
36289
+ 掩: '客方的目和太乙挤在同一格',
36290
+ 击: '始击挨在太乙左右',
36291
+ 格: '太乙和始击隔一格正面对上',
36292
+ 对: '文昌从对面顶过来',
36293
+ 提: '客大将和文昌挤在一格',
36294
+ 迫: '有将贴得太近,就在太乙前后一格',
36295
+ 囚: '有将被关在太乙那一格里',
36296
+ 关: '主客两边的人撞在一处',
36297
+ };
36298
+ const hits = (gj.list || []).map((x) => {
36299
+ const k = String(x).charAt(0);
36300
+ return SAY[k] ? k + '——' + SAY[k] : String(x);
36301
+ });
36302
+ const lead = jxGrade === 'xiong'
36303
+ ? `太乙站在${t.palaceName}宫(${t.dir}),值${gateName}门,判凶:主客两边有几样撞到了一起。`
36304
+ : jxGrade === 'daji'
36305
+ ? `太乙站在${t.palaceName}宫(${t.dir}),值${gateName}门,判大吉:位置和数都顺,门也在吉道上。`
36306
+ : jxGrade === 'buhe'
36307
+ ? `太乙站在${t.palaceName}宫(${t.dir}),值${gateName}门,判不和:位置不冲突,但数上不合。`
36308
+ : `太乙站在${t.palaceName}宫(${t.dir}),值${gateName}门,判吉:位置不冲突。`;
35628
36309
  return `<section class="mp-ty" aria-label="太乙神数">
35629
36310
  <div class="mp-ty-h">
35630
36311
  <span class="mp-ty-y">${esc(String(r.meta.year))} 年</span>
35631
36312
  <span class="mp-ty-j">${esc(r.meta.dunText || '')}${esc(String(r.meta.ju))}局</span>
35632
36313
  <span class="mp-ty-m">太乙临 ${esc(t.palaceName || '')} 宫</span>
35633
- <span class="mp-ty-m">${esc(r.gate ? r.gate.gate : '')}</span>
36314
+ <span class="mp-ty-m">${esc(gateName)}</span>
35634
36315
  </div>
35635
36316
  <div class="mp-ty-g">${cells}</div>
35636
- <div class="mp-ty-sec"><em>太乙</em>第 ${esc(String(t.palace || ''))} 宫(${esc(t.dir || '')}),三年里的第 ${esc(String(t.yearInPalace || ''))} 年,${esc(t.li || '')}</div>
35637
- <div class="mp-ty-sec"><em>八门</em>${esc(r.gate ? r.gate.gate : '')} 八门三十年一转,1954 年从休门起</div>
35638
- <div class="mp-ty-sec"><em>文昌</em>${esc(wc.pos || '')}(${esc(wc.god || '')},${esc(wc.palaceName || '')}宫) 十八年一周</div>
35639
- <div class="mp-ty-sec"><em>积年</em>${esc(String(r.meta.jinian || ''))} 残年 ${esc(String(r.meta.rest360 || ''))} ${esc(r.year ? r.year.jiName : '')}${esc(r.year ? String(r.year.jiYear) : '')}年 ${esc(r.year ? r.year.yuanName : '')}第 ${esc(r.year ? String(r.year.yuanYear) : '')} 年</div>
35640
- <div class="mp-ty-note">只算到太乙、八门、文昌三个落点;${esc(nc.join('、'))}未收录,盘上不显示。</div>
36317
+ <div class="mp-ty-plain">
36318
+ <p class="mp-ty-lead">${esc(lead)}</p>
36319
+ <p>先看太乙落在哪一格——那是「主」这一年的位置,整张盘围着它转。</p>
36320
+ <p>${esc(gateName)}门一值三十年,管的是这三十年的大环境,不是今年单一年的事。</p>
36321
+ <p>判${esc(jxLabel)},是因为${esc(hits.length ? hits.join(';') : '八种位置关系一个都没犯')}。</p>
36322
+ <p class="mp-ty-close">这一层只摆位置和数,不回答事情成不成;想看每一步怎么来的,展开下面的细目。</p>
36323
+ </div>
36324
+ <details class="mp-ty-det">
36325
+ <summary>细目(想核对推导再展开)</summary>
36326
+ <div class="mp-ty-sec"><em>太乙</em>第 ${esc(String(t.palace || ''))} 宫(${esc(t.dir || '')}),三年里的第 ${esc(String(t.yearInPalace || ''))} 年,${esc(t.li || '')}</div>
36327
+ <div class="mp-ty-sec"><em>八门</em>${esc(gateName)} 八门三十年一转,1954 年从休门起</div>
36328
+ <div class="mp-ty-sec"><em>文昌</em>${esc(wc.pos || '')}(${esc(wc.god || '')},${esc(wc.palaceName || '')}宫) 十八年一周</div>
36329
+ <div class="mp-ty-sec"><em>定目</em>${esc((r.dingmu && r.dingmu.pos) || '')}(${esc((r.dingmu && r.dingmu.god) || '')}) <em>三基</em>君${esc((r.sanji && r.sanji.jun) || '')} 臣${esc((r.sanji && r.sanji.chen) || '')} 民${esc((r.sanji && r.sanji.min) || '')}</div>
36330
+ <div class="mp-ty-sec"><em>五福</em>${esc((r.wufu && r.wufu.palaceName) || '')}宫 <em>大游</em>${esc((r.dayou && r.dayou.palaceName) || '')}宫 <em>十精</em>天乙${esc((r.shijing && r.shijing.tianyi) || '')} 地乙${esc((r.shijing && r.shijing.diyi) || '')} 直符${esc((r.shijing && r.shijing.zhifu) || '')}</div>
36331
+ <div class="mp-ty-sec"><em>数和</em>主算 ${esc((r.heshu && r.heshu.zhu && r.heshu.zhu.text) || '')} 客算 ${esc((r.heshu && r.heshu.ke && r.heshu.ke.text) || '')}</div>
36332
+ <div class="mp-ty-sec"><em>月计</em>太乙在 ${esc(monthN)} 宫(第 ${esc(monthU)} 月) 天目 ${esc(monthMu)} 计神 ${esc(monthJs)}</div>
36333
+ <div class="mp-ty-sec"><em>日计</em>太乙在 ${esc(dayN)} 宫(第 ${esc(dayU)} 日) 天目 ${esc(dayMu)} 计神 ${esc(dayJs)}</div>
36334
+ <div class="mp-ty-sec"><em>时计</em>太乙在 ${esc(hourN)} 宫(第 ${esc(hourU)} 时) 计神 ${esc(hourJs)}</div>
36335
+ <div class="mp-ty-sec"><em>吉凶</em><b class="mp-ty-jx ${esc(vdGrade)}">${esc(vdLabel)}</b> ${esc((r.jixiong && r.jixiong.text) || '')}</div>
36336
+ <div class="mp-ty-sec"><em>神将</em>${esc(sjLine)}</div>
36337
+ <div class="mp-ty-sec"><em>计神</em>${esc(js.branch || '')}(${esc(js.god || '')}) <em>始击</em>${esc(sj.pos || '')}(${esc(sj.god || '')},${esc(sj.palaceName || '')}宫)</div>
36338
+ <div class="mp-ty-sec"><em>主算</em>${esc(String(su.zhu || ''))} 主大将${esc(jj.zhuDaName || '')}宫 主参将${esc(jj.zhuCanName || '')}宫</div>
36339
+ <div class="mp-ty-sec"><em>客算</em>${esc(String(su.ke || ''))} 客大将${esc(jj.keDaName || '')}宫 客参将${esc(jj.keCanName || '')}宫</div>
36340
+ <div class="mp-ty-sec"><em>格局</em>${gj.list && gj.list.length ? esc(gj.list.join(';')) : '四将不相犯,没有掩、迫、囚、格、关'}</div>
36341
+ <div class="mp-ty-sec"><em>积年</em>${esc(String(r.meta.jinian || ''))} 残年 ${esc(String(r.meta.rest360 || ''))} ${esc(r.year ? r.year.jiName : '')}${esc(r.year ? String(r.year.jiYear) : '')}年 ${esc(r.year ? r.year.yuanName : '')}第 ${esc(r.year ? String(r.year.yuanYear) : '')} 年</div>
36342
+ <div class="mp-ty-note">算到太乙、八门、文昌、计神、始击、主客算与四将、五种格局;${esc(nc.join('、'))}未收录,盘上不显示。将落中五时只标数不加宫名。</div>
36343
+ </details>
35641
36344
  </section>`;
35642
36345
  };
35643
36346