dsh-metaphysics 0.34.0 → 0.38.2
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.
- package/CHANGELOG.md +103 -3
- package/README.md +342 -309
- package/client.js +1137 -137
- package/docs/assets/dsh-metaphysics-group.png +0 -0
- package/engine/bazi.js +48 -2
- package/engine/classics.js +123 -7
- package/engine/followup.js +58 -0
- package/engine/index.js +54 -15
- package/engine/interpret-knowledge.js +50 -4
- package/engine/interpret-plain.js +46 -3
- package/engine/interpret.js +78 -1
- package/engine/liuyao.js +145 -0
- package/engine/ziwei.js +119 -13
- package/locale/zh.json +1 -1
- package/package.json +16 -14
- package//345/221/275/347/220/206/346/216/222/347/233/230.html +1213 -167
|
@@ -13,59 +13,121 @@
|
|
|
13
13
|
<meta property="og:description" content="八字 / 紫微 / 六爻 / 梅花 / 六壬 / 奇门 / 合盘 / 塔罗。本地计算,不采集数据;口径怎么取、差异在哪里,都能逐字对照。">
|
|
14
14
|
<meta name="twitter:card" content="summary_large_image">
|
|
15
15
|
<style>
|
|
16
|
-
:root{--bg:#
|
|
16
|
+
:root{--bg:#f3eee4;--panel:#fffdf8;--panel2:#f8f3e9;--line:#d6cbb7;--ink:#1a1916;--ink2:#3f3a33;--dim:#6f6a60;--gold:#a72c23;--gold-deep:#7d1f18;--good:#1f6f3f;--bad:#a72c23;--warn:#8a5a00;
|
|
17
|
+
--radius:12px;--shadow:0 1px 2px rgba(35,28,18,.05),0 18px 40px -30px rgba(35,28,18,.42);--ring:0 0 0 3px rgba(167,44,35,.16)}
|
|
17
18
|
/* 深色:跟随系统。只换变量,元素规则一条不改。@media screen 限定 → 打印永远浅色 */
|
|
18
19
|
@media screen and (prefers-color-scheme:dark){
|
|
19
|
-
:root{--bg:#12110d;--panel:#1b1913;--panel2:#221f18;--line:#3c372e;--ink:#e7e2d6;--dim:#9b9488;--gold:#e2755f;--good:#67b98a;--bad:#e2755f;--warn:#d9a052
|
|
20
|
+
:root{--bg:#12110d;--panel:#1b1913;--panel2:#221f18;--line:#3c372e;--ink:#e7e2d6;--ink2:#d5cfc2;--dim:#9b9488;--gold:#e2755f;--gold-deep:#b8503f;--good:#67b98a;--bad:#e2755f;--warn:#d9a052;
|
|
21
|
+
--shadow:0 1px 2px rgba(0,0,0,.5),0 18px 40px -30px rgba(0,0,0,.9);--ring:0 0 0 3px rgba(226,117,95,.2)}
|
|
20
22
|
/* 深色下强调色是浅色,这些实心底上的文字得反过来 */
|
|
21
23
|
.tab.on,.seg button.on,.go{color:#14130f}
|
|
24
|
+
.mb-o.on b,.mb-o.on span,.mb-btn.primary{color:#14130f}
|
|
22
25
|
.err{background:rgba(226,117,95,.14)}
|
|
23
26
|
}
|
|
24
27
|
*{box-sizing:border-box}
|
|
25
28
|
html{-webkit-text-size-adjust:100%}
|
|
26
|
-
body{margin:0;
|
|
29
|
+
body{margin:0;color:var(--ink);font:16px/1.65 "Microsoft YaHei","PingFang SC",system-ui,sans-serif;padding-bottom:env(safe-area-inset-bottom);
|
|
30
|
+
background:
|
|
31
|
+
radial-gradient(900px 460px at 14% -160px,color-mix(in srgb,var(--gold) 9%,transparent),transparent 68%),
|
|
32
|
+
radial-gradient(760px 420px at 96% -120px,color-mix(in srgb,var(--good) 7%,transparent),transparent 72%),
|
|
33
|
+
var(--bg);
|
|
34
|
+
-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
|
|
35
|
+
::selection{background:color-mix(in srgb,var(--gold) 24%,transparent)}
|
|
36
|
+
:where(button,input,select,textarea,a,summary):focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:6px}
|
|
27
37
|
.wrap{max-width:1180px;margin:0 auto;padding:22px 26px 60px}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
.brand
|
|
31
|
-
.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
.
|
|
35
|
-
.
|
|
38
|
+
/* 抬头竖排:品牌在上,tab 条独占一行。19 个 tab 横排在品牌右侧会把末行挤成「起名 人格」孤零零两个 */
|
|
39
|
+
header{display:flex;flex-direction:column;align-items:stretch;gap:12px;margin-bottom:18px;padding-bottom:14px;border-bottom:1px solid var(--line)}
|
|
40
|
+
.brand{display:flex;align-items:center;gap:12px;font-size:22px;font-weight:700;letter-spacing:.14em;color:var(--gold);line-height:1.3}
|
|
41
|
+
.brand .seal{display:inline-flex;align-items:center;justify-content:center;flex:none;width:40px;height:40px;border-radius:11px;
|
|
42
|
+
background:linear-gradient(145deg,var(--gold),var(--gold-deep));color:#fff;font:700 20px/1 "Songti SC","SimSun",serif;letter-spacing:0;
|
|
43
|
+
box-shadow:inset 0 0 0 1px rgba(255,255,255,.22),0 8px 18px -10px var(--gold)}
|
|
44
|
+
.brand-txt{display:block;min-width:0}
|
|
45
|
+
.brand-txt small{display:block;font-size:12.5px;letter-spacing:.02em;color:var(--dim);font-weight:400;margin-top:3px}
|
|
46
|
+
.ver{display:inline-block;margin-left:8px;vertical-align:3px;padding:2px 8px;border:1px solid var(--line);border-radius:999px;background:var(--panel2);
|
|
47
|
+
color:var(--dim);font:600 11px/1.5 system-ui,sans-serif;letter-spacing:.04em}
|
|
48
|
+
/* 等宽网格铺满一行:每格同宽、末行左对齐,不会出现右对齐造成的锯齿缺口 */
|
|
49
|
+
.tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(74px,1fr));grid-auto-rows:minmax(36px,auto);gap:6px}
|
|
50
|
+
.tab{display:flex;align-items:center;justify-content:center;text-align:center;padding:7px 10px;border-radius:999px;border:1px solid transparent;background:color-mix(in srgb,var(--panel) 62%,transparent);color:var(--dim);cursor:pointer;font-size:13.5px;font-family:inherit;white-space:nowrap;
|
|
51
|
+
transition:background .16s ease,color .16s ease,border-color .16s ease,box-shadow .16s ease}
|
|
52
|
+
.tab:hover{background:var(--panel);border-color:var(--line);color:var(--ink)}
|
|
53
|
+
.tab.on{background:linear-gradient(145deg,var(--gold),var(--gold-deep));border-color:transparent;color:#fff;font-weight:600;box-shadow:0 8px 18px -12px var(--gold)}
|
|
54
|
+
.bar{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px 14px;align-items:start;padding:18px 20px;margin-bottom:20px;
|
|
55
|
+
background:linear-gradient(180deg,var(--panel),color-mix(in srgb,var(--panel) 90%,var(--bg)));border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow)}
|
|
36
56
|
.grp{display:contents}
|
|
37
|
-
.field{display:flex;flex-direction:column;gap:6px;font-size:
|
|
57
|
+
.field{display:flex;flex-direction:column;gap:6px;font-size:12.5px;letter-spacing:.03em;color:var(--dim)}
|
|
38
58
|
/* 固定宽度而非 min-width:输入控件的默认固有宽度(20 字符)会把 1180px 下的单行输入区挤到换行 */
|
|
39
|
-
.field input,.field select{background:var(--panel2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:8px 12px;font-size:15px;font-family:inherit;outline:none;width:150px
|
|
59
|
+
.field input,.field select{background:var(--panel2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:8px 12px;font-size:15px;font-family:inherit;outline:none;width:150px;
|
|
60
|
+
transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}
|
|
61
|
+
.field input:hover,.field select:hover,.field textarea:hover{border-color:color-mix(in srgb,var(--line) 55%,var(--gold))}
|
|
40
62
|
#addr{width:178px}
|
|
41
63
|
#mh-num input{width:124px}
|
|
42
64
|
#changing{width:132px}
|
|
43
|
-
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--gold)}
|
|
65
|
+
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--gold);box-shadow:var(--ring);background:var(--panel)}
|
|
44
66
|
.field.check{flex-direction:row;align-items:center;gap:8px;padding-bottom:8px}
|
|
45
67
|
/* 所问之事:多行文本,样式与输入框一致;整组可伸缩,空间不足时自动换行独占一行 */
|
|
46
68
|
.field textarea{background:var(--panel2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:8px 12px;font-size:15px;font-family:inherit;line-height:1.5;outline:none;width:100%;min-width:0;resize:vertical}
|
|
47
69
|
#for-ask{flex:1 1 240px;min-width:0}
|
|
48
70
|
#ask-wrap{flex:1 1 auto;min-width:0}
|
|
71
|
+
/* 人格问卷:与日期/时刻无关,整行独占;4 题一页,1–5 单选。
|
|
72
|
+
题目由 web-ui 从引擎取,页面只放容器与进度/翻页骨架 */
|
|
73
|
+
#for-mbti{grid-column:1/-1}
|
|
74
|
+
#for-mbti>.field{width:100%}
|
|
75
|
+
.mb-top{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
|
|
76
|
+
.mb-prog{flex:1 1 180px;min-width:120px;height:6px;border:1px solid var(--line);border-radius:999px;background:var(--panel2);overflow:hidden}
|
|
77
|
+
.mb-prog i{display:block;height:100%;width:0;border-radius:999px;background:linear-gradient(90deg,var(--gold),var(--gold-deep));transition:width .18s ease}
|
|
78
|
+
.mb-count{font-size:12.5px;color:var(--dim);font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
79
|
+
.mb-qs{display:flex;flex-direction:column;gap:10px;margin-top:12px}
|
|
80
|
+
.mb-q{padding:12px 14px;border:1px solid var(--line);border-radius:12px;background:color-mix(in srgb,var(--panel) 72%,transparent)}
|
|
81
|
+
.mb-qt{display:flex;gap:10px;align-items:baseline;font-size:14.5px;line-height:1.6;color:var(--ink)}
|
|
82
|
+
.mb-qt b{flex:none;padding-top:2px;font:600 12px/1 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;letter-spacing:.04em;color:var(--gold)}
|
|
83
|
+
.mb-opts{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:6px;margin-top:10px}
|
|
84
|
+
.mb-o{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:7px 4px;border:1px solid var(--line);border-radius:9px;background:var(--panel2);color:var(--dim);cursor:pointer;text-align:center;
|
|
85
|
+
transition:border-color .14s ease,background .14s ease,color .14s ease,box-shadow .14s ease}
|
|
86
|
+
.mb-o input{position:absolute;inset:0;margin:0;opacity:0;cursor:pointer}
|
|
87
|
+
.mb-o b{font-size:14px;font-weight:600;color:var(--ink2);font-variant-numeric:tabular-nums}
|
|
88
|
+
.mb-o span{font-size:11.5px;line-height:1.3}
|
|
89
|
+
.mb-o:hover{border-color:color-mix(in srgb,var(--line) 40%,var(--gold))}
|
|
90
|
+
.mb-o.on{border-color:transparent;background:linear-gradient(145deg,var(--gold),var(--gold-deep));box-shadow:0 8px 16px -12px var(--gold)}
|
|
91
|
+
.mb-o.on b,.mb-o.on span{color:#fff}
|
|
92
|
+
.mb-o:focus-within{outline:2px solid var(--gold);outline-offset:2px}
|
|
93
|
+
.mb-nav{display:flex;align-items:center;gap:8px;margin-top:12px;flex-wrap:wrap}
|
|
94
|
+
.mb-btn{padding:8px 16px;border-radius:9px;border:1px solid var(--line);background:var(--panel2);color:var(--ink);font-family:inherit;font-size:13.5px;cursor:pointer;
|
|
95
|
+
transition:border-color .14s ease,background .14s ease,color .14s ease}
|
|
96
|
+
.mb-btn:hover:not(:disabled){border-color:var(--gold)}
|
|
97
|
+
.mb-btn:disabled{opacity:.42;cursor:not-allowed}
|
|
98
|
+
.mb-btn.primary{border-color:transparent;background:linear-gradient(145deg,var(--gold),var(--gold-deep));color:#fff;font-weight:600;box-shadow:0 10px 20px -14px var(--gold)}
|
|
99
|
+
.mb-btn.primary:hover:not(:disabled){filter:brightness(1.05)}
|
|
100
|
+
.mb-hint{margin-left:auto;font-size:12.5px;color:var(--dim);line-height:1.6}
|
|
101
|
+
.mb-hint.warn{color:var(--bad);font-weight:600}
|
|
49
102
|
#direction{flex:none;width:104px}
|
|
50
103
|
/* 必填未填:边框转红,提示复用 .err 的口径 */
|
|
51
104
|
.field.invalid textarea{border-color:var(--bad);background:rgba(224,102,95,.06)}
|
|
52
105
|
.field.check input{min-width:0;width:18px;height:18px;accent-color:var(--gold);padding:0}
|
|
53
|
-
.go{margin-left:0;grid-column:4;justify-self:end;align-self:end;padding:
|
|
54
|
-
|
|
55
|
-
.
|
|
106
|
+
.go{margin-left:0;grid-column:4;justify-self:end;align-self:end;padding:11px 24px;border-radius:9px;border:none;color:#fff;font-weight:600;cursor:pointer;font-family:inherit;font-size:15px;
|
|
107
|
+
background:linear-gradient(145deg,var(--gold),var(--gold-deep));box-shadow:0 10px 22px -14px var(--gold),inset 0 1px 0 rgba(255,255,255,.18);
|
|
108
|
+
transition:transform .14s ease,filter .14s ease,box-shadow .14s ease}
|
|
109
|
+
.go:hover{filter:brightness(1.06);transform:translateY(-1px);box-shadow:0 14px 26px -14px var(--gold),inset 0 1px 0 rgba(255,255,255,.22)}
|
|
110
|
+
.go:active{transform:translateY(0);filter:brightness(.98)}
|
|
111
|
+
.go.ghost{grid-column:3;background:transparent;border:1px solid var(--line);color:var(--dim);font-weight:500;margin-right:8px;box-shadow:none;transform:none}
|
|
112
|
+
.go.ghost:hover{background:var(--panel2);color:var(--ink)}
|
|
56
113
|
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
|
|
57
|
-
.chip{font-size:
|
|
58
|
-
.chip.ok{color:var(--good);border-color:
|
|
59
|
-
.chip.warn{color:var(--warn);border-color:
|
|
114
|
+
.chip{font-size:12.5px;padding:4px 11px;border-radius:999px;background:var(--panel2);border:1px solid var(--line);color:var(--dim)}
|
|
115
|
+
.chip.ok{color:var(--good);border-color:color-mix(in srgb,var(--good) 35%,transparent);background:color-mix(in srgb,var(--good) 8%,transparent)}
|
|
116
|
+
.chip.warn{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 35%,transparent);background:color-mix(in srgb,var(--warn) 8%,transparent)}
|
|
60
117
|
.chip.dim{opacity:.6}
|
|
61
118
|
.note{margin-top:10px;font-size:13px;color:var(--dim)}
|
|
62
119
|
.err{margin-top:18px;padding:12px 16px;border-radius:10px;background:rgba(224,102,95,.12);color:var(--bad);font-size:14px}
|
|
63
120
|
/* 注:盘面样式(紫微宫格 .pp-grid / 八字 .pp-bz / 六爻 .mp-hy-row / 梅花 .mp-hexbox / 六壬 .mp-dl-pan2 / 塔罗 .mp-tt-grid)
|
|
64
121
|
全部由 src/panel-kit.js 的 PP.CSS 提供,本文件只保留页面框架样式,不再重复定义旧版盘面类 */
|
|
65
|
-
h3{margin:
|
|
66
|
-
|
|
67
|
-
.seg
|
|
68
|
-
.seg button
|
|
122
|
+
h3{display:flex;align-items:center;gap:10px;margin:22px 0 10px;font-size:15px;font-weight:600;color:var(--gold);letter-spacing:.06em}
|
|
123
|
+
h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--line),transparent)}
|
|
124
|
+
.seg{display:inline-flex;border:1px solid var(--line);border-radius:9px;overflow:hidden;background:var(--panel2)}
|
|
125
|
+
.seg button{padding:7px 14px;background:transparent;border:none;color:var(--dim);font-size:13.5px;font-family:inherit;cursor:pointer;transition:background .14s ease,color .14s ease}
|
|
126
|
+
.seg button:hover{color:var(--ink)}
|
|
127
|
+
.seg button.on{background:linear-gradient(145deg,var(--gold),var(--gold-deep));color:#fff;font-weight:600}
|
|
128
|
+
/* 结果入场:只做一次轻微上浮,不做循环动画 */
|
|
129
|
+
#out{animation:mp-rise .3s cubic-bezier(.2,.7,.3,1) both}
|
|
130
|
+
@keyframes mp-rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
|
|
69
131
|
/* 奇门换局规则:fieldset + 原生 radio(语义优先,外观沿用页面浅色块) */
|
|
70
132
|
.qmrule{grid-column:1 / -1;border:0;margin:0;padding:0;display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px}
|
|
71
133
|
.qmrule legend{padding:0;font-size:13.5px;color:var(--dim)}
|
|
@@ -82,13 +144,17 @@ h3{margin:18px 0 8px;font-size:15px;font-weight:600;color:var(--gold)}
|
|
|
82
144
|
.cast-at{margin:0 0 14px;font-size:13.5px;color:var(--dim);line-height:1.7}
|
|
83
145
|
.cast-at b{color:var(--ink);font-weight:600;letter-spacing:.02em}
|
|
84
146
|
/* 结果区下方:导出/打印 */
|
|
85
|
-
.askbox{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:
|
|
86
|
-
.askbox input{flex:1 1 240px;min-width:0;background:var(--panel2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:8px 12px;font-size:14px;font-family:inherit}
|
|
87
|
-
.askbox
|
|
147
|
+
.askbox{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:16px 0 0;padding:11px 13px;border:1px dashed var(--line);border-radius:10px;background:color-mix(in srgb,var(--panel) 55%,transparent)}
|
|
148
|
+
.askbox input{flex:1 1 240px;min-width:0;background:var(--panel2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:8px 12px;font-size:14px;font-family:inherit;outline:none}
|
|
149
|
+
.askbox input:focus{border-color:var(--gold);box-shadow:var(--ring)}
|
|
150
|
+
.askbox button{padding:8px 14px;border:1px solid transparent;border-radius:8px;background:var(--gold);color:#fff;font:inherit;font-size:13px;cursor:pointer}
|
|
151
|
+
.askbox button:hover{filter:brightness(1.08)}
|
|
88
152
|
.askbox .hint{font-size:12px;color:var(--dim)}
|
|
89
153
|
.method{max-width:860px;margin:0 auto;padding:24px 18px 40px;font-size:14px;line-height:1.9;color:var(--ink2)}
|
|
90
|
-
.method h2{font-size:18px;color:var(--gold);margin:0 0 12px}
|
|
91
|
-
.method h3{font-size:15px;color:var(--ink);margin:18px 0 6px}
|
|
154
|
+
.method h2{font-size:18px;color:var(--gold);margin:0 0 12px;letter-spacing:.05em}
|
|
155
|
+
.method h3{display:block;font-size:15px;color:var(--ink);margin:18px 0 6px;letter-spacing:0}
|
|
156
|
+
.method h3::after{display:none}
|
|
157
|
+
.method a{color:var(--gold);text-decoration-color:color-mix(in srgb,var(--gold) 45%,transparent);text-underline-offset:3px}
|
|
92
158
|
.method ul{margin:6px 0;padding-left:20px}
|
|
93
159
|
.method .note{color:var(--dim);font-size:13px}
|
|
94
160
|
.mp-verify,.mp-rect{margin:14px 0 0;padding:12px;border:1px solid var(--line);border-radius:8px;background:var(--panel)}
|
|
@@ -105,8 +171,9 @@ h3{margin:18px 0 8px;font-size:15px;font-weight:600;color:var(--gold)}
|
|
|
105
171
|
.mp-rect-cand.best{border-left:3px solid var(--gold);color:var(--ink)}
|
|
106
172
|
.mp-rect-err{color:var(--bad);font-size:12.5px}
|
|
107
173
|
.exp{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:14px 0 0}
|
|
108
|
-
.exp button{padding:9px 16px;border-radius:
|
|
109
|
-
.
|
|
174
|
+
.exp button{padding:9px 16px;border-radius:9px;border:1px solid var(--line);background:var(--panel);color:var(--ink);font-family:inherit;font-size:14px;cursor:pointer;
|
|
175
|
+
transition:background .14s ease,border-color .14s ease,transform .14s ease}
|
|
176
|
+
.exp button:hover{background:var(--panel2);border-color:var(--gold);transform:translateY(-1px)}
|
|
110
177
|
.exp .hint{font-size:13px;color:var(--dim)}
|
|
111
178
|
|
|
112
179
|
/* —— 竖屏(≤640px):整页不横向滚动,输入区整行堆叠,盘面交给 panel-kit 的同名媒体查询 —— */
|
|
@@ -115,12 +182,18 @@ h3{margin:18px 0 8px;font-size:15px;font-weight:600;color:var(--gold)}
|
|
|
115
182
|
.wrap{padding:14px 12px 48px}
|
|
116
183
|
header{flex-direction:column;align-items:stretch;gap:10px;margin-bottom:12px}
|
|
117
184
|
header>*{min-width:0}
|
|
118
|
-
|
|
119
|
-
.
|
|
120
|
-
.
|
|
185
|
+
header{gap:10px;padding-bottom:12px}
|
|
186
|
+
.brand{font-size:19px;letter-spacing:.1em}
|
|
187
|
+
.brand .seal{width:34px;height:34px;border-radius:9px;font-size:17px}
|
|
188
|
+
.brand-txt small{font-size:11.5px;line-height:1.5}
|
|
189
|
+
/* 19 个 tab 铺网格要占掉大半个首屏,改成单行横滑:44px 触摸目标、滚动条藏起来、
|
|
190
|
+
左右各留 12px 呼吸位(padding 与 .wrap 等宽,首尾 tab 不会被切口)*/
|
|
191
|
+
.tabs{display:flex;flex-wrap:nowrap;gap:8px;overflow-x:auto;overscroll-behavior-x:contain;
|
|
192
|
+
margin:0 -12px;padding:2px 12px 6px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
|
|
193
|
+
.tabs::-webkit-scrollbar{display:none}
|
|
194
|
+
.tab{flex:0 0 auto;min-height:44px;padding:11px 16px;font-size:14px}
|
|
121
195
|
.bar{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:14px}
|
|
122
|
-
|
|
123
|
-
.field{width:100%}
|
|
196
|
+
.field{width:100%;min-width:0}
|
|
124
197
|
.field input,.field select,.field textarea,#addr,#changing,#direction{width:100%;min-width:0;padding:11px 12px;font-size:16px;min-height:44px}
|
|
125
198
|
#for-ask{flex-direction:column;align-items:stretch}
|
|
126
199
|
.field.check{padding-bottom:0}
|
|
@@ -128,14 +201,28 @@ h3{margin:18px 0 8px;font-size:15px;font-weight:600;color:var(--gold)}
|
|
|
128
201
|
#mh-num input{flex:1 1 30%;width:auto}
|
|
129
202
|
.seg{display:flex;width:100%}
|
|
130
203
|
.seg button{flex:1;padding:12px 8px;min-height:44px}
|
|
131
|
-
|
|
204
|
+
/* 人格问卷:5 个评分格在窄屏会挤成一行细条,缩字号与内边距,按钮整行方便点 */
|
|
205
|
+
.mb-q{padding:11px 12px}
|
|
206
|
+
.mb-qt{font-size:14px}
|
|
207
|
+
.mb-o{padding:8px 3px;min-height:52px}
|
|
208
|
+
.mb-o span{font-size:10.5px}
|
|
209
|
+
.mb-btn{flex:1 1 auto;min-height:44px;padding:10px 12px}
|
|
210
|
+
.mb-hint{flex-basis:100%;margin-left:0}
|
|
211
|
+
/* 两列下把「看示例 / 排盘」并排放:原来写死 grid-column:4 会凭空多出两列 auto 轨道,
|
|
212
|
+
把前两列挤成 134px,性别、按钮全被压扁 */
|
|
213
|
+
.go,.go.ghost{grid-column:auto;justify-self:stretch;margin-left:0;margin-right:0;width:100%;padding:13px;font-size:16px;min-height:48px;border-radius:8px}
|
|
214
|
+
.go.ghost{grid-column:1}
|
|
215
|
+
.go{grid-column:2}
|
|
216
|
+
/* 性别只有一格,留在半幅会空出右边半格;出生地同理,独占一行好填 */
|
|
217
|
+
#for-gender,#for-bazi .field:not(.check){grid-column:1/-1}
|
|
132
218
|
.tip{font-size:13px}
|
|
133
219
|
.tip .auto-note{font-size:13px}
|
|
134
220
|
.cast-at{font-size:13px}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* 动效偏好:系统要求减少动态时,全部关掉(含结果入场) */
|
|
224
|
+
@media (prefers-reduced-motion:reduce){
|
|
225
|
+
*,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;scroll-behavior:auto!important}
|
|
139
226
|
}
|
|
140
227
|
|
|
141
228
|
/* —— 打印 / 存为 PDF ——
|
|
@@ -168,7 +255,7 @@ h3{margin:18px 0 8px;font-size:15px;font-weight:600;color:var(--gold)}
|
|
|
168
255
|
<body>
|
|
169
256
|
<div class="wrap">
|
|
170
257
|
<header>
|
|
171
|
-
<div class="brand">命理排盘<small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></div>
|
|
258
|
+
<div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.38.2</span><small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></span></div>
|
|
172
259
|
<div class="tabs">
|
|
173
260
|
<button class="tab" data-tab="ziwei">紫微</button>
|
|
174
261
|
<button class="tab" data-tab="bazi">八字</button>
|
|
@@ -333,11 +420,24 @@ h3{margin:18px 0 8px;font-size:15px;font-weight:600;color:var(--gold)}
|
|
|
333
420
|
<label class="field" id="fs-advise" style="display:none">坐山<input id="sitting" placeholder="如 子 / 乾" value="子"></label>
|
|
334
421
|
<label class="field" id="fs-advise2" style="display:none">朝向<input id="facing" placeholder="如 午 / 巽" value="午"></label>
|
|
335
422
|
</div>
|
|
423
|
+
<!-- 人格问卷:4 题一页、1–5 打分。题目与 1–5 的说明由 web-ui 从引擎取,
|
|
424
|
+
这里只放容器与翻页骨架,避免题目在页面和引擎里各抄一份 -->
|
|
336
425
|
<div id="for-mbti" style="display:none">
|
|
337
|
-
<
|
|
338
|
-
<
|
|
339
|
-
|
|
340
|
-
|
|
426
|
+
<div class="field">
|
|
427
|
+
<span>十六型人格问卷 · 4 题一页,按 1(完全不像)到 5(很像我)打分</span>
|
|
428
|
+
<div class="mb-top">
|
|
429
|
+
<div class="mb-prog" aria-hidden="true"><i id="mbti-fill"></i></div>
|
|
430
|
+
<span class="mb-count" id="mbti-count">第 1 / 6 页 · 已答 0 / 24</span>
|
|
431
|
+
</div>
|
|
432
|
+
<div class="mb-qs" id="mbti-qs"></div>
|
|
433
|
+
<div class="mb-nav">
|
|
434
|
+
<button type="button" class="mb-btn" id="mbti-prev" disabled>上一页</button>
|
|
435
|
+
<button type="button" class="mb-btn" id="mbti-next">下一页</button>
|
|
436
|
+
<button type="button" class="mb-btn primary" id="mbti-submit" disabled>看结果</button>
|
|
437
|
+
<button type="button" class="mb-btn" id="mbti-clear">清空</button>
|
|
438
|
+
<span class="mb-hint" id="mbti-hint">答满 12 题可先看结果</span>
|
|
439
|
+
</div>
|
|
440
|
+
</div>
|
|
341
441
|
</div>
|
|
342
442
|
<div id="qk-name" style="display:none">
|
|
343
443
|
<div class="field">看什么
|
|
@@ -367,9 +467,9 @@ h3{margin:18px 0 8px;font-size:15px;font-weight:600;color:var(--gold)}
|
|
|
367
467
|
<h3>对拍:把典籍当期望值</h3>
|
|
368
468
|
<ul><li>六爻:京房八宫卦序与世应,64 卦全表;旬空六旬表</li><li>六壬:日干寄宫、中气换将;紫微:纳音定五行局、紫微天府相照</li><li>卦例:《增删卜易》9 条 +《卜筮正宗》128 条(93 成对 + 35 静卦),核本变卦 / 动爻数 / 卦宫 / 缺爻 / 旬空</li></ul>
|
|
369
469
|
<h3>工程验证</h3>
|
|
370
|
-
<ul><li>测试:
|
|
470
|
+
<ul><li>测试:81 个测试文件 / 2832 条断言;七道闸(回归 · 断言基线 · 测试可失败自检 · HTML 注入面 · 工程约定 · 产物宿主形态 · 随机扫射)</li><li>可复现:seed / asOf 显式;同一输入同一输出</li><li>口径:晚子时、真太阳时、奇门三流派、闰月归月都可切换,并有字段级差异对照</li></ul>
|
|
371
471
|
<h3>已知边界(不猜)</h3>
|
|
372
|
-
<ul><li>六爻应期(具体哪天应验)不做;卦例只录动爻个数,不录爻位</li><li>财富/健康只给结构判断与档位,不给金额区间、不作诊断</li><li
|
|
472
|
+
<ul><li>六爻应期(具体哪天应验)不做;卦例只录动爻个数,不录爻位</li><li>财富/健康只给结构判断与档位,不给金额区间、不作诊断</li><li>紫微飞星已做「单一支化逐宫追到成环」与「三方四正 16 条按落宫归堆」,但都未叠大限流年四化、不折吉凶;八字交运日已能算到日/时,但未与第三方排盘案例批量对拍</li></ul>
|
|
373
473
|
<p class="note">内容用于传统文化学习与自我探索,不构成医疗、投资、法律或人事决策依据。</p>
|
|
374
474
|
<button id="method-close" class="go" style="margin-top:12px">收起</button>
|
|
375
475
|
</section>
|
|
@@ -3186,13 +3286,14 @@ return { QT_BRANCHES, QT_MONTHS, QT_BASE_URL, QT_NOTE, QT, qtOf, qtLine };
|
|
|
3186
3286
|
})();
|
|
3187
3287
|
|
|
3188
3288
|
__mods.classics = (function () {
|
|
3189
|
-
//
|
|
3190
|
-
//
|
|
3289
|
+
// 古籍原文库:《子平真诠》《滴天髓》《三命通会》里与「格局取用」「十神喜忌」「寒暖燥湿」直接相关的条目。
|
|
3290
|
+
// 原文照录(公共版权:清·沈孝瞻《子平真诠》、明·京图《滴天髓》、明·万民英《三命通会》通行本),仅供文化研究与参考。
|
|
3191
3291
|
// 出处以中华典藏网在线本为准(逐条给 url),异文处不合并、不改写;plain 是本站自撰白话,不是原文。
|
|
3192
3292
|
|
|
3193
3293
|
const CLASSIC_BOOKS = {
|
|
3194
3294
|
ziping: { name: '子平真诠', author: '清·沈孝瞻', base: 'https://www.diancang.xyz/xuanxuewushu/zipingzhenquan/' },
|
|
3195
3295
|
ditian: { name: '滴天髓', author: '明·京图(通行本)', base: 'https://www.diancang.xyz/xuanxuewushu/ditiansui/' },
|
|
3296
|
+
sanming: { name: '三命通会', author: '明·万民英', base: 'https://www.diancang.xyz/xuanxuewushu/sanmingtonghui/' },
|
|
3196
3297
|
};
|
|
3197
3298
|
|
|
3198
3299
|
const CLASSICS = [
|
|
@@ -3296,6 +3397,26 @@ const CLASSICS = [
|
|
|
3296
3397
|
plain: '月令用神为主,但必须配气候参看;同样的格局,生在得时的气候里事半功倍,逆着气候就费劲。',
|
|
3297
3398
|
url: 'https://www.diancang.xyz/xuanxuewushu/zipingzhenquan/53634.html',
|
|
3298
3399
|
},
|
|
3400
|
+
{
|
|
3401
|
+
id: 'zp-chengbai',
|
|
3402
|
+
book: 'ziping',
|
|
3403
|
+
chapter: '九、论用神成败救应',
|
|
3404
|
+
scene: '格局',
|
|
3405
|
+
tags: [],
|
|
3406
|
+
quote: '成中有败,必是带忌;败中有成,全凭救应。',
|
|
3407
|
+
plain: '成格不等于一路顺:成中带忌(官逢财又逢伤、官被合之类)就打了折;败格也未必无救——印来解伤、合来清煞,败中还能转成。',
|
|
3408
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/zipingzhenquan/53629.html',
|
|
3409
|
+
},
|
|
3410
|
+
{
|
|
3411
|
+
id: 'zp-bianhua',
|
|
3412
|
+
book: 'ziping',
|
|
3413
|
+
chapter: '十、论用神变化',
|
|
3414
|
+
scene: '格局',
|
|
3415
|
+
tags: [],
|
|
3416
|
+
quote: '故若丁生亥月,本为正官,支全卯未,则化为印。己生申月,本属伤官。藏庚透壬,则化为财。凡此之类皆用神之变化也。',
|
|
3417
|
+
plain: '用神本从月令取,但月令藏干不一:丁生亥月本为正官,支会卯未就化为印;己生申月本属伤官,庚藏壬透就化为财。起点相同,合化一变,取用也跟着变(原文只说变化之由,不断定某盘必化)。',
|
|
3418
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/zipingzhenquan/53630.html',
|
|
3419
|
+
},
|
|
3299
3420
|
{
|
|
3300
3421
|
id: 'dt-hannuan',
|
|
3301
3422
|
book: 'ditian',
|
|
@@ -3386,6 +3507,78 @@ const CLASSICS = [
|
|
|
3386
3507
|
plain: '看精神不能偏执一端,要在损益之间求其中。',
|
|
3387
3508
|
url: 'https://www.diancang.xyz/xuanxuewushu/ditiansui/153091.html',
|
|
3388
3509
|
},
|
|
3510
|
+
// —— 三命通会(明·万民英):同一组十神,子平真诠说「怎么用」,三命通会说「怎么取、怕什么」。
|
|
3511
|
+
// 两书并列取用,按同一 tag 各取一条对照读,不合并、不裁定谁对。
|
|
3512
|
+
{
|
|
3513
|
+
id: 'smt-zhenguan',
|
|
3514
|
+
book: 'sanming',
|
|
3515
|
+
chapter: '卷五·论正官',
|
|
3516
|
+
scene: '格局',
|
|
3517
|
+
tags: ['正官'],
|
|
3518
|
+
quote: '正官者,乃甲见辛、乙见庚之例。阴阳配合,相制有用,成其道也。故正官为六格之首,止许一位,多则不宜。',
|
|
3519
|
+
plain: '正官取「克我而阴阳相配」,有制而能成用;六格以正官居首,只宜一位,多见就杂。',
|
|
3520
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/sanmingtonghui/7582.html',
|
|
3521
|
+
},
|
|
3522
|
+
{
|
|
3523
|
+
id: 'smt-zhengcai',
|
|
3524
|
+
book: 'sanming',
|
|
3525
|
+
chapter: '卷六·论正财',
|
|
3526
|
+
scene: '格局',
|
|
3527
|
+
tags: ['财'],
|
|
3528
|
+
quote: '正财者,乃甲见己、乙见戊之例。受我克制,为我之妻,譬人娶妻,妻赍财嫁我,我必精神康强,而后可享用,若衰微不振,虽妻财丰厚,但能目视,终不得用。',
|
|
3529
|
+
plain: '正财是我克制之物,古人以「娶妻带财」作比:自身精神康强才受用得起,身弱不振,财再厚也只是看着。',
|
|
3530
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/sanmingtonghui/7645.html',
|
|
3531
|
+
},
|
|
3532
|
+
{
|
|
3533
|
+
id: 'smt-yinshou',
|
|
3534
|
+
book: 'sanming',
|
|
3535
|
+
chapter: '卷六·论印绶',
|
|
3536
|
+
scene: '格局',
|
|
3537
|
+
tags: ['印'],
|
|
3538
|
+
quote: '印绶者,乃五行生我之名。如甲乙在亥子月,丙丁在寅卯月之类,乃我气之源,为生气,为父母,能护我官星,使无伤克',
|
|
3539
|
+
plain: '印是生我之气,像源头与父母:它能护住官星,使官不受伤克;反过来说,印重就怕财来破。',
|
|
3540
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/sanmingtonghui/7655.html',
|
|
3541
|
+
},
|
|
3542
|
+
{
|
|
3543
|
+
id: 'smt-shishen',
|
|
3544
|
+
book: 'sanming',
|
|
3545
|
+
chapter: '卷六·论食神',
|
|
3546
|
+
scene: '格局',
|
|
3547
|
+
tags: ['食神'],
|
|
3548
|
+
quote: '凡命遇财煞之地,食神旺相,煞被食制,不敢为祸,财被食生,充裕不竭,故食神一名寿星,一名爵星,良有以也。',
|
|
3549
|
+
plain: '食神旺,一头制煞、一头生财:煞被制住不敢为祸,财被生起不至枯竭;所以食神又叫寿星、爵星。',
|
|
3550
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/sanmingtonghui/7663.html',
|
|
3551
|
+
},
|
|
3552
|
+
{
|
|
3553
|
+
id: 'smt-shangguan',
|
|
3554
|
+
book: 'sanming',
|
|
3555
|
+
chapter: '卷六·论伤官',
|
|
3556
|
+
scene: '格局',
|
|
3557
|
+
tags: ['伤官'],
|
|
3558
|
+
quote: '伤官虽凶,乃我所生,自家之物,伤尽则能生财,财旺则能生官,造化展转有情。',
|
|
3559
|
+
plain: '伤官虽称凶,却是我自己生出来的:伤尽(柱中不见官星)反能生财,财旺再生官,辗转还是有情。',
|
|
3560
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/sanmingtonghui/7662.html',
|
|
3561
|
+
},
|
|
3562
|
+
{
|
|
3563
|
+
id: 'smt-yangren',
|
|
3564
|
+
book: 'sanming',
|
|
3565
|
+
chapter: '卷六·论阳刃',
|
|
3566
|
+
scene: '格局',
|
|
3567
|
+
tags: ['阳刃', '劫财'],
|
|
3568
|
+
quote: '阳者,阴阳之阳,刃者,刀刃之刃,即禄前一位,言旺越其分,故险。',
|
|
3569
|
+
plain: '阳刃指禄前一位,旺过了本分,所以险;甲丙戊庚壬五阳干才有刃,阴干见伤官同论。',
|
|
3570
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/sanmingtonghui/7671.html',
|
|
3571
|
+
},
|
|
3572
|
+
{
|
|
3573
|
+
id: 'smt-jianlu',
|
|
3574
|
+
book: 'sanming',
|
|
3575
|
+
chapter: '卷六·论建禄',
|
|
3576
|
+
scene: '格局',
|
|
3577
|
+
tags: ['建禄', '比肩', '月劫'],
|
|
3578
|
+
quote: '凡命月令建禄,难招祖业,必主平生见财不聚,却病少寿长,行运再见比肩,克妻妨父损子',
|
|
3579
|
+
plain: '月令建禄是日主临官之地,身旺而财官难取:古说难承祖业、见财不聚,但病少寿长;再走比肩运,古书说克妻妨父损子(属于旧说的重话,本插件只记原文、不作断语)。',
|
|
3580
|
+
url: 'https://www.diancang.xyz/xuanxuewushu/sanmingtonghui/7672.html',
|
|
3581
|
+
},
|
|
3389
3582
|
];
|
|
3390
3583
|
|
|
3391
3584
|
const BY_ID = CLASSICS.reduce((m, e) => { m[e.id] = e; return m; }, {});
|
|
@@ -3417,8 +3610,19 @@ function tagOf(gejuName) {
|
|
|
3417
3610
|
return GEJU_KEY[bare + '格'] || bare;
|
|
3418
3611
|
}
|
|
3419
3612
|
|
|
3420
|
-
//
|
|
3421
|
-
function
|
|
3613
|
+
// 同一 tag 各书取一条:子平真诠在前(讲怎么用),三命通会紧随作对照(讲怎么取、怕什么)
|
|
3614
|
+
function pick(tag, book) {
|
|
3615
|
+
return CLASSICS.find((e) => e.scene === '格局' && e.tags.includes(tag) && (!book || e.book === book)) || null;
|
|
3616
|
+
}
|
|
3617
|
+
|
|
3618
|
+
// 章节名去掉卷次/序号与开头的「论」,避免 why 里拼成「论论财」
|
|
3619
|
+
function chapterTitle(e) {
|
|
3620
|
+
return e.chapter.replace(/^.*[、·]/, '').replace(/^论/, '');
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3623
|
+
// 根据一张八字结果挑原文:先格局(子平真诠 + 三命通会对照),再调候(寒暖/燥湿),
|
|
3624
|
+
// 最后「用神总纲」一位按盘取:有化气格取论用神变化、见组合取论用神成败救应、其余取通用总纲;去重、限量。
|
|
3625
|
+
function classicsFor(r, limit = 5) {
|
|
3422
3626
|
if (!r) return [];
|
|
3423
3627
|
const out = [];
|
|
3424
3628
|
const seen = new Set();
|
|
@@ -3431,8 +3635,10 @@ function classicsFor(r, limit = 4) {
|
|
|
3431
3635
|
for (const g of gejuList) {
|
|
3432
3636
|
if (!g || (g.kind && g.kind !== '月令格')) continue;
|
|
3433
3637
|
const tag = tagOf(g.name);
|
|
3434
|
-
const
|
|
3435
|
-
if (
|
|
3638
|
+
const primary = pick(tag, 'ziping') || pick(tag);
|
|
3639
|
+
if (primary) push(primary, `你的月令格局是「${g.name}」,故取${CLASSIC_BOOKS[primary.book].name}「${chapterTitle(primary)}」一条`);
|
|
3640
|
+
const alt = CLASSICS.find((e) => e.scene === '格局' && e.tags.includes(tag) && (!primary || e.book !== primary.book));
|
|
3641
|
+
if (alt) push(alt, `同是「${g.name}」,${CLASSIC_BOOKS[alt.book].name}「${chapterTitle(alt)}」另有取法,可对照读`);
|
|
3436
3642
|
}
|
|
3437
3643
|
const cli = r.climate || (r.frame && r.frame.yongshen && (r.frame.yongshen.climate || r.frame.yongshen.tiaohou));
|
|
3438
3644
|
if (cli && cli.kind && cli.kind !== '平和') {
|
|
@@ -3442,7 +3648,17 @@ function classicsFor(r, limit = 4) {
|
|
|
3442
3648
|
push(classicOf('zp-qihou'), '气候与月令用神要互参,故取子平真诠「用神配气候」一条');
|
|
3443
3649
|
if (hot) push(classicOf('dt-hannuan'), '本盘偏热,寒暖一条正对');
|
|
3444
3650
|
}
|
|
3445
|
-
|
|
3651
|
+
// 用神总纲位只放一条:同一个格,化气看「变化」、有组合看「成败救应」,都没有才回到四吉四凶总纲。
|
|
3652
|
+
// 不另加位次,是因为格局两条 + 气候两条正好占满 5 条上限;总纲与具体结构二选一,避免泛论挤掉针对这张盘的话。
|
|
3653
|
+
const huagi = gejuList.find((g) => g && g.kind === '化气格');
|
|
3654
|
+
const combo = gejuList.find((g) => g && g.kind === '组合');
|
|
3655
|
+
if (huagi) {
|
|
3656
|
+
push(classicOf('zp-bianhua'), `本盘列有「${huagi.name}」:用神由月令合化而变,总纲一位改取${CLASSIC_BOOKS.ziping.name}论用神变化`);
|
|
3657
|
+
} else if (combo) {
|
|
3658
|
+
push(classicOf('zp-chengbai'), `本盘另有「${combo.name}」组合:成格还要看带忌与救应,总纲一位改取${CLASSIC_BOOKS.ziping.name}论用神成败救应`);
|
|
3659
|
+
} else {
|
|
3660
|
+
push(classicOf('zp-yongshen'), '用神从月令取、四吉顺用四凶逆用,是通用总纲');
|
|
3661
|
+
}
|
|
3446
3662
|
return out;
|
|
3447
3663
|
}
|
|
3448
3664
|
|
|
@@ -4122,9 +4338,12 @@ function buildBazi(input) {
|
|
|
4122
4338
|
};
|
|
4123
4339
|
|
|
4124
4340
|
const dayun = [];
|
|
4341
|
+
const dayunWindows = [];
|
|
4125
4342
|
for (let i = 1; i <= 8; i++) {
|
|
4126
4343
|
const idx = (((monthIdx + (forward ? i : -i)) % 60) + 60) % 60;
|
|
4127
4344
|
const g = ganzhiName(idx);
|
|
4345
|
+
const fromJd = partsToJd(addYearsClamped(jiaoParts, (i - 1) * 10));
|
|
4346
|
+
const toJd = partsToJd(addYearsClamped(jiaoParts, i * 10));
|
|
4128
4347
|
dayun.push({
|
|
4129
4348
|
step: i,
|
|
4130
4349
|
startAge: startAgeYears + (i - 1) * 10,
|
|
@@ -4134,9 +4353,10 @@ function buildBazi(input) {
|
|
|
4134
4353
|
stemTenGod: tenGod(dayStem, g.stem),
|
|
4135
4354
|
nayin: nayin(idx),
|
|
4136
4355
|
// 这一步大运的起止交运时刻(与摘要/面板同源,可直接拿来对年表)
|
|
4137
|
-
fromDate: formatJd(
|
|
4138
|
-
toDate: formatJd(
|
|
4356
|
+
fromDate: formatJd(fromJd),
|
|
4357
|
+
toDate: formatJd(toJd),
|
|
4139
4358
|
});
|
|
4359
|
+
dayunWindows.push({ step: i, ganzhi: g.name, fromJd, toJd });
|
|
4140
4360
|
}
|
|
4141
4361
|
|
|
4142
4362
|
// 流年(默认从「今年」起排 10 年;传 input.nowYear 可钉死基准年,用于复现历史结论)
|
|
@@ -4289,6 +4509,48 @@ function buildBazi(input) {
|
|
|
4289
4509
|
l.luck = scoreLuck(l.ganzhi, frame);
|
|
4290
4510
|
}
|
|
4291
4511
|
|
|
4512
|
+
// ── 岁运并临 / 伏吟反吟:只标干支层面的「变动信号」,不判吉凶 ──
|
|
4513
|
+
// 流年按立春起算(该年立春到次年立春),当值大运取与这一区间相交的步;
|
|
4514
|
+
// 交运落在这一年里时,前后两步都在本年当过值,两条都列出。
|
|
4515
|
+
const NATAL_LABEL = { year: '年柱', month: '月柱', day: '日柱', hour: '时柱' };
|
|
4516
|
+
const stemOvercomes = (a, b) => OVERCOMES[STEM_ELEMENT[a]] === STEM_ELEMENT[b];
|
|
4517
|
+
const tianKeDiChong = (a, b) => {
|
|
4518
|
+
if (typeof a !== 'string' || typeof b !== 'string' || a.length < 2 || b.length < 2) return false;
|
|
4519
|
+
if (!(a[0] in STEM_ELEMENT) || !(b[0] in STEM_ELEMENT)) return false;
|
|
4520
|
+
return (stemOvercomes(a[0], b[0]) || stemOvercomes(b[0], a[0])) && hasPair(BRANCH_CHONG, a[1], b[1]);
|
|
4521
|
+
};
|
|
4522
|
+
const lichunJd = (y) => {
|
|
4523
|
+
const t = termWindow(y, { jieOnly: true }).find((x) => x.index === 2 && jdToParts(x.jd).year === y);
|
|
4524
|
+
return t ? t.jd : partsToJd({ year: y, month: 2, day: 4 });
|
|
4525
|
+
};
|
|
4526
|
+
for (const l of liunian) {
|
|
4527
|
+
const yStart = lichunJd(l.year);
|
|
4528
|
+
const yEnd = lichunJd(l.year + 1);
|
|
4529
|
+
const active = dayunWindows.filter((w) => w.fromJd < yEnd && w.toJd > yStart);
|
|
4530
|
+
const signals = [];
|
|
4531
|
+
for (const w of active) {
|
|
4532
|
+
if (w.ganzhi === l.ganzhi) {
|
|
4533
|
+
signals.push({ type: '岁运并临', target: `第${w.step}步大运`, detail: `大运与流年同为${l.ganzhi}` });
|
|
4534
|
+
} else if (tianKeDiChong(w.ganzhi, l.ganzhi)) {
|
|
4535
|
+
signals.push({ type: '运年反吟', target: `第${w.step}步大运`, detail: `大运${w.ganzhi}与流年${l.ganzhi}天克地冲` });
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
for (const key of ['year', 'month', 'day', 'hour']) {
|
|
4539
|
+
const g = pillars[key].ganzhi;
|
|
4540
|
+
if (!g) continue;
|
|
4541
|
+
if (l.ganzhi === g) {
|
|
4542
|
+
signals.push({ type: '流年伏吟', target: NATAL_LABEL[key], detail: `流年${l.ganzhi}与${NATAL_LABEL[key]}同干支` });
|
|
4543
|
+
} else if (tianKeDiChong(l.ganzhi, g)) {
|
|
4544
|
+
signals.push({ type: '流年反吟', target: NATAL_LABEL[key], detail: `流年${l.ganzhi}与${NATAL_LABEL[key]}${g}天克地冲` });
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4547
|
+
l.suiyun = {
|
|
4548
|
+
dayun: active.map((w) => ({ step: w.step, ganzhi: w.ganzhi })),
|
|
4549
|
+
signals,
|
|
4550
|
+
note: '只标干支重复与天克地冲这类变动信号,不判吉凶;大运按该年立春到次年立春的区间取,交运落在年内时前后两步并列',
|
|
4551
|
+
};
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4292
4554
|
const p = jdToParts(jd);
|
|
4293
4555
|
|
|
4294
4556
|
// ── 胎元 / 命宫 / 身宫 ──
|
|
@@ -5079,7 +5341,152 @@ function yongshenStrength(result, useGod, opts = {}) {
|
|
|
5079
5341
|
};
|
|
5080
5342
|
}
|
|
5081
5343
|
|
|
5082
|
-
|
|
5344
|
+
// ── 全卦逐爻旺衰:月建日辰落到六爻全部 ──────────────────────────────
|
|
5345
|
+
// 与用神旺衰同一套判定(月令五态、日辰五关系、三种冲法),区别只在不挑用神:
|
|
5346
|
+
// 六爻每一爻都给一次,世应、动爻、旬空另标,看得出整张卦的气压在哪一头。
|
|
5347
|
+
function hexagramStrength(result, opts = {}) {
|
|
5348
|
+
const rows = (result && result.ben && Array.isArray(result.ben.lines))
|
|
5349
|
+
? result.ben.lines
|
|
5350
|
+
: (result && Array.isArray(result.lines) ? result.lines : []);
|
|
5351
|
+
if (!rows.length) return null;
|
|
5352
|
+
const monthBranch = opts.monthBranch || null;
|
|
5353
|
+
const dayBranch = opts.dayBranch || (result.dayGanZhi ? result.dayGanZhi.branch : null);
|
|
5354
|
+
if (!monthBranch && !dayBranch) return null;
|
|
5355
|
+
const monthElement = monthBranch ? zhiElementOf(monthBranch) : null;
|
|
5356
|
+
const dayElement = dayBranch ? zhiElementOf(dayBranch) : null;
|
|
5357
|
+
const kong = Array.isArray(result.xunKong)
|
|
5358
|
+
? result.xunKong
|
|
5359
|
+
: (typeof result.xunKong === 'string' ? result.xunKong.split('') : []);
|
|
5360
|
+
const shiPos = result.ben ? result.ben.shi : null;
|
|
5361
|
+
const yingPos = result.ben ? result.ben.ying : null;
|
|
5362
|
+
|
|
5363
|
+
const lines = rows.map((l) => {
|
|
5364
|
+
const element = l.element || zhiElementOf(l.branch);
|
|
5365
|
+
const monthChong = !!(monthBranch && CHONG_OF[l.branch] === monthBranch);
|
|
5366
|
+
const dayChong = !!(dayBranch && CHONG_OF[l.branch] === dayBranch);
|
|
5367
|
+
const monthState = monthStateOf(element, monthElement);
|
|
5368
|
+
const dayRelation = dayRelationOf(element, dayElement);
|
|
5369
|
+
const isEmpty = kong.includes(l.branch);
|
|
5370
|
+
return {
|
|
5371
|
+
position: l.position,
|
|
5372
|
+
name: l.name,
|
|
5373
|
+
branch: l.branch,
|
|
5374
|
+
element,
|
|
5375
|
+
liuqin: l.liuqin ?? null,
|
|
5376
|
+
shi: l.position === shiPos,
|
|
5377
|
+
ying: l.position === yingPos,
|
|
5378
|
+
moving: !!l.moving,
|
|
5379
|
+
kong: isEmpty,
|
|
5380
|
+
monthState,
|
|
5381
|
+
monthSay: MONTH_STATE_SAY[monthState] || '',
|
|
5382
|
+
monthChong,
|
|
5383
|
+
dayRelation,
|
|
5384
|
+
daySay: DAY_RELATION_SAY[dayRelation] || '',
|
|
5385
|
+
dayChong,
|
|
5386
|
+
chongTag: monthChong ? '月破'
|
|
5387
|
+
: dayChong ? (isEmpty ? '冲空' : (l.moving ? '逢日辰冲' : '暗动')) : '',
|
|
5388
|
+
};
|
|
5389
|
+
});
|
|
5390
|
+
|
|
5391
|
+
const counts = {};
|
|
5392
|
+
for (const st of MONTH_STATE_ORDER) counts[st] = lines.filter((l) => l.monthState === st).length;
|
|
5393
|
+
|
|
5394
|
+
const labels = [];
|
|
5395
|
+
for (const st of MONTH_STATE_ORDER) if (counts[st]) labels.push(`全卦${st}${counts[st]}爻`);
|
|
5396
|
+
const shiLine = lines.find((l) => l.shi) || null;
|
|
5397
|
+
const yingLine = lines.find((l) => l.ying) || null;
|
|
5398
|
+
if (shiLine && shiLine.monthState !== 'unknown') labels.push(`世爻月建${shiLine.monthState}`);
|
|
5399
|
+
if (yingLine && yingLine.monthState !== 'unknown') labels.push(`应爻月建${yingLine.monthState}`);
|
|
5400
|
+
const tagCount = (tag) => lines.filter((l) => l.chongTag === tag).length;
|
|
5401
|
+
for (const tag of ['月破', '暗动', '冲空', '逢日辰冲']) {
|
|
5402
|
+
const n = tagCount(tag);
|
|
5403
|
+
if (n) labels.push(`${tag}${n}爻`);
|
|
5404
|
+
}
|
|
5405
|
+
|
|
5406
|
+
return {
|
|
5407
|
+
month: monthBranch ? { branch: monthBranch, element: monthElement } : null,
|
|
5408
|
+
day: dayBranch ? { branch: dayBranch, element: dayElement } : null,
|
|
5409
|
+
lines,
|
|
5410
|
+
counts,
|
|
5411
|
+
strongest: lines.filter((l) => l.monthState === '旺').map((l) => l.position),
|
|
5412
|
+
weakest: lines.filter((l) => l.monthState === '死' || l.monthChong).map((l) => l.position),
|
|
5413
|
+
shi: shiLine ? { position: shiLine.position, branch: shiLine.branch, monthState: shiLine.monthState, dayRelation: shiLine.dayRelation } : null,
|
|
5414
|
+
ying: yingLine ? { position: yingLine.position, branch: yingLine.branch, monthState: yingLine.monthState, dayRelation: yingLine.dayRelation } : null,
|
|
5415
|
+
labels,
|
|
5416
|
+
note: '月建主这一段的旺衰、日辰管当天的扶克,六爻逐一给状态;判定与用神旺衰同一套,只多了世应与动爻标记。只报状态、不折分数,也不单独断吉凶。',
|
|
5417
|
+
};
|
|
5418
|
+
}
|
|
5419
|
+
|
|
5420
|
+
// ── 化进 / 化退的力重:进退只管方向,走不走得动看时令 ─────────────────
|
|
5421
|
+
// 化进只说明这一爻顺着往前走一步,能不能走实要放回月建日辰:
|
|
5422
|
+
// 得令(旺/相)化进 → 后劲足;休/囚化进 → 后劲有限;逢死 → 进得虚
|
|
5423
|
+
// 得令化退 → 退得缓(时令还托着,退得慢);失令化退 → 退得实
|
|
5424
|
+
// 月破压过一切:爻遭月建冲,进退都站不稳,先看出空填实。
|
|
5425
|
+
// 旬空只标出来、不并进结论——动爻旬空要等出空才算数。
|
|
5426
|
+
// 《增删卜易》进神退神章讲「化进神须得日月生扶」,这里只做这一步,不叠动变连环。
|
|
5427
|
+
const JIN_VERDICT = { 旺: '后劲足', 相: '后劲足', 休: '后劲有限', 囚: '后劲有限', 死: '进得虚' };
|
|
5428
|
+
const TUI_VERDICT = { 旺: '退得缓', 相: '退得缓', 休: '退得实', 囚: '退得实', 死: '退得实' };
|
|
5429
|
+
|
|
5430
|
+
/**
|
|
5431
|
+
* 化进 / 化退的力重:把 body.jinTui 每一条放回月建日辰结算。
|
|
5432
|
+
* @param {object} result buildLiuyao 的结果(需带 body.jinTui)
|
|
5433
|
+
* @param {{monthBranch?: string, dayBranch?: string}} opts
|
|
5434
|
+
*/
|
|
5435
|
+
function jinTuiPower(result, opts = {}) {
|
|
5436
|
+
const items = result && result.body && Array.isArray(result.body.jinTui) ? result.body.jinTui : [];
|
|
5437
|
+
if (!items.length) return null;
|
|
5438
|
+
const rows = result && result.ben && Array.isArray(result.ben.lines) ? result.ben.lines : [];
|
|
5439
|
+
const monthBranch = opts.monthBranch || null;
|
|
5440
|
+
const dayBranch = opts.dayBranch || (result && result.dayGanZhi ? result.dayGanZhi.branch : null);
|
|
5441
|
+
const monthElement = monthBranch ? zhiElementOf(monthBranch) : null;
|
|
5442
|
+
const dayElement = dayBranch ? zhiElementOf(dayBranch) : null;
|
|
5443
|
+
const kong = Array.isArray(result && result.xunKong)
|
|
5444
|
+
? result.xunKong
|
|
5445
|
+
: (result && typeof result.xunKong === 'string' ? result.xunKong.split('') : []);
|
|
5446
|
+
|
|
5447
|
+
const lines = items.map((x) => {
|
|
5448
|
+
const line = rows[x.position - 1] || null;
|
|
5449
|
+
const element = (line && line.element) || zhiElementOf(x.from);
|
|
5450
|
+
const monthState = monthStateOf(element, monthElement);
|
|
5451
|
+
const monthChong = !!(monthBranch && CHONG_OF[x.from] === monthBranch);
|
|
5452
|
+
const dayChong = !!(dayBranch && CHONG_OF[x.from] === dayBranch);
|
|
5453
|
+
const dayRelation = dayRelationOf(element, dayElement);
|
|
5454
|
+
const isEmpty = kong.includes(x.from);
|
|
5455
|
+
// 判定顺序:无月建只报趋势 → 月破压过一切 → 按五态给进退定档
|
|
5456
|
+
const verdict = !monthBranch ? '只报趋势'
|
|
5457
|
+
: monthChong ? '月破失据'
|
|
5458
|
+
: ((x.type === '进' ? JIN_VERDICT : TUI_VERDICT)[monthState] || '未定');
|
|
5459
|
+
const monthSay = monthBranch
|
|
5460
|
+
? `月建${monthBranch}(${monthElement})对${element}为${monthState}`
|
|
5461
|
+
: '缺月建,只看日辰';
|
|
5462
|
+
const daySay = dayRelation === 'unknown' ? '' : `日辰${dayBranch}(${dayElement})${dayRelation}`;
|
|
5463
|
+
const extra = [monthChong ? '又遭月破' : '', isEmpty ? '旬空待填' : '', dayChong ? '逢日辰冲' : ''].filter(Boolean);
|
|
5464
|
+
return {
|
|
5465
|
+
position: x.position,
|
|
5466
|
+
from: x.from,
|
|
5467
|
+
to: x.to,
|
|
5468
|
+
type: x.type,
|
|
5469
|
+
element,
|
|
5470
|
+
monthState,
|
|
5471
|
+
monthChong,
|
|
5472
|
+
dayRelation,
|
|
5473
|
+
dayChong,
|
|
5474
|
+
kong: isEmpty,
|
|
5475
|
+
verdict,
|
|
5476
|
+
say: `${x.from}→${x.to}(${x.type}):${monthSay}${daySay ? `,${daySay}` : ''}${extra.length ? `,${extra.join('、')}` : ''} → ${verdict}`,
|
|
5477
|
+
};
|
|
5478
|
+
});
|
|
5479
|
+
|
|
5480
|
+
return {
|
|
5481
|
+
month: monthBranch ? { branch: monthBranch, element: monthElement } : null,
|
|
5482
|
+
day: dayBranch ? { branch: dayBranch, element: dayElement } : null,
|
|
5483
|
+
lines,
|
|
5484
|
+
labels: lines.map((l) => `${l.position}爻化${l.type}·${l.verdict}`),
|
|
5485
|
+
note: '进退只说这一爻往哪边走;力重是把它放回月建日辰,看有没有托着——得令则进得动、退得慢,失令则进得虚、退得实,月破压过一切。仍不直接定吉凶:用神化进为喜,忌神化进反而是忌。',
|
|
5486
|
+
};
|
|
5487
|
+
}
|
|
5488
|
+
|
|
5489
|
+
return { jinTuiOf, hexBody, bodyRelations, bodyLabels, HEXAGRAM_COUNT, hexagramFromBits, YONGSHEN_RULES, yongshenOf, tossLines, buildLiuyao, zhiElementOf, monthStateOf, dayRelationOf, yongshenStrength, hexagramStrength, jinTuiPower };
|
|
5083
5490
|
})();
|
|
5084
5491
|
|
|
5085
5492
|
__mods.ziwei = (function () {
|
|
@@ -5603,6 +6010,7 @@ function buildZiwei(input) {
|
|
|
5603
6010
|
shensha: '长生、博士随大限顺逆;将前、岁前恒顺行;天伤恒在交友、天使恒在疾厄',
|
|
5604
6011
|
masters: '命主按命宫地支,身主按生年地支',
|
|
5605
6012
|
liunian: '流年命宫取该年地支宫;三方四正为本宫与 +4/+8/+6;并给该年所属大限与小限',
|
|
6013
|
+
flyComposite: '三方四正取本宫、对宫与两个三合宫共四宫,四宫宫干各化禄权科忌共 16 条,按落宫归堆标会聚(双忌会、禄忌同宫、三化会、自化);只描会照,不折吉凶',
|
|
5606
6014
|
changqu: '昌曲落宫只由时支决定,故与丑未的关系(夹/三合/同宫/无关)是结构性结论;absorb 的「清/杂」是启发式标记,依据昌曲化忌与会煞,不是断语',
|
|
5607
6015
|
},
|
|
5608
6016
|
};
|
|
@@ -5611,14 +6019,16 @@ function buildZiwei(input) {
|
|
|
5611
6019
|
chart.daxianList = daxianList(chart);
|
|
5612
6020
|
chart.fly = flyStars(chart);
|
|
5613
6021
|
chart.flyChains = flyChains(chart, { from: '命宫' });
|
|
6022
|
+
chart.flyComposite = flyComposite(chart, { from: '命宫' });
|
|
5614
6023
|
enrichLiunian(chart);
|
|
5615
6024
|
// 流月/流日/流时:默认按本机当前时刻,可用 asOf 指定(如 "2026-10-22T16:00")
|
|
5616
6025
|
chart.flow = flowOf(chart, input.asOf);
|
|
5617
6026
|
chart.patternSummary = {
|
|
5618
6027
|
count: chart.patterns.length,
|
|
5619
6028
|
good: chart.patterns.filter((p) => p.tone === 'good').map((p) => p.name),
|
|
6029
|
+
neutral: chart.patterns.filter((p) => p.tone === 'neutral').map((p) => p.name),
|
|
5620
6030
|
bad: chart.patterns.filter((p) => p.tone === 'bad').map((p) => p.name),
|
|
5621
|
-
note: '
|
|
6031
|
+
note: '格局只描述结构,不作吉凶断语;同一命盘可并存吉格、中性结构与忌格',
|
|
5622
6032
|
};
|
|
5623
6033
|
return chart;
|
|
5624
6034
|
}
|
|
@@ -5660,19 +6070,18 @@ function detectPatterns(chart) {
|
|
|
5660
6070
|
|
|
5661
6071
|
const lu = starBranchOf(chart, '禄存');
|
|
5662
6072
|
const ma = starBranchOf(chart, '天马');
|
|
5663
|
-
if (lu >= 0 && ma >= 0 && (lu === ma || fix(lu - ma) === 6)) add('禄马交驰', `禄存在${
|
|
6073
|
+
if (lu >= 0 && ma >= 0 && (lu === ma || fix(lu - ma) === 6)) add('禄马交驰', `禄存在${BRANCHES[lu]},天马在${BRANCHES[ma]}`);
|
|
5664
6074
|
|
|
5665
6075
|
const huo = starBranchOf(chart, '火星');
|
|
5666
6076
|
const ling = starBranchOf(chart, '铃星');
|
|
5667
6077
|
if (fix(soulIdx - 1) === huo && fix(soulIdx + 1) === ling) add('火铃夹命', '火星在命宫前一宫、铃星在后一宫夹命');
|
|
5668
6078
|
if (fix(soulIdx - 1) === ling && fix(soulIdx + 1) === huo) add('火铃夹命', '铃星与火星夹命');
|
|
5669
6079
|
|
|
6080
|
+
// 擎羊在禄存 +1、陀罗在禄存 -1,两星只能夹「禄存」那一宫;
|
|
6081
|
+
// 所以「羊陀夹忌」实际就是化忌与禄存同宫,按左右两侧去找永远找不到。
|
|
5670
6082
|
const ji = chart.palaces.find((p) => p.stars.some((s) => s.mutagen === '忌'));
|
|
5671
|
-
if (ji) {
|
|
5672
|
-
|
|
5673
|
-
if (fix(jb - 1) === starBranchOf(chart, '擎羊') && fix(jb + 1) === starBranchOf(chart, '陀罗')) {
|
|
5674
|
-
add('羊陀夹忌', `化忌在${ji.branch},擎羊陀罗夹之`);
|
|
5675
|
-
}
|
|
6083
|
+
if (ji && lu >= 0 && BRANCHES.indexOf(ji.branch) === lu) {
|
|
6084
|
+
add('羊陀夹忌', `化忌与禄存在${ji.branch}同宫,擎羊陀罗夹之`);
|
|
5676
6085
|
}
|
|
5677
6086
|
|
|
5678
6087
|
// 铃昌陀武:四星会于命宫三方四正
|
|
@@ -5690,10 +6099,14 @@ function detectPatterns(chart) {
|
|
|
5690
6099
|
// ── 以下为扩展格局(条件都是星位判断,evidence 写明落在哪宫)──
|
|
5691
6100
|
const inSoul = (name) => soul.stars.some((s) => s.name === name);
|
|
5692
6101
|
const nearStar = (name) => near.has(name);
|
|
6102
|
+
// 「夹」只要求两星分居命宫前后,不分左右——日月、左右、魁钺本来就没有固定左右;
|
|
6103
|
+
// 旧写法只认一种顺序,昌曲夹命与羊陀夹命因此从未命中,日月/左右/魁钺也漏掉一半。
|
|
5693
6104
|
const jia = (a, b) => {
|
|
5694
6105
|
const ba = starBranchOf(chart, a);
|
|
5695
6106
|
const bb = starBranchOf(chart, b);
|
|
5696
|
-
|
|
6107
|
+
if (ba < 0 || bb < 0) return false;
|
|
6108
|
+
return (fix(ba + 1) === soulIdx && fix(bb - 1) === soulIdx)
|
|
6109
|
+
|| (fix(bb + 1) === soulIdx && fix(ba - 1) === soulIdx);
|
|
5697
6110
|
};
|
|
5698
6111
|
const mutagensIn = (indices) => {
|
|
5699
6112
|
const set = new Set();
|
|
@@ -5727,7 +6140,7 @@ function detectPatterns(chart) {
|
|
|
5727
6140
|
if (jia('左辅', '右弼')) add('左右夹命', '左辅、右弼夹命宫');
|
|
5728
6141
|
if (jia('文昌', '文曲')) add('昌曲夹命', '文昌、文曲夹命宫');
|
|
5729
6142
|
if (jia('天魁', '天钺')) add('魁钺夹命', '天魁、天钺夹命宫');
|
|
5730
|
-
if (jia('擎羊', '陀罗')) add('羊陀夹命',
|
|
6143
|
+
if (jia('擎羊', '陀罗')) add('羊陀夹命', `禄存在${BRANCHES[soulIdx]}守命,擎羊陀罗前后夹之`);
|
|
5731
6144
|
|
|
5732
6145
|
// 四化
|
|
5733
6146
|
const muts = mutagensIn(sanfang);
|
|
@@ -5742,9 +6155,13 @@ function detectPatterns(chart) {
|
|
|
5742
6155
|
const lianzhen = starBranchOf(chart, '廉贞');
|
|
5743
6156
|
const tianxiang = starBranchOf(chart, '天相');
|
|
5744
6157
|
const qingyang = starBranchOf(chart, '擎羊');
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
6158
|
+
// 天相与廉贞永远隔偶数宫,字面上的「廉贞、擎羊夹天相」不可能成立;
|
|
6159
|
+
// 通行说法取「廉贞天相同守命宫于子午、擎羊同宫」——判的是守命那一宫,其它宫位同宫不算。
|
|
6160
|
+
// 命宫卯酉、廉贞天相对照遇擎羊的变体未纳入。
|
|
6161
|
+
if (lianzhen >= 0 && tianxiang >= 0 && qingyang >= 0
|
|
6162
|
+
&& lianzhen === tianxiang && qingyang === tianxiang && tianxiang === soulIdx
|
|
6163
|
+
&& (tianxiang === 0 || tianxiang === 6)) {
|
|
6164
|
+
add('刑囚夹印', `廉贞天相同守命宫${BRANCHES[tianxiang]},擎羊同宫`);
|
|
5748
6165
|
}
|
|
5749
6166
|
if (near.has('贪狼') && (near.has('火星') || near.has('铃星'))) {
|
|
5750
6167
|
add('火贪铃贪', `贪狼与${near.has('火星') ? '火星' : '铃星'}会于命宫三方四正`);
|
|
@@ -5880,6 +6297,102 @@ function flyChains(chart, { from = '命宫', maxSteps = 12 } = {}) {
|
|
|
5880
6297
|
return out;
|
|
5881
6298
|
}
|
|
5882
6299
|
|
|
6300
|
+
// ── 三方四正复合飞化:四宫一起飞、看落到同一宫的会聚 ─────────────────
|
|
6301
|
+
// 单宫飞化回答「这一宫自己去找谁」;三方四正看的是本宫连同对宫、两个三合宫
|
|
6302
|
+
// 四股力同时飞出去,最后在哪一宫会到一起。会在一处的化越多,那一宫被牵动的力道越集中。
|
|
6303
|
+
// 只归堆与标会照,不折吉凶:同样是双忌会一宫,落在生年忌和落在生年禄上意思完全不同。
|
|
6304
|
+
const PALACE_SUFFIX = (p) => `${p}${String(p).endsWith('宫') ? '' : '宫'}`;
|
|
6305
|
+
|
|
6306
|
+
function flyComposite(chart, { from = '命宫' } = {}) {
|
|
6307
|
+
const palaces = chart.palaces || [];
|
|
6308
|
+
const src = palaces.find((p) => p.palace === from) || palaces[0];
|
|
6309
|
+
if (!src) return null;
|
|
6310
|
+
const names = Array.isArray(src.sanfang) && src.sanfang.length
|
|
6311
|
+
? [...new Set(src.sanfang)].slice(0, 4)
|
|
6312
|
+
: [src.palace];
|
|
6313
|
+
|
|
6314
|
+
const sources = [];
|
|
6315
|
+
for (const name of names) {
|
|
6316
|
+
const p = palaces.find((x) => x.palace === name);
|
|
6317
|
+
if (!p) continue;
|
|
6318
|
+
sources.push({
|
|
6319
|
+
palace: p.palace,
|
|
6320
|
+
branch: p.branch,
|
|
6321
|
+
stem: p.stem,
|
|
6322
|
+
flies: FLY_TYPES.map((type) => {
|
|
6323
|
+
const star = flyStarOf(p.stem, type);
|
|
6324
|
+
const b = star ? starBranchOf(chart, star) : -1;
|
|
6325
|
+
const target = b >= 0 ? palaces.find((x) => x.branch === BRANCHES[b]) : null;
|
|
6326
|
+
return {
|
|
6327
|
+
type,
|
|
6328
|
+
star,
|
|
6329
|
+
to: target ? target.palace : null,
|
|
6330
|
+
toBranch: target ? target.branch : null,
|
|
6331
|
+
self: !!(target && target.palace === p.palace),
|
|
6332
|
+
};
|
|
6333
|
+
}),
|
|
6334
|
+
});
|
|
6335
|
+
}
|
|
6336
|
+
|
|
6337
|
+
// 16 条飞化按落宫归堆;未上盘的星不计入落点
|
|
6338
|
+
const targets = [];
|
|
6339
|
+
for (const p of palaces) {
|
|
6340
|
+
const incoming = [];
|
|
6341
|
+
for (const s of sources) {
|
|
6342
|
+
for (const f of s.flies) {
|
|
6343
|
+
if (f.to === p.palace) {
|
|
6344
|
+
incoming.push({ from: s.palace, fromBranch: s.branch, fromStem: s.stem, type: f.type, star: f.star, self: f.self });
|
|
6345
|
+
}
|
|
6346
|
+
}
|
|
6347
|
+
}
|
|
6348
|
+
if (!incoming.length) continue;
|
|
6349
|
+
targets.push({
|
|
6350
|
+
palace: p.palace,
|
|
6351
|
+
branch: p.branch,
|
|
6352
|
+
incoming,
|
|
6353
|
+
types: [...new Set(incoming.map((x) => x.type))],
|
|
6354
|
+
count: incoming.length,
|
|
6355
|
+
});
|
|
6356
|
+
}
|
|
6357
|
+
targets.sort((a, b) => b.count - a.count || BRANCHES.indexOf(a.branch) - BRANCHES.indexOf(b.branch));
|
|
6358
|
+
|
|
6359
|
+
const jiAt = (t) => t.incoming.filter((x) => x.type === '忌').length;
|
|
6360
|
+
const groups = {
|
|
6361
|
+
doubleJi: targets.filter((t) => jiAt(t) >= 2),
|
|
6362
|
+
luJi: targets.filter((t) => t.types.includes('禄') && t.types.includes('忌')),
|
|
6363
|
+
tripleHua: targets.filter((t) => t.types.length >= 3),
|
|
6364
|
+
selfHua: targets.filter((t) => t.incoming.some((x) => x.self)),
|
|
6365
|
+
};
|
|
6366
|
+
|
|
6367
|
+
const labels = [];
|
|
6368
|
+
for (const t of groups.doubleJi) labels.push(`${['', '', '双忌', '三忌', '四忌'][jiAt(t)] || `${jiAt(t)}忌`}会${PALACE_SUFFIX(t.palace)}`);
|
|
6369
|
+
for (const t of groups.luJi) labels.push(`禄忌同宫${PALACE_SUFFIX(t.palace)}`);
|
|
6370
|
+
const HUA_NUM = { 3: '三化会', 4: '四化会' };
|
|
6371
|
+
for (const t of groups.tripleHua) labels.push(`${HUA_NUM[t.types.length] || `${t.types.length}化会`}${PALACE_SUFFIX(t.palace)}`);
|
|
6372
|
+
for (const t of groups.selfHua) labels.push(`${PALACE_SUFFIX(t.palace)}自化`);
|
|
6373
|
+
|
|
6374
|
+
const byType = {};
|
|
6375
|
+
for (const type of FLY_TYPES) {
|
|
6376
|
+
byType[type] = sources
|
|
6377
|
+
.map((s) => {
|
|
6378
|
+
const f = s.flies.find((x) => x.type === type);
|
|
6379
|
+
return f && f.to ? { from: s.palace, star: f.star, to: f.to, self: f.self } : null;
|
|
6380
|
+
})
|
|
6381
|
+
.filter(Boolean);
|
|
6382
|
+
}
|
|
6383
|
+
|
|
6384
|
+
return {
|
|
6385
|
+
from: src.palace,
|
|
6386
|
+
sanfang: sources.map((s) => s.palace),
|
|
6387
|
+
sources,
|
|
6388
|
+
targets,
|
|
6389
|
+
groups,
|
|
6390
|
+
byType,
|
|
6391
|
+
labels,
|
|
6392
|
+
note: '三方四正取本宫、对宫与两个三合宫共四宫,四宫宫干各化禄权科忌共 16 条飞化,按落宫归堆;只在落宫相同(会照)时标会聚,单条飞出不另立标签。只描会照与方向,不折吉凶,也未叠大限流年四化。',
|
|
6393
|
+
};
|
|
6394
|
+
}
|
|
6395
|
+
|
|
5883
6396
|
// ── 流年四化落宫 ────────────────────────────────────────────
|
|
5884
6397
|
|
|
5885
6398
|
function enrichLiunian(chart) {
|
|
@@ -5989,7 +6502,7 @@ function flowOf(chart, asOf) {
|
|
|
5989
6502
|
};
|
|
5990
6503
|
}
|
|
5991
6504
|
|
|
5992
|
-
return { PALACE_NAMES, BRIGHTNESS, MUTAGEN, LUCUN, KUI_YUE, MING_ZHU, SHEN_ZHU, triadOf, HUO_START, LING_START, TIANMA, XIANCHI, HUAGAI, JIANGXING, GUCHEN, GUASU, posuIndex, XIAOXIAN_START, CHANGSHENG_NAMES, BOSHI_NAMES, JIANGQIAN_NAMES, SUIQI_NAMES, CHANGSHENG_START, hourBranchIndex, ziweiTianfuIndex, xiaoxianAge, buildZiwei, detectPatterns, daxianList, FLY_TYPES, flyStarOf, flyStars, flyChain, flyChains, enrichLiunian, asOfParts, flowOf };
|
|
6505
|
+
return { PALACE_NAMES, BRIGHTNESS, MUTAGEN, LUCUN, KUI_YUE, MING_ZHU, SHEN_ZHU, triadOf, HUO_START, LING_START, TIANMA, XIANCHI, HUAGAI, JIANGXING, GUCHEN, GUASU, posuIndex, XIAOXIAN_START, CHANGSHENG_NAMES, BOSHI_NAMES, JIANGQIAN_NAMES, SUIQI_NAMES, CHANGSHENG_START, hourBranchIndex, ziweiTianfuIndex, xiaoxianAge, buildZiwei, detectPatterns, PATTERN_TONE, daxianList, FLY_TYPES, flyStarOf, flyStars, flyChain, flyChains, flyComposite, enrichLiunian, asOfParts, flowOf };
|
|
5993
6506
|
})();
|
|
5994
6507
|
|
|
5995
6508
|
__mods.tarot = (function () {
|
|
@@ -10830,6 +11343,43 @@ function useStrengthPlain(st) {
|
|
|
10830
11343
|
return `${when}对这件事有帮有压,一半的力要自己挣——结果更看你怎么走。`;
|
|
10831
11344
|
}
|
|
10832
11345
|
|
|
11346
|
+
// 化进 / 化退的力重 → 一句白话:方向之外,时令托不托着
|
|
11347
|
+
function jinTuiPlain(r) {
|
|
11348
|
+
const jp = r && r.jinTuiPower;
|
|
11349
|
+
if (!jp || !Array.isArray(jp.lines) || !jp.lines.length) return '';
|
|
11350
|
+
const sayOf = (l) => (l.verdict === '后劲足' ? '时令托着,后劲足'
|
|
11351
|
+
: l.verdict === '后劲有限' ? '时令不太托,后劲有限'
|
|
11352
|
+
: l.verdict === '进得虚' ? '时令最背,进也是虚进'
|
|
11353
|
+
: l.verdict === '退得缓' ? '时令还托着,退得慢'
|
|
11354
|
+
: l.verdict === '退得实' ? '时令也不托,退得实'
|
|
11355
|
+
: l.verdict === '月破失据' ? '又正好逢月破,进退都站不稳'
|
|
11356
|
+
: '缺月建,先只当方向看');
|
|
11357
|
+
return `动爻的进退还要看时令:${jp.lines.map((l) => `${l.position}爻${l.from}→${l.to}${l.type},${sayOf(l)}`).join(';')}。`;
|
|
11358
|
+
}
|
|
11359
|
+
|
|
11360
|
+
// 全卦逐爻旺衰 → 一句白话:整张卦的气偏在哪一头(与用神那一句分开说)
|
|
11361
|
+
function hexStrengthPlain(hs) {
|
|
11362
|
+
if (!hs || !hs.counts) return '';
|
|
11363
|
+
const up = (hs.counts.旺 || 0) + (hs.counts.相 || 0);
|
|
11364
|
+
const down = (hs.counts.囚 || 0) + (hs.counts.死 || 0);
|
|
11365
|
+
const when = hs.month && hs.month.branch ? `按${hs.month.branch}月这段时令看` : '按起卦这天看';
|
|
11366
|
+
const shi = hs.shi && hs.shi.monthState !== 'unknown' ? `代表你的世爻在${hs.shi.monthState}` : '';
|
|
11367
|
+
if (up >= 4 && down === 0) return `${when},整张卦六爻的气多数是顺的,${shi},眼下算是好推的时候。`;
|
|
11368
|
+
if (down >= 4 && up === 0) return `${when},整张卦六爻的气多数被压着,${shi},这几天更适合等而不是冲。`;
|
|
11369
|
+
return `${when},整张卦六爻有顺有逆(旺相 ${up} 爻、囚死 ${down} 爻)${shi ? `,${shi}` : ''},成不成要看具体哪一爻在动。`;
|
|
11370
|
+
}
|
|
11371
|
+
|
|
11372
|
+
// 三方四正复合飞化 → 一句白话:四股力有没有挤到同一处
|
|
11373
|
+
function flyCompositePlain(fc) {
|
|
11374
|
+
if (!fc || !Array.isArray(fc.targets)) return '';
|
|
11375
|
+
const hub = fc.targets.find((t) => t.count >= 2);
|
|
11376
|
+
const self = fc.groups && fc.groups.selfHua && fc.groups.selfHua.length
|
|
11377
|
+
? '其中有的宫自己化出去又落回自己,容易表现为「想得多、落得少」。'
|
|
11378
|
+
: '';
|
|
11379
|
+
if (!hub) return `把命宫连同对宫、两个三合宫一起看,四股力飞出去没有挤到同一处,这几件事之间牵连不深。${self}`;
|
|
11380
|
+
return `把命宫连同对宫与两个三合宫一起看,${hub.incoming.length} 股力最后挤在「${String(hub.palace).replace(/宫$/, '')}」这件事上——这件事会把好几个方面的劲都吸过来。${self}`;
|
|
11381
|
+
}
|
|
11382
|
+
|
|
10833
11383
|
/**
|
|
10834
11384
|
* 六爻卦体 → 一句白话。
|
|
10835
11385
|
* 标签可能带爻位(「化进神 5」),所以按前缀匹配;
|
|
@@ -10900,6 +11450,7 @@ function buildAnswer(r, ask, ctx = {}) {
|
|
|
10900
11450
|
`${bureau.name ? `、${bureau.name}` : ''}${md ? `,命主${md}` : ''}` +
|
|
10901
11451
|
`${body.lands ? `,身宫落在「${body.lands}」——这张盘的重心在这件事上` : ''}。`,
|
|
10902
11452
|
plainFly,
|
|
11453
|
+
flyCompositePlain(r.flyComposite),
|
|
10903
11454
|
`具体到你问的这件事,重点看${where}。`,
|
|
10904
11455
|
].filter(Boolean).join('');
|
|
10905
11456
|
}
|
|
@@ -10915,7 +11466,7 @@ function buildAnswer(r, ask, ctx = {}) {
|
|
|
10915
11466
|
head + `先说结论:本卦是${s(ben.name, '—')}` +
|
|
10916
11467
|
`${ben.palace ? `(${ben.palace})` : ''}` +
|
|
10917
11468
|
`${moving.length ? `,第 ${moving.join('、')} 爻动,变为${s(bian.name, '—')}` : ',六爻安静没有动爻'}。` +
|
|
10918
|
-
`${plainBody}${usePlainOf(r.useGod)}${useStrengthPlain(r.useGodStrength)}`,
|
|
11469
|
+
`${plainBody}${usePlainOf(r.useGod)}${useStrengthPlain(r.useGodStrength)}${jinTuiPlain(r)}${hexStrengthPlain(r.hexStrength)}`,
|
|
10919
11470
|
'断卦的落点在「世爻」(代表你)和「动爻」(事情的推动点),下面「看盘顺序」就按这个次序展开。',
|
|
10920
11471
|
].join('');
|
|
10921
11472
|
}
|
|
@@ -10933,9 +11484,13 @@ function buildPlain(r, ask, ctx = {}) {
|
|
|
10933
11484
|
const avoid = join(ys.avoid);
|
|
10934
11485
|
const strength = STRENGTH_PLAIN[st.level] || '力量偏中性';
|
|
10935
11486
|
const tiaohou = ys.tiaohou && ys.tiaohou.note ? `另外,${ys.tiaohou.note},所以「暖一点、亮一点」的环境通常更舒服。` : '';
|
|
11487
|
+
const sy = (r.liunian || []).find((l) => l.suiyun && Array.isArray(l.suiyun.signals) && l.suiyun.signals.length);
|
|
11488
|
+
const syPlain = sy
|
|
11489
|
+
? `再往后看,${sy.year} 年${sy.ganzhi}是${sy.suiyun.signals.map((x) => x.type).join('、')}——传统上把它当作「变化感强一点」的提示,既不是好消息也不是坏消息,遇上时多留个心眼就好。`
|
|
11490
|
+
: '';
|
|
10936
11491
|
return `你的命局属于「${s(st.level, '中性')}」:${strength}。` +
|
|
10937
11492
|
`${favor ? `能补${favor}的环境(行业、方位、作息、相处的人)会让你省力;${avoid ? `而${avoid}偏重的场合容易空耗,能绕就绕。` : ''}` : ''}` +
|
|
10938
|
-
tiaohou;
|
|
11493
|
+
tiaohou + syPlain;
|
|
10939
11494
|
}
|
|
10940
11495
|
if (r.system === 'ziwei') {
|
|
10941
11496
|
const soul = r.soul || {};
|
|
@@ -10949,6 +11504,7 @@ function buildPlain(r, ask, ctx = {}) {
|
|
|
10949
11504
|
`紫微看的是「你与环境怎么互动」。命宫落${s(soul.branch, '—')}宫,说明你做事的第一反应是从这个宫位的气质出发` +
|
|
10950
11505
|
`${body.lands ? `;身宫在「${body.lands}」,意味着真正让你上心的,是${body.lands}这件事` : ''}。`,
|
|
10951
11506
|
plainFly,
|
|
11507
|
+
flyCompositePlain(r.flyComposite),
|
|
10952
11508
|
].filter(Boolean).join('');
|
|
10953
11509
|
}
|
|
10954
11510
|
if (r.system === 'liuyao') {
|
|
@@ -10958,7 +11514,7 @@ function buildPlain(r, ask, ctx = {}) {
|
|
|
10958
11514
|
const plainBody = bodyPlainOf(labels);
|
|
10959
11515
|
return `${s(ben.name, '这一卦')}讲的是一个「${moving.length ? '正在动、还会变' : '暂时不动、先看清'}」的局面——` +
|
|
10960
11516
|
`${moving.length ? '有动爻,说明事情还有转圜空间,不是死局。' : '六爻安静,说明当下更该观察而不是硬推。'}` +
|
|
10961
|
-
`${plainBody}${usePlainOf(r.useGod)}${useStrengthPlain(r.useGodStrength)}`;
|
|
11517
|
+
`${plainBody}${usePlainOf(r.useGod)}${useStrengthPlain(r.useGodStrength)}${jinTuiPlain(r)}${hexStrengthPlain(r.hexStrength)}`;
|
|
10962
11518
|
}
|
|
10963
11519
|
return '';
|
|
10964
11520
|
}
|
|
@@ -11115,10 +11671,10 @@ const KNOWLEDGE = [
|
|
|
11115
11671
|
id: 'bazi-suiyun',
|
|
11116
11672
|
system: 'bazi', dims: ['overall', 'career'],
|
|
11117
11673
|
gist: '大运管十年基调,流年管当年触发。',
|
|
11118
|
-
detail: '
|
|
11674
|
+
detail: '大运像换了条路,流年像这条路上某一段的天气。岁运并临(当值大运与流年干支相同)、运年反吟(大运与流年天克地冲)、流年伏吟(流年与原局某柱干支相同)与流年反吟(流年与原局某柱天克地冲),是传统上标记「变动较大」的年份,属于提示而非断语。本插件逐年标出四类信号:当值大运按该年立春到次年立春的区间取,交运落在年内时前后两步并列;只标干支重复与对冲,不折分数。',
|
|
11119
11675
|
source: '岁运并临、伏吟反吟见《三命通会》《渊海子平》',
|
|
11120
11676
|
status: 'variant',
|
|
11121
|
-
note: '
|
|
11677
|
+
note: '「岁运并临主大凶」是流传最广也最被滥用的说法,本插件只作变动提示,不断吉凶;大运与原局之间的伏吟反吟未逐年标注,四柱十神层面的引化也未叠入。',
|
|
11122
11678
|
},
|
|
11123
11679
|
{
|
|
11124
11680
|
id: 'bazi-liuqin',
|
|
@@ -11147,6 +11703,34 @@ const KNOWLEDGE = [
|
|
|
11147
11703
|
status: 'settled',
|
|
11148
11704
|
},
|
|
11149
11705
|
|
|
11706
|
+
{
|
|
11707
|
+
id: 'bazi-sanming-duizhao',
|
|
11708
|
+
system: 'bazi', dims: ['overall', 'career'],
|
|
11709
|
+
gist: '同一个格,子平真诠讲怎么用,三命通会讲怎么取。',
|
|
11710
|
+
detail: '两书不是谁替代谁:子平真诠以月令取用神、论顺逆成败,重「用」;三命通会按十神逐格立论,重「取」与「忌」。同看正官格,前者问财印护官、伤煞混杂,后者先说「止许一位,多则不宜」。本插件把两条并列,不合并成一句断语。',
|
|
11711
|
+
source: '《子平真诠》论正官等篇;《三命通会》卷五、卷六论十神',
|
|
11712
|
+
status: 'variant',
|
|
11713
|
+
note: '两书成书年代与流派不同,用语有出入;本插件照录通行本,不做校勘改字,也不替两家调和。',
|
|
11714
|
+
},
|
|
11715
|
+
{
|
|
11716
|
+
id: 'bazi-geju-chengbai',
|
|
11717
|
+
system: 'bazi', dims: ['overall', 'career'],
|
|
11718
|
+
gist: '格有成有败:成中带忌会打折,败中有救还能转成。',
|
|
11719
|
+
detail: '月令取到格只是起点。成格要看有没有带忌——官逢财又逢伤、官透而被合、财旺生官又逢伤,都会把成格打折;败格也看有没有救应——印来解伤、合来清煞、劫来解财,败中可转。所以判格不能只报一个格名。',
|
|
11720
|
+
source: '《子平真诠》九、论用神成败救应',
|
|
11721
|
+
status: 'variant',
|
|
11722
|
+
note: '各家对成格条件与带忌轻重的排序不同(有先看刑冲、有先看合化),本插件只把原文与成败方向并列摆出,不逐盘判成破。',
|
|
11723
|
+
},
|
|
11724
|
+
{
|
|
11725
|
+
id: 'bazi-huagi-bianhua',
|
|
11726
|
+
system: 'bazi', dims: ['overall', 'career'],
|
|
11727
|
+
gist: '月令用神会因合化而变:同一个起点,取用可以不同。',
|
|
11728
|
+
detail: '用神本从月令取,但月令藏干不一,透出的字不同、支会合局不同,取用就跟着变:丁生亥月本为正官,支全卯未化为印;己生申月本属伤官,藏庚透壬化为财。所以看到化气格,要回头核对月令与合局,不能只按本气定格。',
|
|
11729
|
+
source: '《子平真诠》十、论用神变化;化气条件各家另论',
|
|
11730
|
+
status: 'variant',
|
|
11731
|
+
note: '化气格成立条件各家宽严不一(是否要求月令为化神、日主是否允许有根),本插件只列条件、附原文,不据此断定化气已成。',
|
|
11732
|
+
},
|
|
11733
|
+
|
|
11150
11734
|
// ── 紫微 ──────────────────────────────────────────────
|
|
11151
11735
|
{
|
|
11152
11736
|
id: 'ziwei-sanfang',
|
|
@@ -11207,7 +11791,16 @@ const KNOWLEDGE = [
|
|
|
11207
11791
|
detail: '生年四化是先天带的,飞星四化是宫位自己去找的:每一宫的宫干定出禄权科忌四颗星,那几颗星落在哪一宫,就是这一宫的力气往哪边使。所以同一个「化忌」,从命宫飞出去和从财帛飞出去,说的是两件事。',
|
|
11208
11792
|
source: '《紫微斗数全书》四化篇;中州派宫干四化传法',
|
|
11209
11793
|
status: 'variant',
|
|
11210
|
-
note: '
|
|
11794
|
+
note: '飞星派(如钦天四化)把宫干四化当主线,三合派只作辅助;庚干四化各派另有异说,本插件取中州派常用表。飞星串连与三方四正复合飞化现已给出,但未叠大限流年四化。',
|
|
11795
|
+
},
|
|
11796
|
+
{
|
|
11797
|
+
id: 'ziwei-sanfang-fei',
|
|
11798
|
+
system: 'ziwei', dims: ['overall', 'career'],
|
|
11799
|
+
gist: '三方四正一起飞,看四股力会到哪一宫。',
|
|
11800
|
+
detail: '单宫飞化只看本宫宫干把四化送去哪里;三方四正复合飞化把本宫、对宫与两个三合宫共四宫的宫干四化同时摊开,约 16 条,按落宫归堆,落到同一宫的就是会照。会在一处的化越多,那一宫被牵动的力道越集中;两忌以上会宫、禄忌同宫、三化以上会宫、宫干化出又落回本宫(自化),是这一层最常取的几种情形。',
|
|
11801
|
+
source: '《紫微斗数全书》四化篇;飞星派三方四正同飞说',
|
|
11802
|
+
status: 'variant',
|
|
11803
|
+
note: '飞星派对「三方四正一起飞」是否成立、会照要不要折成分数,各家口径不一;本插件只做落宫归堆与会照标记,不折分数,也未叠大限流年四化。',
|
|
11211
11804
|
},
|
|
11212
11805
|
{
|
|
11213
11806
|
id: 'ziwei-jichuanji',
|
|
@@ -11262,6 +11855,15 @@ const KNOWLEDGE = [
|
|
|
11262
11855
|
status: 'variant',
|
|
11263
11856
|
note: '月破、暗动、冲空三者各家取法不完全一致(有派别把日冲动爻也叫暗动,有派别只认旺相之爻暗动);本插件按「月建冲=月破、日冲静爻=暗动、日冲旬空=冲空」这一套给标签,并注明用了哪一支月建。',
|
|
11264
11857
|
},
|
|
11858
|
+
{
|
|
11859
|
+
id: 'liuyao-quanggu-shuai',
|
|
11860
|
+
system: 'liuyao', dims: ['overall', 'work'],
|
|
11861
|
+
gist: '全卦逐爻看月建,才看得出气聚在哪一头。',
|
|
11862
|
+
detail: '月建管这一段时令的旺衰、日辰管当天的扶克,落到全部六爻逐爻判定:每爻都出月令五态(旺相休囚死)与日辰五关系,并标月破、暗动、冲空。世爻、应爻、动爻与旬空另标,五态分布能看出气是聚在世应还是散在旁爻——用神只是其中一处落点,不看全卦容易把一处当全局。',
|
|
11863
|
+
source: '《增删卜易》月建章、日辰章;《卜筮正宗》六爻旺衰论',
|
|
11864
|
+
status: 'variant',
|
|
11865
|
+
note: '各家对月破、暗动、冲空的取法不完全一致,是否给六爻折力重(分数)分歧更大;本插件只给状态标签与五态分布,不折分数。',
|
|
11866
|
+
},
|
|
11265
11867
|
{
|
|
11266
11868
|
id: 'liuyao-yingqi',
|
|
11267
11869
|
system: 'liuyao', dims: ['overall', 'career'],
|
|
@@ -11327,7 +11929,7 @@ const KNOWLEDGE = [
|
|
|
11327
11929
|
id: 'liuyao-jintui-yong',
|
|
11328
11930
|
system: 'liuyao', dims: ['overall', 'work'],
|
|
11329
11931
|
gist: '化进化退要看是用神还是忌神,还要叠月建日辰。',
|
|
11330
|
-
detail: '
|
|
11932
|
+
detail: '进神退神本身只说明这一爻的向外趋势:用神化进为得力,忌神化进则为患加剧;用神化退是力衰,忌神化退反而是解脱。传统还要看它在本月令衰旺、有没有日辰生扶,空亡或受克时进者未必能进。本插件把进退与爻位标出来,再按月建五态给一档力重——得令则进得动、退得慢,失令则进得虚、退得实,月破压过一切;只给档位,不折成加权分数,吉凶仍落在用神与忌神那一层判。',
|
|
11331
11933
|
source: '《增删卜易》进神退神章、用神章',
|
|
11332
11934
|
status: 'variant',
|
|
11333
11935
|
note: '土之进退次序各家说法不完全一致,有以丑→辰→未→戌为进、也有只取辰戌丑未相对者;本插件按丑辰未戌成环处理,并用《增删卜易》卦例中「未土化戌土为进」「戌土化未土为退」对拍。',
|
|
@@ -11794,6 +12396,19 @@ function baziInterpret(r) {
|
|
|
11794
12396
|
return `${jiaoLine}当前大运:${pick(cur, 'ganzhi', '—')}(${curSpan})。后续两步:${nextTwo}。\n近五年流年:${years || '—'}。\n读法:大运管"这十年的大环境",流年管"今年的具体天气";两者打架时,以能否动到用神为准。`;
|
|
11795
12397
|
})(),
|
|
11796
12398
|
},
|
|
12399
|
+
(() => {
|
|
12400
|
+
const hits = (r.liunian || []).filter((l) => l.suiyun && Array.isArray(l.suiyun.signals) && l.suiyun.signals.length);
|
|
12401
|
+
return {
|
|
12402
|
+
key: 'suiyun', label: '岁运提示',
|
|
12403
|
+
text: hits.length
|
|
12404
|
+
? hits.map((l) => {
|
|
12405
|
+
const stem = (l.suiyun.dayun || []).map((d) => `第${d.step}步${d.ganzhi}`).join('、');
|
|
12406
|
+
return `${l.year} ${l.ganzhi}(${stem || '未到起运'}):${l.suiyun.signals.map((s) => s.detail).join(';')}`;
|
|
12407
|
+
}).join('\n') +
|
|
12408
|
+
'\n读法:岁运并临、运年反吟与流年伏吟/反吟只说明干支层面重复或对冲,传统上当作「变动感较强」的信号;本插件不据此判吉凶,要落到具体年份,仍看该年是否动到用神。'
|
|
12409
|
+
: '近十年没有岁运并临、运年反吟或流年伏吟/反吟。「岁运并临主大凶」这类说法流传很广,本插件只把它当变动提示,没有命中就不作额外解读。',
|
|
12410
|
+
};
|
|
12411
|
+
})(),
|
|
11797
12412
|
{
|
|
11798
12413
|
key: 'checks', label: '交叉校验',
|
|
11799
12414
|
text: (() => {
|
|
@@ -12151,6 +12766,39 @@ function ziweiInterpret(r) {
|
|
|
12151
12766
|
}
|
|
12152
12767
|
}
|
|
12153
12768
|
|
|
12769
|
+
// 三方四正复合飞化:命宫连同对宫与两个三合宫一起飞,四宫 16 条按落宫归堆
|
|
12770
|
+
{
|
|
12771
|
+
const fc = r.flyComposite;
|
|
12772
|
+
const word = (p) => `${p}${String(p).endsWith('宫') ? '' : '宫'}`;
|
|
12773
|
+
if (fc && Array.isArray(fc.sources) && fc.sources.length >= 2) {
|
|
12774
|
+
const hubs = fc.targets.filter((t) => t.count >= 2);
|
|
12775
|
+
const hubText = hubs.length
|
|
12776
|
+
? hubs.slice(0, 5).map((t) => `${word(t.palace)}收了 ${t.incoming.map((x) => `${word(x.from)}化${x.type}${x.star}`).join('、')}`).join(';')
|
|
12777
|
+
: '四宫化出去之后没有落在同一宫,力是散开的';
|
|
12778
|
+
const readings = [];
|
|
12779
|
+
if (fc.groups.doubleJi.length) {
|
|
12780
|
+
readings.push(`${fc.groups.doubleJi.map((t) => word(t.palace)).join('、')}收到两个以上的忌——同一件事被反复牵动,传统看作那一宫的事务容易拖着不放`);
|
|
12781
|
+
}
|
|
12782
|
+
if (fc.groups.luJi.length) {
|
|
12783
|
+
readings.push(`${fc.groups.luJi.map((t) => word(t.palace)).join('、')}禄忌同宫:好处与在意的地方绑在一起,越想要的东西越容易反复`);
|
|
12784
|
+
}
|
|
12785
|
+
if (fc.groups.tripleHua.length) {
|
|
12786
|
+
readings.push(`${fc.groups.tripleHua.map((t) => word(t.palace)).join('、')}三化以上会宫:那一宫同时被几种力牵住,常常是这张盘最忙的地方`);
|
|
12787
|
+
}
|
|
12788
|
+
if (fc.groups.selfHua.length) {
|
|
12789
|
+
readings.push(`${fc.groups.selfHua.map((t) => word(t.palace)).join('、')}自化:宫干化出去又落回自己,表现为力气绕回原处`);
|
|
12790
|
+
}
|
|
12791
|
+
sections.push({
|
|
12792
|
+
key: 'flyComposite',
|
|
12793
|
+
label: '三方四正飞化',
|
|
12794
|
+
text: `上一节是命宫一条线往下追;这一节把命宫连同对宫与两个三合宫(${fc.sanfang.join('、')})一起飞:四宫各化禄权科忌,共 16 条飞化(星未上盘的只记星不记落宫),按落宫归堆。` +
|
|
12795
|
+
`${hubText}。` +
|
|
12796
|
+
`${readings.length ? `${readings.join(';')}。` : ''}` +
|
|
12797
|
+
`读法上,会在一处的化越多,那一宫被牵动的力道越集中;落单的飞化只说明方向,不单独取象。这一层同样只描会照与方向,不折吉凶,也没有叠大限与流年四化。`,
|
|
12798
|
+
});
|
|
12799
|
+
}
|
|
12800
|
+
}
|
|
12801
|
+
|
|
12154
12802
|
// 流月/流日/流时:流年只回答「今年」,再往下才是「这个月」「这两天」
|
|
12155
12803
|
if (r.flow) {
|
|
12156
12804
|
const f = r.flow;
|
|
@@ -12322,6 +12970,10 @@ function liuyaoInterpret(r, ask) {
|
|
|
12322
12970
|
const tuiYao = (bd.jinTui || []).filter((x) => x.type === '退');
|
|
12323
12971
|
if (jinYao.length) bodyText.push(`化进神(第${jinYao.map((x) => x.position).join('、')}爻:${jinYao.map((x) => `${x.from}→${x.to}`).join('、')}):变出的地支与本爻同五行、且顺着往前一步,传统读作「进」——这一爻代表的人或事有后劲,往前走比退回去顺。`);
|
|
12324
12972
|
if (tuiYao.length) bodyText.push(`化退神(第${tuiYao.map((x) => x.position).join('、')}爻:${tuiYao.map((x) => `${x.from}→${x.to}`).join('、')}):变出的地支与本爻同五行、却倒着退一步,传统读作「退」——这一爻代表的人或事渐渐退气,别按原来的势头去推。`);
|
|
12973
|
+
const jp = r.jinTuiPower;
|
|
12974
|
+
if (jp && Array.isArray(jp.lines) && jp.lines.length) {
|
|
12975
|
+
bodyText.push(`进退的力重(放回月建日辰看):${jp.lines.map((l) => `第${l.position}爻${l.say}`).join(';')}。进退只管方向,走不走得动看时令托不托着;用神化进为喜,忌神化进反而是忌。`);
|
|
12976
|
+
}
|
|
12325
12977
|
bodyText.push('这些标签只说明卦体的动势,不直接定吉凶:同一支六冲,近病问的是速愈、久病问的是凶险;同一爻化进,也得看用神旺不旺、有没有月建日辰托着。');
|
|
12326
12978
|
sections.push({ key: 'body', label: '卦体关系', text: bodyText.join('\n') });
|
|
12327
12979
|
}
|
|
@@ -12381,9 +13033,36 @@ function liuyaoInterpret(r, ask) {
|
|
|
12381
13033
|
sections.push({ key: 'yongshen', label: '用神落位与卦体', text: useText.join('\n') });
|
|
12382
13034
|
}
|
|
12383
13035
|
|
|
13036
|
+
// 全卦逐爻旺衰:不挑用神,六爻都过一遍,看整张卦的气压在哪一头
|
|
13037
|
+
{
|
|
13038
|
+
const hs = r.hexStrength;
|
|
13039
|
+
if (hs && Array.isArray(hs.lines) && hs.lines.length) {
|
|
13040
|
+
const head = hs.month && hs.month.branch
|
|
13041
|
+
? `月建 ${hs.month.branch}(${hs.month.element})`
|
|
13042
|
+
: '没有月建(未给起卦时间)';
|
|
13043
|
+
const day = hs.day && hs.day.branch ? `日辰 ${hs.day.branch}(${hs.day.element})` : '日辰 —';
|
|
13044
|
+
const rows = hs.lines.map((l) => {
|
|
13045
|
+
const who = l.shi ? '(世)' : l.ying ? '(应)' : '';
|
|
13046
|
+
const flags = `${l.moving ? '·动' : ''}${l.kong ? '·旬空' : ''}`;
|
|
13047
|
+
return `${l.position}爻${l.liuqin ? l.liuqin : ''}${l.branch}${l.element}${who}${flags}:月建${l.monthState},${l.dayRelation}${l.chongTag ? `,${l.chongTag}` : ''}`;
|
|
13048
|
+
});
|
|
13049
|
+
const order = ['旺', '相', '休', '囚', '死'];
|
|
13050
|
+
const dist = order.filter((k) => hs.counts[k]).map((k) => `${k}${hs.counts[k]}`).join('、');
|
|
13051
|
+
const shi = hs.shi ? `世爻在${hs.shi.position}爻(月建${hs.shi.monthState},${hs.shi.dayRelation})` : '';
|
|
13052
|
+
const ying = hs.ying ? `应爻在${hs.ying.position}爻(月建${hs.ying.monthState},${hs.ying.dayRelation})` : '';
|
|
13053
|
+
sections.push({
|
|
13054
|
+
key: 'hexStrength',
|
|
13055
|
+
label: '全卦逐爻旺衰',
|
|
13056
|
+
text: `整张卦按${head}、${day}逐爻过一遍:${rows.join(';')}。五态分布:${dist}——${[shi, ying].filter(Boolean).join(',')}。` +
|
|
13057
|
+
`气旺的爻对应的事推进起来省力,气弱或遭月破的爻对应的事宜缓;这只是六爻全貌,用神那几爻的细节仍以上一节为准,两处不冲突时再看动爻把哪一头带动。` +
|
|
13058
|
+
`判定与用神旺衰同一套(月令五态、日辰五关系、月破/暗动/冲空),只报状态,不折成分数。`,
|
|
13059
|
+
});
|
|
13060
|
+
}
|
|
13061
|
+
}
|
|
13062
|
+
|
|
12384
13063
|
sections.push({
|
|
12385
13064
|
key: 'limits', label: '未纳入',
|
|
12386
|
-
text: '
|
|
13065
|
+
text: '本卦没有计算:用神两现时该取哪一爻的权重、伏神出伏的应期。化进/化退的力重只按月建五态给「得令/失令」这类档位,不折成加权分数,也不叠动变连环;这些都会改变"旺不旺"的判断,所以这里只给取象与方向。',
|
|
12387
13066
|
});
|
|
12388
13067
|
|
|
12389
13068
|
const dimensions = [
|
|
@@ -13118,8 +13797,66 @@ function followup(r, question) {
|
|
|
13118
13797
|
return { question: q, ...result };
|
|
13119
13798
|
}
|
|
13120
13799
|
|
|
13800
|
+
/** 体系显示名:追问提示里用,避免把 bazi 这类内部键直接给用户看。 */
|
|
13801
|
+
const SYSTEM_LABEL = {
|
|
13802
|
+
bazi: '八字(四柱)',
|
|
13803
|
+
ziwei: '紫微斗数',
|
|
13804
|
+
liuyao: '六爻',
|
|
13805
|
+
meihua: '梅花易数',
|
|
13806
|
+
daliuren: '大六壬',
|
|
13807
|
+
qimen: '奇门遁甲',
|
|
13808
|
+
tarot: '塔罗',
|
|
13809
|
+
hepan: '合盘',
|
|
13810
|
+
chenggu: '称骨',
|
|
13811
|
+
almanac: '黄历',
|
|
13812
|
+
zeri: '择日',
|
|
13813
|
+
star: '星座',
|
|
13814
|
+
numerology: '生命数字',
|
|
13815
|
+
mbti: '十六型人格',
|
|
13816
|
+
trend: '人生 K 线',
|
|
13817
|
+
fengshui: '风水',
|
|
13818
|
+
name: '起名',
|
|
13819
|
+
convert: '公农历互转',
|
|
13820
|
+
};
|
|
13821
|
+
|
|
13822
|
+
/**
|
|
13823
|
+
* 把「就这一盘继续问」整理成一段可以发到对话窗口的提问。
|
|
13824
|
+
*
|
|
13825
|
+
* 这里只做文本组装,不调用模型、不改盘:面板里点「问进对话」时,
|
|
13826
|
+
* 客户端把这段文字写进对话输入框并提交,由对话里的模型基于盘面回答。
|
|
13827
|
+
*
|
|
13828
|
+
* @param {object} r compute 的结果(至少要带 system 与 summary)
|
|
13829
|
+
* @param {{question?:string, maxChars?:number}} [opts]
|
|
13830
|
+
* @returns {{text:string, question:string, system:string, label:string, chars:number, truncated:boolean}}
|
|
13831
|
+
*/
|
|
13832
|
+
function askPrompt(r, opts = {}) {
|
|
13833
|
+
const label = SYSTEM_LABEL[r && r.system] || (r && r.system) || '未知体系';
|
|
13834
|
+
const asked = String((opts && opts.question) || '').trim();
|
|
13835
|
+
const question = asked || '请先总览这张盘,指出最值得注意的一两处,并说明各自的依据。';
|
|
13836
|
+
const limit = Number.isFinite(opts && opts.maxChars) && opts.maxChars >= 400 ? opts.maxChars : 3000;
|
|
13837
|
+
const raw = String((r && r.summary) || '').trim();
|
|
13838
|
+
const truncated = raw.length > limit;
|
|
13839
|
+
const summary = truncated ? `${raw.slice(0, limit)}…(摘要已截断)` : raw;
|
|
13840
|
+
|
|
13841
|
+
const lines = [
|
|
13842
|
+
'【命理追问】下面这张盘是命理插件刚排好的,请就着它回答我的问题;不用重新排盘,盘面字段已经够用。',
|
|
13843
|
+
`体系:${label}`,
|
|
13844
|
+
`所问:${question}`,
|
|
13845
|
+
'',
|
|
13846
|
+
'——盘面摘要——',
|
|
13847
|
+
summary || '(这张盘没有摘要字段,请先让我重新排一次。)',
|
|
13848
|
+
'',
|
|
13849
|
+
'——回答要求——',
|
|
13850
|
+
'1) 尽量引用到具体的柱、宫或爻,再说判断,别只给结论;',
|
|
13851
|
+
'2) 盘面里没有依据的地方直接说「这盘里看不出来」,不要补外部假设;',
|
|
13852
|
+
'3) 用概率和倾向的说法,别给绝对化的断言,也别把传统说法当成事实。',
|
|
13853
|
+
];
|
|
13854
|
+
const text = lines.join('\n');
|
|
13855
|
+
return { text, question, system: (r && r.system) || '', label, chars: text.length, truncated };
|
|
13856
|
+
}
|
|
13857
|
+
|
|
13121
13858
|
|
|
13122
|
-
return { followup };
|
|
13859
|
+
return { followup, askPrompt };
|
|
13123
13860
|
})();
|
|
13124
13861
|
|
|
13125
13862
|
__mods.crosscheck = (function () {
|
|
@@ -13465,7 +14202,7 @@ return { matchEvent, rectifyBirth, RECTIFY_KINDS };
|
|
|
13465
14202
|
__mods.index = (function () {
|
|
13466
14203
|
// 统一入口:解析参数、分派到各体系、生成可读摘要
|
|
13467
14204
|
const { buildBazi } = __mods.bazi;
|
|
13468
|
-
const { buildLiuyao, tossLines, bodyLabels, yongshenOf, yongshenStrength } = __mods.liuyao;
|
|
14205
|
+
const { buildLiuyao, tossLines, bodyLabels, yongshenOf, yongshenStrength, hexagramStrength, jinTuiPower } = __mods.liuyao;
|
|
13469
14206
|
const { buildZiwei, BRIGHTNESS, flowOf, asOfParts } = __mods.ziwei;
|
|
13470
14207
|
const { drawTarot } = __mods.tarot;
|
|
13471
14208
|
const { buildMeihua } = __mods.meihua;
|
|
@@ -13477,7 +14214,7 @@ const { geocodeAddress, resolveAddress } = __mods.geo;
|
|
|
13477
14214
|
const { toJDN, ganzhiName, dayGanzhiIndex } = __mods.calendar;
|
|
13478
14215
|
const { randomOf, isSeed } = __mods.random;
|
|
13479
14216
|
const { interpret, DIRECTIONS, DIRECTION_DEFAULT } = __mods.interpret;
|
|
13480
|
-
const { followup } = __mods.followup;
|
|
14217
|
+
const { followup, askPrompt } = __mods.followup;
|
|
13481
14218
|
const { crossCheck, crossText } = __mods.crosscheck;
|
|
13482
14219
|
const { pastSignals, verifyFit } = __mods.verify;
|
|
13483
14220
|
const { rectifyBirth } = __mods.rectify;
|
|
@@ -13601,6 +14338,13 @@ function baziText(r) {
|
|
|
13601
14338
|
`大运:${r.dayun.rule}(${r.dayun.direction}),${r.dayun.startAge.years}岁${r.dayun.startAge.months}个月起运${jiao}`,
|
|
13602
14339
|
` ${dayun}`,
|
|
13603
14340
|
`流年:${r.liunian.slice(0, 10).map((l) => `${l.year}${l.ganzhi}(${l.stemTenGod})${l.luck ? `·${l.luck.tier}` : ''}`).join(' ')}`,
|
|
14341
|
+
(() => {
|
|
14342
|
+
const hits = r.liunian.filter((l) => l.suiyun && l.suiyun.signals && l.suiyun.signals.length);
|
|
14343
|
+
if (!hits.length) return '岁运提示:近十年无岁运并临、运年反吟或流年伏吟/反吟(只标干支,不判吉凶)';
|
|
14344
|
+
const label = (s) => `${s.type}${s.type.startsWith('流年') && s.target ? `(${s.target})` : ''}`;
|
|
14345
|
+
return '岁运提示(只标干支变动,不判吉凶):' + hits
|
|
14346
|
+
.map((l) => `${l.year}${l.ganzhi} ${l.suiyun.signals.map(label).join('/')}`).join(';');
|
|
14347
|
+
})(),
|
|
13604
14348
|
'(格局、用神、行运吉凶为扶抑+简化调候的量化提示,非断语。)',
|
|
13605
14349
|
].join('\n') + near;
|
|
13606
14350
|
}
|
|
@@ -13639,6 +14383,18 @@ function ziweiText(r) {
|
|
|
13639
14383
|
const text = ['禄', '权', '科', '忌'].map(one).filter(Boolean).join(' ');
|
|
13640
14384
|
return text ? `【命宫飞星】${text}` : '';
|
|
13641
14385
|
})();
|
|
14386
|
+
// 三方四正一起飞:四宫的 16 条飞化按落宫归堆,只看会聚
|
|
14387
|
+
const flyCompositeLine = (() => {
|
|
14388
|
+
const fc = r.flyComposite;
|
|
14389
|
+
if (!fc || !Array.isArray(fc.sources) || !fc.sources.length) return '';
|
|
14390
|
+
const groups = fc.labels.length ? fc.labels.join(' · ') : '无同宫会聚';
|
|
14391
|
+
const detail = ['禄', '权', '科', '忌'].map((t) => {
|
|
14392
|
+
const list = ((fc.byType && fc.byType[t]) || []).filter((x) => !x.self);
|
|
14393
|
+
const tos = [...new Set(list.map((x) => String(x.to).replace(/宫$/, '')))];
|
|
14394
|
+
return tos.length ? `${t}→${tos.join('/')}` : '';
|
|
14395
|
+
}).filter(Boolean).join(' ');
|
|
14396
|
+
return `【三方四正飞化】${fc.sanfang.join('·')}:${groups}${detail ? ` ${detail}` : ''}`;
|
|
14397
|
+
})();
|
|
13642
14398
|
return [
|
|
13643
14399
|
`【农历】${lunarText}(月首 ${r.lunar.monthStart}) 时支:${r.hourBranch} 年干支:${r.yearGanzhi}`,
|
|
13644
14400
|
`【时刻】${r.solarTime ? `${r.solarTime.civilText} → 真太阳时 ${r.solarTime.trueSolarText}${r.input.geo ? '(' + r.input.geo.note + ')' : ''}` : ''}`,
|
|
@@ -13648,6 +14404,7 @@ function ziweiText(r) {
|
|
|
13648
14404
|
`【昌曲】文昌${r.changqu.wenchang.branch}(${r.changqu.wenchang.palace}${r.changqu.wenchang.mutagen ? '·化' + r.changqu.wenchang.mutagen : ''}) 文曲${r.changqu.wenqu.branch}(${r.changqu.wenqu.palace}${r.changqu.wenqu.mutagen ? '·化' + r.changqu.wenqu.mutagen : ''})`,
|
|
13649
14405
|
` ${r.changqu.relation} 入命三方:${r.changqu.inSoulSanfang ? '是' : '否'} 吸收面:${r.changqu.absorb.label}(${r.changqu.absorb.reason})`,
|
|
13650
14406
|
flyLine,
|
|
14407
|
+
flyCompositeLine,
|
|
13651
14408
|
'十二宫:',
|
|
13652
14409
|
...rows,
|
|
13653
14410
|
'大限(按起运年龄排序,前 8 限,宫干四化落宫):',
|
|
@@ -13655,7 +14412,7 @@ function ziweiText(r) {
|
|
|
13655
14412
|
'流年(前 6 年,完整 12 年在结构化数据里):',
|
|
13656
14413
|
...liunian,
|
|
13657
14414
|
`【格局】${patterns}`,
|
|
13658
|
-
r.patternSummary ? `【结构统计】吉格 ${r.patternSummary.good.length}、忌格 ${r.patternSummary.bad.length};${r.patternSummary.note}` : '',
|
|
14415
|
+
r.patternSummary ? `【结构统计】吉格 ${r.patternSummary.good.length}、中性 ${r.patternSummary.neutral.length}、忌格 ${r.patternSummary.bad.length};${r.patternSummary.note}` : '',
|
|
13659
14416
|
r.lunar.note ? `注:${r.lunar.note}` : '',
|
|
13660
14417
|
].filter(Boolean).join('\n');
|
|
13661
14418
|
}
|
|
@@ -13803,6 +14560,19 @@ function liuyaoText(r) {
|
|
|
13803
14560
|
} else {
|
|
13804
14561
|
out.push('用神:未取(未指明所问之事;用「询问方向」指定后即按六亲取用)');
|
|
13805
14562
|
}
|
|
14563
|
+
// 全卦逐爻旺衰:不挑用神,六爻都给状态,世应、动爻、旬空另标
|
|
14564
|
+
const hexSt = r.hexStrength;
|
|
14565
|
+
if (hexSt && Array.isArray(hexSt.labels) && hexSt.labels.length) {
|
|
14566
|
+
const m = hexSt.month && hexSt.month.branch
|
|
14567
|
+
? `月建 ${hexSt.month.branch}(${hexSt.month.element}) `
|
|
14568
|
+
: '无月建(未给起卦时间) ';
|
|
14569
|
+
out.push(`全卦旺衰:${m}${hexSt.labels.join(' · ')}`);
|
|
14570
|
+
}
|
|
14571
|
+
// 化进/化退的力重:单列一行,免得跟卦体标签混着读
|
|
14572
|
+
const jt = r.jinTuiPower;
|
|
14573
|
+
if (jt && Array.isArray(jt.lines) && jt.lines.length) {
|
|
14574
|
+
out.push(`进退力重:${jt.lines.map((l) => `${l.position}爻${l.from}→${l.to}${l.type}·${l.verdict}`).join(' · ')}`);
|
|
14575
|
+
}
|
|
13806
14576
|
return out.filter(Boolean).join('\n');
|
|
13807
14577
|
}
|
|
13808
14578
|
|
|
@@ -14114,18 +14884,24 @@ function computeRaw(args = {}) {
|
|
|
14114
14884
|
}
|
|
14115
14885
|
// 用神挂在结果上:摘要、面板、解析三层读同一份,避免各自取一次走散
|
|
14116
14886
|
const ug = yongshenOf(result, { direction: args.direction, gender: args.gender });
|
|
14117
|
-
if (ug.liuqin)
|
|
14118
|
-
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
monthBranch = null;
|
|
14127
|
-
}
|
|
14887
|
+
if (ug.liuqin) result.useGod = ug;
|
|
14888
|
+
// 月建按节气换月、与八字同源:从同一个 snapshot 取月支,取不到就只按日辰算
|
|
14889
|
+
let monthBranch = null;
|
|
14890
|
+
if (stamp) {
|
|
14891
|
+
try {
|
|
14892
|
+
const snap = buildSnapshot({ year: stamp.year, month: stamp.month, day: stamp.day, hour: stamp.hour, minute: stamp.minute });
|
|
14893
|
+
monthBranch = (snap.monthGanZhi || '')[1] || null;
|
|
14894
|
+
} catch {
|
|
14895
|
+
monthBranch = null;
|
|
14128
14896
|
}
|
|
14897
|
+
}
|
|
14898
|
+
// 全卦逐爻旺衰不依赖用神:没指定所问之事也要能看整张卦的气
|
|
14899
|
+
const hexStrength = hexagramStrength(result, { monthBranch, dayBranch: result.dayGanZhi.branch });
|
|
14900
|
+
if (hexStrength) result.hexStrength = hexStrength;
|
|
14901
|
+
// 化进/化退的力重:与旺衰同一套五态/五关系,只说走不走得动
|
|
14902
|
+
const jtPower = jinTuiPower(result, { monthBranch, dayBranch: result.dayGanZhi.branch });
|
|
14903
|
+
if (jtPower) result.jinTuiPower = jtPower;
|
|
14904
|
+
if (ug.liuqin) {
|
|
14129
14905
|
const strength = yongshenStrength(result, ug, { monthBranch, dayBranch: result.dayGanZhi.branch });
|
|
14130
14906
|
if (strength) result.useGodStrength = strength;
|
|
14131
14907
|
}
|
|
@@ -14547,7 +15323,7 @@ function renderText(result) {
|
|
|
14547
15323
|
|
|
14548
15324
|
|
|
14549
15325
|
|
|
14550
|
-
return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAddress, resolveAddress, buildBazi, buildLiuyao, tossLines, followup, pastSignals, verifyFit, rectifyBirth, crossCheck, crossText, buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buildNumerology, buildConvert, buildTrend, buildFengshui, buildName, parseDateTime, compute, interpretText, renderText };
|
|
15326
|
+
return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAddress, resolveAddress, buildBazi, buildLiuyao, tossLines, followup, askPrompt, pastSignals, verifyFit, rectifyBirth, crossCheck, crossText, buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buildNumerology, buildConvert, buildTrend, buildFengshui, buildName, parseDateTime, compute, interpretText, renderText };
|
|
14551
15327
|
})();
|
|
14552
15328
|
|
|
14553
15329
|
window.Engine = __mods.index;
|
|
@@ -14597,7 +15373,7 @@ window.Engine = __mods.index;
|
|
|
14597
15373
|
// 共用渲染层:紫微/八字/六爻/梅花/六壬/塔罗 -> HTML 字符串。面板与独立页面共用同一份。
|
|
14598
15374
|
(function () {
|
|
14599
15375
|
const CSS = `
|
|
14600
|
-
.pp,.mp-it{--ink:#1b1b1b;--ink2:#3f3a33;--muted:#6f6a60;--label:#8a8378;--faint:#a9a296;
|
|
15376
|
+
.pp,.mp-it,.mp-al,.mp-cg,.mp-cl,.mp-cli,.mp-kline,.mp-mb,.mp-mb-paper,.mp-nm,.mp-quick{--ink:#1b1b1b;--ink2:#3f3a33;--muted:#6f6a60;--label:#8a8378;--faint:#a9a296;
|
|
14601
15377
|
--line:#c8c1b2;--dimline:#b9b2a4;--hair:#e9e2d3;
|
|
14602
15378
|
/* 底色略沉作「桌面」,--card 跳到近白:原先 bg 与 card 只差 1/255,卡片感等于零。
|
|
14603
15379
|
同一色相里塞 9 个几乎相等的浅色,谁都浮不起来。 */
|
|
@@ -14606,15 +15382,19 @@ window.Engine = __mods.index;
|
|
|
14606
15382
|
--red:#b3261e;--red-rgb:179,38,30;--lu:#1f6f3f;--lu-rgb:31,111,63;
|
|
14607
15383
|
--quan:#8a5a00;--quan-rgb:138,90,0;--ke:#1f4e79;--ke-rgb:31,78,121;--ji:#b3261e;
|
|
14608
15384
|
--br-good:#4c7a5c;--br-bad:#9c5b56;--on-accent:#fff;--wx-metal:#8a6b1f;
|
|
14609
|
-
--tg-bi:#4a6f8a;--tg-shi:#4c7a5c;--tg-cai:#8a6b1f;--tg-guan:#9c5b56;--tg-yin:#6d5f83
|
|
15385
|
+
--tg-bi:#4a6f8a;--tg-shi:#4c7a5c;--tg-cai:#8a6b1f;--tg-guan:#9c5b56;--tg-yin:#6d5f83;
|
|
15386
|
+
/* 之前 mp-cli / mp-qt / mp-cl / 起名卡里引用了 --ink3、--fx、--sans,却从未定义:
|
|
15387
|
+
var() 取不到值 → 整条声明作废,字色与字形全靠继承,楷体、弱化灰都成了摆设。 */
|
|
15388
|
+
--ink3:#8a8378;--fx:"Kaiti SC",KaiTi,"STKaiti","Songti SC",serif;--sans:system-ui,-apple-system,"Microsoft YaHei",sans-serif;--kai:"Kaiti SC",KaiTi,"STKaiti",serif;
|
|
15389
|
+
--shadow:0 1px 2px rgba(35,28,18,.05),0 18px 40px -30px rgba(35,28,18,.42)}
|
|
14610
15390
|
/* 变量与 .mp-it 共享 —— 「解析与详解」是 .pp 的兄弟节点、不在 .pp 内部,
|
|
14611
15391
|
变量只挂在 .pp 上时它拿不到 --card/--muted/--red,头部底色会变透明、边框会退回黑色。 */
|
|
14612
15392
|
.pp{border:1px solid var(--line);background:var(--bg);color:var(--ink);font-family:"Songti SC","SimSun","Microsoft YaHei",serif;font-size:12.5px;line-height:1.55;
|
|
14613
|
-
container-type:inline-size}
|
|
15393
|
+
border-radius:12px;overflow:hidden;box-shadow:var(--shadow);container-type:inline-size}
|
|
14614
15394
|
/* 深色:只换变量,不动任何一条选择器。用 @media screen 限定,
|
|
14615
15395
|
打印永远走浅色 —— 深色主题下直接打印会得到一整页耗墨的深底 PDF。 */
|
|
14616
15396
|
@media screen and (prefers-color-scheme:dark){
|
|
14617
|
-
.pp,.mp-it{--ink:#eae5d9;--ink2:#d5cfc2;--muted:#aca598;--label:#a49c8e;--faint:#928b7e;
|
|
15397
|
+
.pp,.mp-it,.mp-al,.mp-cg,.mp-cl,.mp-cli,.mp-kline,.mp-mb,.mp-mb-paper,.mp-nm,.mp-quick{--ink:#eae5d9;--ink2:#d5cfc2;--muted:#aca598;--label:#a49c8e;--faint:#928b7e;
|
|
14618
15398
|
--line:#514a3e;--dimline:#5f5849;--hair:#2f2b23;
|
|
14619
15399
|
/* 与浅色同理:底更沉、卡片更亮,让层级在深底上也能立起来 */
|
|
14620
15400
|
--bg:#12110c;--card:#211f18;--band:#282419;--hover:#2e2a1f;--hover2:#383322;
|
|
@@ -14622,7 +15402,8 @@ window.Engine = __mods.index;
|
|
|
14622
15402
|
--red:#f08569;--red-rgb:240,133,105;--lu:#74c795;--lu-rgb:116,199,149;
|
|
14623
15403
|
--quan:#e2a95c;--quan-rgb:226,169,92;--ke:#86bcea;--ke-rgb:134,188,234;--ji:#f08569;
|
|
14624
15404
|
--br-good:#79c79a;--br-bad:#e09a8c;--on-accent:#14130f;--wx-metal:#dcb273;
|
|
14625
|
-
--tg-bi:#93b7cf;--tg-shi:#8fbb9d;--tg-cai:#d3ae62;--tg-guan:#d98d84;--tg-yin:#b4a4d0
|
|
15405
|
+
--tg-bi:#93b7cf;--tg-shi:#8fbb9d;--tg-cai:#d3ae62;--tg-guan:#d98d84;--tg-yin:#b4a4d0;
|
|
15406
|
+
--ink3:#8b8478;--shadow:0 1px 2px rgba(0,0,0,.5),0 18px 40px -30px rgba(0,0,0,.9)}
|
|
14626
15407
|
}
|
|
14627
15408
|
.pp *{box-sizing:border-box}
|
|
14628
15409
|
.pp-grid{display:grid;grid-template-columns:repeat(4,1fr);grid-template-rows:repeat(4,minmax(150px,auto));gap:0;border:1px solid var(--line)}
|
|
@@ -14730,6 +15511,8 @@ window.Engine = __mods.index;
|
|
|
14730
15511
|
点开后把该宫的完整星曜、四化、十二神、三方四正摊平看。 */
|
|
14731
15512
|
.pp-cell{cursor:pointer;transition:background .14s ease,box-shadow .14s ease;outline:none}
|
|
14732
15513
|
.pp-cell:hover{background:var(--hover)}
|
|
15514
|
+
/* 键盘可达:宫格是 div+tabindex,焦点必须看得见(原先把 outline 关了却没补替代) */
|
|
15515
|
+
.pp-cell:focus-visible{box-shadow:inset 0 0 0 2px var(--red)}
|
|
14733
15516
|
.pp-cell.pp-sel{background:var(--sel);box-shadow:inset 0 0 0 2px rgba(var(--red-rgb),.5)}
|
|
14734
15517
|
/* 选中宫的财帛/官禄/迁移三宫:能一眼看出命宫牵着哪几宫 */
|
|
14735
15518
|
.pp-cell.pp-link{background:var(--link);box-shadow:inset 0 0 0 1.5px rgba(var(--red-rgb),.22)}
|
|
@@ -14795,7 +15578,7 @@ window.Engine = __mods.index;
|
|
|
14795
15578
|
|
|
14796
15579
|
/* —— 六爻 —— */
|
|
14797
15580
|
.mp-hy-wrap{display:flex;gap:22px;flex-wrap:wrap;align-items:flex-start}
|
|
14798
|
-
.mp-hy-box{border:1px solid var(--line);background:var(--card);padding:12px 16px 14px;min-width:250px}
|
|
15581
|
+
.mp-hy-box{border:1px solid var(--line);border-radius:10px;background:var(--card);padding:12px 16px 14px;min-width:250px}
|
|
14799
15582
|
.mp-hy-h{display:flex;align-items:baseline;gap:8px;margin-bottom:10px;font-family:system-ui,sans-serif}
|
|
14800
15583
|
.mp-hy-h b{color:var(--red);font-size:14px}
|
|
14801
15584
|
.mp-hy-h span{color:var(--muted);font-size:12px}
|
|
@@ -14815,7 +15598,7 @@ window.Engine = __mods.index;
|
|
|
14815
15598
|
.mp-mh{padding:16px}
|
|
14816
15599
|
.mp-mh-head{font-size:13px;color:var(--muted);margin-bottom:12px}
|
|
14817
15600
|
.mp-mh-main{display:flex;gap:18px;flex-wrap:wrap;align-items:flex-start}
|
|
14818
|
-
.mp-hexbox{border:1px solid var(--line);background:var(--card);padding:12px 15px 13px}
|
|
15601
|
+
.mp-hexbox{border:1px solid var(--line);border-radius:10px;background:var(--card);padding:12px 15px 13px}
|
|
14819
15602
|
.mp-hexbox.hb-mini{min-width:118px}
|
|
14820
15603
|
.mp-hexbox .hb-h{display:flex;justify-content:space-between;gap:10px;font-size:12px;letter-spacing:.14em;color:var(--muted);font-family:system-ui,sans-serif;margin-bottom:5px}
|
|
14821
15604
|
.mp-hexbox .hb-n{font-size:17px;font-weight:700;color:var(--red);margin-bottom:8px;letter-spacing:.04em}
|
|
@@ -14997,7 +15780,7 @@ window.Engine = __mods.index;
|
|
|
14997
15780
|
.mp-tt{padding:16px}
|
|
14998
15781
|
.mp-tt-head{font-size:12.5px;color:var(--muted);margin-bottom:12px;letter-spacing:.04em}
|
|
14999
15782
|
.mp-tt-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(172px,1fr));gap:10px}
|
|
15000
|
-
.mp-tt-card{border:1px solid var(--line);background:var(--card);padding:13px 14px;display:flex;flex-direction:column;gap:7px;min-height:168px}
|
|
15783
|
+
.mp-tt-card{border:1px solid var(--line);border-radius:10px;background:var(--card);padding:13px 14px;display:flex;flex-direction:column;gap:7px;min-height:168px}
|
|
15001
15784
|
.mp-tt-card.tt-rev{background:var(--band);border-style:dashed}
|
|
15002
15785
|
.mp-tt-pos{font-size:12px;color:var(--muted);letter-spacing:.14em}
|
|
15003
15786
|
.mp-tt-name{font-size:19px;font-weight:700;color:var(--red);letter-spacing:.04em}
|
|
@@ -15020,12 +15803,13 @@ window.Engine = __mods.index;
|
|
|
15020
15803
|
/* —— 解析与详解 —— */
|
|
15021
15804
|
/* 变量由上面的 .pp,.mp-it 共享块提供。这里原先写过 --ink:var(--ink) 这类自引用声明,
|
|
15022
15805
|
自引用会让变量变成 guaranteed-invalid,反而把继承值也挡掉了(--card 因此彻底失效)。 */
|
|
15023
|
-
.mp-it{margin-top:14px;border:1px solid var(--line);background:var(--bg);color:var(--ink);
|
|
15806
|
+
.mp-it{margin-top:14px;border:1px solid var(--line);background:var(--bg);color:var(--ink);border-radius:12px;overflow:hidden;box-shadow:var(--shadow);
|
|
15024
15807
|
font-family:"Songti SC","SimSun","Microsoft YaHei",serif;font-size:13px;line-height:1.75}
|
|
15025
15808
|
.mp-it *{box-sizing:border-box}
|
|
15026
15809
|
/* 标题栏即折叠开关:整栏可点,箭头旋转表示状态 */
|
|
15027
15810
|
.mp-it-head{display:flex;align-items:center;gap:9px;flex-wrap:wrap;width:100%;padding:12px 16px;border:none;border-bottom:1px solid var(--line);background:var(--card);color:inherit;font:inherit;font-family:inherit;text-align:left;cursor:pointer;-webkit-appearance:none;appearance:none}
|
|
15028
15811
|
.mp-it-head:hover{background:var(--band)}
|
|
15812
|
+
.mp-it-head:focus-visible{outline:2px solid var(--red);outline-offset:-3px}
|
|
15029
15813
|
.mp-it-arrow{flex:none;font-size:12px;line-height:1;color:var(--red);transition:transform .16s ease}
|
|
15030
15814
|
.mp-it.folded .mp-it-arrow{transform:rotate(-90deg)}
|
|
15031
15815
|
.mp-it.folded .mp-it-wrap{display:none}
|
|
@@ -15113,7 +15897,7 @@ window.Engine = __mods.index;
|
|
|
15113
15897
|
.mp-tables{border-top:1px solid var(--line);padding:12px 16px 4px;background:var(--card)}
|
|
15114
15898
|
.mp-table-wrap{margin-bottom:12px}
|
|
15115
15899
|
.mp-table-h{font-size:12px;font-weight:700;letter-spacing:.1em;color:var(--lu);margin-bottom:5px;font-family:system-ui,sans-serif}
|
|
15116
|
-
.mp-table-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:
|
|
15900
|
+
.mp-table-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:8px}
|
|
15117
15901
|
.mp-table{width:100%;border-collapse:collapse;font-size:12px;line-height:1.6;color:var(--ink2);font-family:system-ui,sans-serif}
|
|
15118
15902
|
.mp-table th,.mp-table td{padding:5px 9px;text-align:left;vertical-align:top;border-bottom:1px solid var(--line);white-space:nowrap}
|
|
15119
15903
|
.mp-table th{background:var(--band);color:var(--label);font-weight:600;font-size:11px;letter-spacing:.06em}
|
|
@@ -15181,15 +15965,17 @@ window.Engine = __mods.index;
|
|
|
15181
15965
|
.mp-qt-y b.first{color:var(--ji);border-bottom:2px solid var(--ji);padding-bottom:1px}
|
|
15182
15966
|
.mp-qt-q{margin-top:6px;font-size:12.5px;line-height:1.8;color:var(--ink2);font-family:var(--fx)}
|
|
15183
15967
|
.mp-qt-q span{display:block;font-size:11px;color:var(--ink3);font-family:var(--sans);margin-top:2px}
|
|
15184
|
-
.mp-cl{margin-top:
|
|
15185
|
-
|
|
15186
|
-
.mp-cl-h
|
|
15968
|
+
.mp-cl{margin-top:12px;padding:10px 12px 8px;border-left:2px solid var(--quan);border-radius:0 8px 8px 0;
|
|
15969
|
+
background:color-mix(in srgb,var(--band) 72%,transparent)}
|
|
15970
|
+
.mp-cl-h{display:flex;gap:8px;align-items:baseline;font-size:12.5px;margin-bottom:7px}
|
|
15971
|
+
.mp-cl-h b{color:var(--ink);letter-spacing:.06em}
|
|
15187
15972
|
.mp-cl-h span{color:var(--ink3);font-size:11.5px}
|
|
15188
|
-
.mp-cl-e{padding:
|
|
15973
|
+
.mp-cl-e{padding:8px 0;border-top:1px dashed var(--hair)}
|
|
15189
15974
|
.mp-cl-e:first-of-type{border-top:0;padding-top:0}
|
|
15190
|
-
.mp-cl-t b{font-family:var(--fx);font-size:13px;color:var(--lu);font-weight:600}
|
|
15191
|
-
.mp-cl-q{font-family:var(--fx);font-size:
|
|
15192
|
-
|
|
15975
|
+
.mp-cl-t b{font-family:var(--fx);font-size:13px;color:var(--lu);font-weight:600;letter-spacing:.03em}
|
|
15976
|
+
.mp-cl-q{font-family:var(--fx);font-size:14px;line-height:2;color:var(--ink);margin-top:3px;letter-spacing:.02em;
|
|
15977
|
+
padding-left:1.05em;text-indent:-1.05em}
|
|
15978
|
+
.mp-cl-p{font-size:12px;line-height:1.9;color:var(--ink2);margin-top:3px}
|
|
15193
15979
|
@media print{.mp-cl{break-inside:avoid}}
|
|
15194
15980
|
@media print{.mp-cli{break-inside:avoid}}
|
|
15195
15981
|
/* —— 起名评估卡片 —— */
|
|
@@ -15220,31 +16006,52 @@ window.Engine = __mods.index;
|
|
|
15220
16006
|
.mp-nm-c em{font-style:normal;font-size:11.5px;line-height:1.7;color:var(--muted);font-family:var(--sans)}
|
|
15221
16007
|
@media print{.mp-nm{break-inside:avoid}}
|
|
15222
16008
|
.mp-quick-pre{margin:0;white-space:pre-wrap;word-break:break-word;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.9;color:var(--ink2)}
|
|
15223
|
-
/* —— 十六型人格卡片 ——
|
|
15224
|
-
|
|
15225
|
-
|
|
15226
|
-
|
|
15227
|
-
.mp-mb
|
|
15228
|
-
.mp-mb-
|
|
15229
|
-
|
|
15230
|
-
.mp-mb-
|
|
15231
|
-
.mp-mb-
|
|
15232
|
-
.mp-mb-
|
|
15233
|
-
.mp-mb-
|
|
15234
|
-
.mp-mb-
|
|
15235
|
-
.mp-mb-
|
|
15236
|
-
.mp-mb-
|
|
15237
|
-
.mp-mb-
|
|
15238
|
-
.mp-mb-
|
|
15239
|
-
.mp-mb-
|
|
15240
|
-
.mp-mb-
|
|
15241
|
-
.mp-mb-
|
|
15242
|
-
.mp-mb-
|
|
15243
|
-
.mp-mb-
|
|
15244
|
-
.mp-mb-
|
|
15245
|
-
.mp-mb-
|
|
15246
|
-
.mp-mb-
|
|
15247
|
-
|
|
16009
|
+
/* —— 十六型人格卡片 ——
|
|
16010
|
+
旧版是「四行细条 + 段落堆叠」:字小、无层级,看着像一份导出的文档。
|
|
16011
|
+
现在按「类型抬头 → 四维瓦片 → 一句 → 优势/留意 → 功能链 → 场景段」分层,
|
|
16012
|
+
四维用左右双极加取值条,颜色只取共享变量,深色与打印都不用另写规则。 */
|
|
16013
|
+
.mp-mb{margin:12px 16px;border:1px solid var(--line);border-radius:12px;background:var(--card);box-shadow:var(--shadow);overflow:hidden;font-family:var(--sans)}
|
|
16014
|
+
.mp-mb-h{display:flex;flex-direction:row;align-items:center;gap:14px;flex-wrap:wrap;padding:15px 18px 14px;
|
|
16015
|
+
background:linear-gradient(135deg,var(--sel),var(--band) 64%,var(--card));border-bottom:1px solid var(--hair)}
|
|
16016
|
+
.mp-mb-code{font-family:var(--fx);font-size:32px;font-weight:700;line-height:1;letter-spacing:.12em;color:var(--ink)}
|
|
16017
|
+
.mp-mb-meta{display:flex;flex-direction:column;gap:3px;min-width:0}
|
|
16018
|
+
.mp-mb-meta b{font-size:14.5px;font-weight:600;color:var(--ink);letter-spacing:.04em}
|
|
16019
|
+
.mp-mb-meta i{font-style:normal;font-size:12px;line-height:1.5;color:var(--muted)}
|
|
16020
|
+
.mp-mb-count{margin-left:auto;padding:3px 10px;border:1px solid var(--line);border-radius:999px;background:var(--card);color:var(--muted);font-size:11.5px;white-space:nowrap}
|
|
16021
|
+
.mp-mb-body{padding:14px 18px 16px}
|
|
16022
|
+
.mp-mb-dims{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
|
|
16023
|
+
.mp-mb-dim{border:1px solid var(--hair);border-radius:10px;background:var(--band);padding:9px 11px 10px}
|
|
16024
|
+
.mp-mb-dh{display:flex;align-items:baseline;gap:6px;font-size:11.5px;color:var(--muted)}
|
|
16025
|
+
.mp-mb-dh b{font-family:var(--fx);font-size:17px;font-weight:600;line-height:1.1;letter-spacing:.08em;color:var(--faint)}
|
|
16026
|
+
.mp-mb-dh b.on{color:var(--ink)}
|
|
16027
|
+
.mp-mb-dh em{font-style:normal;margin:0 auto;font-size:11.5px;letter-spacing:.06em}
|
|
16028
|
+
.mp-mb-bar{position:relative;height:7px;border-radius:4px;background:var(--hair);margin:7px 0 6px;overflow:hidden}
|
|
16029
|
+
.mp-mb-bar::after{content:"";position:absolute;left:50%;top:-1px;bottom:-1px;width:1px;background:color-mix(in srgb,var(--line) 70%,transparent)}
|
|
16030
|
+
.mp-mb-bar em{position:absolute;top:0;bottom:0;background:linear-gradient(90deg,var(--quan),color-mix(in srgb,var(--quan) 55%,var(--card)));border-radius:4px}
|
|
16031
|
+
.mp-mb-bar.l em{left:0}
|
|
16032
|
+
.mp-mb-bar.r em{right:0;background:linear-gradient(270deg,var(--quan),color-mix(in srgb,var(--quan) 55%,var(--card)))}
|
|
16033
|
+
.mp-mb-df{font-size:11.5px;color:var(--ink2);font-variant-numeric:tabular-nums}
|
|
16034
|
+
.mp-mb-ds{margin-top:2px;font-size:11.5px;line-height:1.7;color:var(--muted)}
|
|
16035
|
+
.mp-mb-sec{margin-top:11px;font-size:12.5px;line-height:1.85;color:var(--ink2)}
|
|
16036
|
+
.mp-mb-sec em{display:inline-block;margin-right:7px;padding:0 7px;border:1px solid var(--hair);border-radius:5px;background:var(--band);color:var(--muted);font-size:11px;font-style:normal;letter-spacing:.08em}
|
|
16037
|
+
.mp-mb-two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:11px}
|
|
16038
|
+
.mp-mb-two>div{border:1px solid var(--hair);border-left:3px solid var(--br-good);border-radius:8px;background:var(--card);padding:8px 10px;font-size:12.5px;line-height:1.8;color:var(--ink2)}
|
|
16039
|
+
.mp-mb-two>div+div{border-left-color:var(--br-bad)}
|
|
16040
|
+
.mp-mb-two b{display:block;margin-bottom:2px;font-size:11.5px;font-weight:600;letter-spacing:.08em;color:var(--br-good)}
|
|
16041
|
+
.mp-mb-two>div+div b{color:var(--br-bad)}
|
|
16042
|
+
.mp-mb-fn{display:flex;flex-wrap:wrap;gap:6px;margin-top:7px}
|
|
16043
|
+
.mp-mb-fn span{font-size:11.5px;border:1px solid var(--line);border-radius:999px;background:var(--card);padding:2px 9px;color:var(--ink2)}
|
|
16044
|
+
.mp-mb-fn span.lead{border-color:var(--quan);background:color-mix(in srgb,var(--quan) 9%,var(--card));color:var(--quan);font-weight:600}
|
|
16045
|
+
.mp-mb-fn span b{font-weight:600;margin-right:4px}
|
|
16046
|
+
.mp-mb-note{margin:12px 18px 14px;padding-top:10px;font-size:11px;line-height:1.7;color:var(--muted);border-top:1px solid var(--hair)}
|
|
16047
|
+
.mp-mb-paper{margin:12px 16px;border:1px solid var(--line);border-radius:12px;background:var(--card);box-shadow:var(--shadow);overflow:hidden;font-family:var(--sans)}
|
|
16048
|
+
.mp-mb-paper ol{counter-reset:q;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:4px 20px;
|
|
16049
|
+
margin:0;padding:12px 18px 14px;list-style:none;font-size:12.5px;line-height:1.7;color:var(--ink2)}
|
|
16050
|
+
.mp-mb-paper li{counter-increment:q;position:relative;padding:0 0 6px 26px;border-bottom:1px dashed var(--hair)}
|
|
16051
|
+
.mp-mb-paper li::before{content:counter(q);position:absolute;left:0;top:1px;display:flex;align-items:center;justify-content:center;
|
|
16052
|
+
width:19px;height:19px;border:1px solid var(--hair);border-radius:50%;background:var(--band);color:var(--muted);font-size:10.5px;font-variant-numeric:tabular-nums}
|
|
16053
|
+
.mp-mb-paper .mp-mb-note{margin:0 18px 14px}
|
|
16054
|
+
@media (max-width:640px){.mp-mb-dims,.mp-mb-two,.mp-mb-paper ol{grid-template-columns:1fr}.mp-mb-code{font-size:26px}.mp-mb-body{padding:12px 14px 14px}.mp-mb-h{padding:13px 14px 12px}}
|
|
15248
16055
|
@media print{.mp-mb{break-inside:avoid}}
|
|
15249
16056
|
/* —— 黄历卡片 —— */
|
|
15250
16057
|
.mp-al{margin:12px 16px;border:1px solid var(--line);border-radius:8px;background:var(--card);padding:12px 14px;font-family:system-ui,sans-serif}
|
|
@@ -15683,6 +16490,15 @@ window.Engine = __mods.index;
|
|
|
15683
16490
|
}).join('');
|
|
15684
16491
|
return chips ? `<div class="pp-chips">${chips}</div>` : '';
|
|
15685
16492
|
})() : '';
|
|
16493
|
+
// 三方四正一起飞:四宫 16 条按落宫归堆,只摆会聚的那几条
|
|
16494
|
+
const flyCompositeHTML = r.flyComposite && Array.isArray(r.flyComposite.labels) && r.flyComposite.labels.length
|
|
16495
|
+
? `<div class="pp-chips">${r.flyComposite.labels.map((l) => {
|
|
16496
|
+
const cls = /忌/.test(l) ? 'warn' : /自化/.test(l) ? '' : 'ok';
|
|
16497
|
+
const palaceOf = (x) => String(x).replace(/^.*?会/, '').replace(/^禄忌同宫/, '').replace(/自化$/, '');
|
|
16498
|
+
const hit = (r.flyComposite.targets || []).find((t) => t.palace === palaceOf(l));
|
|
16499
|
+
const tip = hit ? hit.incoming.map((x) => `${x.from}化${x.type}${x.star}`).join('、') : r.flyComposite.note;
|
|
16500
|
+
return `<span class="pp-chip ${cls}" title="${esc(tip)}">三方四正 ${esc(l)}</span>`;
|
|
16501
|
+
}).join('')}</div>` : '';
|
|
15686
16502
|
|
|
15687
16503
|
// 流月/流日/流时:流年只能看到「今年」,要落到「这个月这段时间」得再往下一层
|
|
15688
16504
|
const fl = r.flow;
|
|
@@ -15714,7 +16530,7 @@ window.Engine = __mods.index;
|
|
|
15714
16530
|
${body('ben', soulIdx, 'ben')}
|
|
15715
16531
|
${body('da', dxIdx, 'da')}
|
|
15716
16532
|
${body('ln', lnIdx, 'ln')}
|
|
15717
|
-
</div>${flowHTML}${chips}${flyHTML}${pats}${dxs}${lnHit}`;
|
|
16533
|
+
</div>${flowHTML}${chips}${flyHTML}${flyCompositeHTML}${pats}${dxs}${lnHit}`;
|
|
15718
16534
|
};
|
|
15719
16535
|
|
|
15720
16536
|
// ── 宫位详情 ────────────────────────────────────────────────
|
|
@@ -15910,12 +16726,31 @@ window.Engine = __mods.index;
|
|
|
15910
16726
|
return `<span class="pp-chip ${cls}">${esc(l)}</span>`;
|
|
15911
16727
|
}).join('')}</div>`
|
|
15912
16728
|
: '';
|
|
16729
|
+
// 化进/化退的力重:方向之外再叠月建日辰,单列一排,免与卦体标签混读
|
|
16730
|
+
const jp = r.jinTuiPower && Array.isArray(r.jinTuiPower.labels) ? r.jinTuiPower : null;
|
|
16731
|
+
const jinRow = jp && jp.labels.length
|
|
16732
|
+
? `<div class="pp-chips">${jp.labels.map((l) => {
|
|
16733
|
+
const cls = /后劲足|退得缓/.test(l) ? 'ok' : /有限|进得虚|退得实|月破|未定/.test(l) ? 'warn' : '';
|
|
16734
|
+
return `<span class="pp-chip ${cls}">${esc(l)}</span>`;
|
|
16735
|
+
}).join('')}</div>`
|
|
16736
|
+
: '';
|
|
16737
|
+
// 全卦逐爻旺衰:五态分布 + 世应 + 破动空,用神那排之外的整卦视角
|
|
16738
|
+
const hs = r.hexStrength && Array.isArray(r.hexStrength.labels) ? r.hexStrength : null;
|
|
16739
|
+
const hexRow = hs && hs.labels.length
|
|
16740
|
+
? `<div class="pp-chips">${hs.labels.map((l) => {
|
|
16741
|
+
const cls = /死|囚|月破|冲空/.test(l) ? 'warn'
|
|
16742
|
+
: /旺|相/.test(l) ? 'ok' : '';
|
|
16743
|
+
return `<span class="pp-chip ${cls}">${esc(l)}</span>`;
|
|
16744
|
+
}).join('')}</div>`
|
|
16745
|
+
: '';
|
|
15913
16746
|
return `<div class="pp" style="padding:14px">
|
|
15914
16747
|
<div class="mp-mh-head">起卦 ${r.cast.notation.join('、')}(自下而上) 日辰 ${r.dayGanZhi.name}</div>
|
|
15915
16748
|
<div class="mp-hy-wrap">${ben}${bian}</div>
|
|
15916
16749
|
${bodyRow}
|
|
15917
16750
|
${useRow}
|
|
15918
16751
|
${strengthRow}
|
|
16752
|
+
${jinRow}
|
|
16753
|
+
${hexRow}
|
|
15919
16754
|
</div>`;
|
|
15920
16755
|
};
|
|
15921
16756
|
|
|
@@ -16657,8 +17492,13 @@ window.Engine = __mods.index;
|
|
|
16657
17492
|
}).join('');
|
|
16658
17493
|
const ln = (r.liunian && r.liunian.length) ? `<div class="pp-chips">${r.liunian.slice(0, 8).map((l) => {
|
|
16659
17494
|
const lk = l.luck || null;
|
|
16660
|
-
|
|
17495
|
+
const sy = (l.suiyun && Array.isArray(l.suiyun.signals)) ? l.suiyun.signals : [];
|
|
17496
|
+
const syTip = sy.length ? `|${sy.map((x) => x.detail).join(';')}` : '';
|
|
17497
|
+
return `<span class="pp-chip ${lk ? tierCls(lk.tier) : ''}" title="${esc(lk ? `${lk.tier} ${lk.score}|${(lk.reasons || []).join(';')}${syTip}` : syTip.replace(/^|/, ''))}">${l.year} ${l.ganzhi}${lk ? ` ${lk.tier}` : ''}</span>`;
|
|
16661
17498
|
}).join('')}</div>` : '';
|
|
17499
|
+
const sy = (r.liunian || []).filter((l) => l.suiyun && Array.isArray(l.suiyun.signals) && l.suiyun.signals.length);
|
|
17500
|
+
const syRow = sy.length ? `<div class="pp-tl pp-dim">岁运提示(只标干支变动,不判吉凶)</div><div class="pp-chips">${sy.map((l) =>
|
|
17501
|
+
`<span class="pp-chip" title="${esc(`${l.suiyun.signals.map((x) => x.detail).join(';')}|${l.suiyun.note || ''}`)}">${l.year} ${esc(l.suiyun.signals.map((x) => `${x.type}${x.type.startsWith('流年') && x.target ? `·${x.target}` : ''}`).join('/'))}</span>`).join('')}</div>` : '';
|
|
16662
17502
|
const str = r.strength ? `<div class="pp-str">日主强弱:<b>${r.strength.level}</b>${r.strength.score} <span class="pp-dim">${r.strength.detail}</span></div>` : '';
|
|
16663
17503
|
const ssGroups = (r.shensha && r.shensha.groups) || [];
|
|
16664
17504
|
const ssx = ssGroups.length ? `
|
|
@@ -16678,14 +17518,14 @@ window.Engine = __mods.index;
|
|
|
16678
17518
|
${(Array.isArray(r.classics) && r.classics.length) ? `<section class="mp-cl" aria-label="古籍原文">
|
|
16679
17519
|
<div class="mp-cl-h"><b>古籍原文</b><span>照录通行本,释义为白话自撰</span></div>
|
|
16680
17520
|
${r.classics.map((e) => `<div class="mp-cl-e">
|
|
16681
|
-
<div class="mp-cl-t"><b>${esc((
|
|
17521
|
+
<div class="mp-cl-t"><b>${esc(({ ziping: '子平真诠', ditian: '滴天髓', sanming: '三命通会' }[e.book] || e.book) + '·' + e.chapter)}</b></div>
|
|
16682
17522
|
<div class="mp-cl-q">「${esc(e.quote)}」</div>
|
|
16683
17523
|
<div class="mp-cl-p">${esc(e.plain)}</div>
|
|
16684
17524
|
</div>`).join('')}
|
|
16685
17525
|
</section>` : ''}
|
|
16686
17526
|
${sect('五行与十神', `<div class="pp-chips">${wx}</div>${gods}`)}
|
|
16687
17527
|
${sect('大运', `${pp.curveHTML(r)}<div class="pp-chips">${dy}</div>`)}
|
|
16688
|
-
${ln ? sect('流年', ln) : ''}
|
|
17528
|
+
${ln ? sect('流年', ln + syRow) : ''}
|
|
16689
17529
|
${r.palaces ? sect('胎元与命身宫', `<div class="pp-chips">
|
|
16690
17530
|
<span class="pp-chip" title="${r.palaces.taiyuan.note}">胎元 ${r.palaces.taiyuan.ganzhi}</span>
|
|
16691
17531
|
<span class="pp-chip" title="${r.palaces.minggong.note}">命宫 ${r.palaces.minggong.ganzhi}</span>
|
|
@@ -16848,7 +17688,10 @@ window.Engine = __mods.index;
|
|
|
16848
17688
|
if (r.needAnswers && Array.isArray(r.questions)) {
|
|
16849
17689
|
const items = r.questions.map((q) => `<li>${esc(q.text)}</li>`).join('');
|
|
16850
17690
|
return `<section class="mp-mb-paper" aria-label="十六型人格问卷">
|
|
16851
|
-
<div class="mp-mb-h"
|
|
17691
|
+
<div class="mp-mb-h">
|
|
17692
|
+
<span class="mp-mb-meta"><b>十六型人格问卷</b><i>${r.total} 题 · 每题 1 完全不像 / 5 很像我</i></span>
|
|
17693
|
+
<span class="mp-mb-count">填完分数再看结果</span>
|
|
17694
|
+
</div>
|
|
16852
17695
|
<ol>${items}</ol>
|
|
16853
17696
|
<div class="mp-mb-note">${esc(r.note || '')}</div>
|
|
16854
17697
|
</section>`;
|
|
@@ -16857,32 +17700,35 @@ window.Engine = __mods.index;
|
|
|
16857
17700
|
const pct = Math.round((d.pct || 0) * 100);
|
|
16858
17701
|
const leftOn = d.picked === d.left;
|
|
16859
17702
|
const width = Math.max(2, pct);
|
|
16860
|
-
const bar = leftOn
|
|
16861
|
-
? `<em class="on" style="left:0;width:${width}%"></em>`
|
|
16862
|
-
: `<em class="on" style="right:0;width:${width}%"></em>`;
|
|
16863
17703
|
const say = leftOn ? d.leftSay : d.rightSay;
|
|
16864
17704
|
return `<div class="mp-mb-dim">
|
|
16865
|
-
<b class="${leftOn ? 'on' : ''}">${esc(d.left)}</b>
|
|
16866
|
-
<div class="mp-mb-bar"
|
|
16867
|
-
<
|
|
16868
|
-
<
|
|
17705
|
+
<div class="mp-mb-dh"><b class="${leftOn ? 'on' : ''}">${esc(d.left)}</b><em>${esc(d.name)}</em><b class="${leftOn ? '' : 'on'}">${esc(d.right)}</b></div>
|
|
17706
|
+
<div class="mp-mb-bar ${leftOn ? 'l' : 'r'}"><em style="width:${width}%"></em></div>
|
|
17707
|
+
<div class="mp-mb-df">取 ${esc(d.picked)} · ${esc(d.strength)} ${pct}%</div>
|
|
17708
|
+
<div class="mp-mb-ds">${esc(say)}</div>
|
|
16869
17709
|
</div>`;
|
|
16870
17710
|
}).join('');
|
|
16871
17711
|
const p = r.profile || {};
|
|
16872
|
-
const stack = (p.stack || []).map((f) => `<span>${esc(f.code)}
|
|
17712
|
+
const stack = (p.stack || []).map((f, i) => `<span class="${i === 0 ? 'lead' : ''}"><b>${esc(f.code)}</b>${esc(f.say)}</span>`).join('');
|
|
16873
17713
|
return `<section class="mp-mb" aria-label="十六型人格结果">
|
|
16874
|
-
<div class="mp-mb-h"
|
|
16875
|
-
|
|
16876
|
-
|
|
16877
|
-
|
|
16878
|
-
|
|
16879
|
-
|
|
17714
|
+
<div class="mp-mb-h">
|
|
17715
|
+
<span class="mp-mb-code">${esc(r.type || '')}</span>
|
|
17716
|
+
<span class="mp-mb-meta"><b>${esc(p.title || '')}</b><i>${esc(p.keywords || '')}</i></span>
|
|
17717
|
+
<span class="mp-mb-count">已答 ${r.answered || 0}/${r.total || 0} 题</span>
|
|
17718
|
+
</div>
|
|
17719
|
+
<div class="mp-mb-body">
|
|
17720
|
+
<div class="mp-mb-dims">${dims}</div>
|
|
17721
|
+
<div class="mp-mb-sec"><em>一句</em>${esc(p.oneLine || '')}</div>
|
|
17722
|
+
<div class="mp-mb-two">
|
|
17723
|
+
<div><b>优势</b>${(p.strengths || []).map((s) => esc(s)).join(';')}</div>
|
|
17724
|
+
<div><b>留意</b>${(p.blindspots || []).map((s) => esc(s)).join(';')}</div>
|
|
17725
|
+
</div>
|
|
17726
|
+
${stack ? `<div class="mp-mb-sec"><em>认知功能</em>主导 ${esc((p.stack[0] || {}).code || '')} → 依次展开</div><div class="mp-mb-fn">${stack}</div>` : ''}
|
|
17727
|
+
<div class="mp-mb-sec"><em>工作</em>${esc(p.work || '')}</div>
|
|
17728
|
+
<div class="mp-mb-sec"><em>关系</em>${esc(p.love || '')}</div>
|
|
17729
|
+
<div class="mp-mb-sec"><em>学习</em>${esc(p.study || '')}</div>
|
|
17730
|
+
<div class="mp-mb-sec"><em>课题</em>${esc(p.growth || '')}</div>
|
|
16880
17731
|
</div>
|
|
16881
|
-
${stack ? `<div class="mp-mb-sec"><em>认知功能</em>主导 ${esc((p.stack[0] || {}).code || '')} → 依次展开</div><div class="mp-mb-fn">${stack}</div>` : ''}
|
|
16882
|
-
<div class="mp-mb-sec"><em>工作</em>${esc(p.work || '')}</div>
|
|
16883
|
-
<div class="mp-mb-sec"><em>关系</em>${esc(p.love || '')}</div>
|
|
16884
|
-
<div class="mp-mb-sec"><em>学习</em>${esc(p.study || '')}</div>
|
|
16885
|
-
<div class="mp-mb-sec"><em>课题</em>${esc(p.growth || '')}</div>
|
|
16886
17732
|
<div class="mp-mb-note">${esc(r.note || '')}</div>
|
|
16887
17733
|
</section>`;
|
|
16888
17734
|
};
|
|
@@ -17088,7 +17934,7 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
17088
17934
|
trend: '人生 K 线按大运与流年十神给逐年运势分,画成走势图。',
|
|
17089
17935
|
fengshui: '风水看八宅命卦、大游年四吉四凶与流年九宫飞星;也可按坐向看门主灶倾向。',
|
|
17090
17936
|
name: '起名按八字喜用匹配字库五行,可评估现有名字或生成候选名。',
|
|
17091
|
-
mbti: '十六型人格是一份 MBTI 风格问卷:24
|
|
17937
|
+
mbti: '十六型人格是一份 MBTI 风格问卷:24 题分 6 页,每题按 1(完全不像)到 5(很像我)打分;答满 12 题就能出结果。',
|
|
17092
17938
|
};
|
|
17093
17939
|
|
|
17094
17940
|
// 问事的体系必须写清「所问之事」,解读才有落点;命盘类(八字/紫微)不问事,不显示这两项
|
|
@@ -17417,8 +18263,7 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
17417
18263
|
}
|
|
17418
18264
|
if (tab === 'mbti') {
|
|
17419
18265
|
delete args.datetime;
|
|
17420
|
-
const
|
|
17421
|
-
const nums = box ? String(box.value).split(/[^0-9]+/).filter((x) => x !== '').map((x) => Number(x)) : [];
|
|
18266
|
+
const nums = mbAnswersForEngine();
|
|
17422
18267
|
if (nums.length) args.answers = nums;
|
|
17423
18268
|
}
|
|
17424
18269
|
if (tab === 'trend') { args.gender = el('gender').value; args.toAge = Number(el('toage').value) || 60; args.trueSolar = el('ts').checked; args.lateZi = el('latezi') ? el('latezi').checked : true; }
|
|
@@ -17487,6 +18332,8 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
17487
18332
|
* 「此刻」按钮据此取消。
|
|
17488
18333
|
*/
|
|
17489
18334
|
function goCast() {
|
|
18335
|
+
// 人格问卷没有时间可补:先看答够没有,再走同一套计算
|
|
18336
|
+
if (tab === 'mbti') { mbSubmit(); return; }
|
|
17490
18337
|
const k = kindOf(tab);
|
|
17491
18338
|
if (k !== 'none' && usesTimeInput() && !manual[k]) fillDateTime(nowParts());
|
|
17492
18339
|
run();
|
|
@@ -17512,11 +18359,25 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
17512
18359
|
|
|
17513
18360
|
const QUICK = ['almanac', 'convert', 'zeri', 'chenggu', 'xiaoliuren', 'star', 'numerology', 'trend', 'fengshui', 'name', 'mbti'];
|
|
17514
18361
|
|
|
18362
|
+
// 窄屏下 tab 栏是单行横滑:切到靠后的 tab 时把它滚到可视区中间,
|
|
18363
|
+
// 否则点了「人格」页面变了、高亮却停在屏幕外,看着像没响应
|
|
18364
|
+
function scrollTabIntoView(tabEl) {
|
|
18365
|
+
const strip = tabEl && tabEl.parentElement;
|
|
18366
|
+
if (!strip || strip.scrollWidth <= strip.clientWidth + 1) return;
|
|
18367
|
+
const t = tabEl.getBoundingClientRect();
|
|
18368
|
+
const s = strip.getBoundingClientRect();
|
|
18369
|
+
const left = strip.scrollLeft + (t.left - s.left) - (s.width - t.width) / 2;
|
|
18370
|
+
const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion:reduce)').matches;
|
|
18371
|
+
if (strip.scrollTo) strip.scrollTo({ left, behavior: reduce ? 'auto' : 'smooth' });
|
|
18372
|
+
else strip.scrollLeft = left;
|
|
18373
|
+
}
|
|
18374
|
+
|
|
17515
18375
|
function setTab(next) {
|
|
17516
18376
|
tab = next;
|
|
17517
18377
|
const k = kindOf(tab);
|
|
17518
18378
|
const birth = isBirthTab(tab);
|
|
17519
18379
|
document.querySelectorAll('.tab').forEach((b) => b.classList.toggle('on', b.dataset.tab === tab));
|
|
18380
|
+
scrollTabIntoView(document.querySelector('.tab.on'));
|
|
17520
18381
|
el('for-bazi').style.display = birth ? '' : 'none';
|
|
17521
18382
|
el('for-gender').style.display = birth ? '' : 'none';
|
|
17522
18383
|
el('for-liuyao').style.display = tab === 'liuyao' ? '' : 'none';
|
|
@@ -17549,6 +18410,11 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
17549
18410
|
: tab === 'qimen' ? '起局'
|
|
17550
18411
|
: QUICK.indexOf(tab) >= 0 ? '看结果'
|
|
17551
18412
|
: birth ? '排盘' : '起卦';
|
|
18413
|
+
// 人格问卷自带「看结果」和「清空」:底部再放一个主按钮就是两个一样的入口
|
|
18414
|
+
const mbtiOn = tab === 'mbti';
|
|
18415
|
+
el('go').style.display = mbtiOn ? 'none' : '';
|
|
18416
|
+
const sampleBtn = el('sample');
|
|
18417
|
+
if (sampleBtn) sampleBtn.style.display = mbtiOn ? 'none' : '';
|
|
17552
18418
|
syncMhMode(); // 内含 for-date / for-time 的显隐(塔罗、梅花数字起卦都隐藏)
|
|
17553
18419
|
applyDateTime(k); // 起卦类 → 当前时刻;命盘类 → 示例默认;用户改过则保留
|
|
17554
18420
|
ctxKind = k;
|
|
@@ -17559,8 +18425,8 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
17559
18425
|
document.querySelectorAll('#for-meihua .seg button').forEach((b) => b.classList.toggle('on', b.dataset.mode === mhMode));
|
|
17560
18426
|
const mhNum = tab === 'meihua' && mhMode === 'number';
|
|
17561
18427
|
el('mh-num').style.display = mhNum ? '' : 'none';
|
|
17562
|
-
//
|
|
17563
|
-
const showDT = tab !== 'tarot' && !mhNum;
|
|
18428
|
+
// 梅花「数字起卦」不参与时间计算,日期/时刻在此模式下隐藏,避免误导;人格问卷同样与日期无关
|
|
18429
|
+
const showDT = tab !== 'tarot' && tab !== 'mbti' && !mhNum;
|
|
17564
18430
|
el('for-date').style.display = showDT ? '' : 'none';
|
|
17565
18431
|
el('for-time').style.display = showDT && kindOf(tab) !== 'date' ? '' : 'none';
|
|
17566
18432
|
}
|
|
@@ -17580,11 +18446,191 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
17580
18446
|
if (el('qk-convert-lunar')) el('qk-convert-lunar').style.display = convMode === 'lunar2solar' ? '' : 'none';
|
|
17581
18447
|
}
|
|
17582
18448
|
|
|
18449
|
+
// ── 十六型人格:4 题一页的分页问卷 ──────────────────────────────
|
|
18450
|
+
// 题目与 1–5 的说法都从引擎取(compute 不带 answers 就回问卷),
|
|
18451
|
+
// 前端不再抄一份题目表;答案按题序存在 mbAns 里,null = 未答。
|
|
18452
|
+
const MBTI_PER_PAGE = 4;
|
|
18453
|
+
const MBTI_MIN = 12;
|
|
18454
|
+
let mbPaper = null;
|
|
18455
|
+
let mbAns = [];
|
|
18456
|
+
let mbPage = 0;
|
|
18457
|
+
|
|
18458
|
+
function ensureMbtiPaper() {
|
|
18459
|
+
if (mbPaper) return mbPaper;
|
|
18460
|
+
let p = null;
|
|
18461
|
+
try { p = window.Engine.compute({ system: 'mbti' }); } catch (e) { p = null; }
|
|
18462
|
+
const questions = (p && p.questions) || [];
|
|
18463
|
+
mbPaper = { total: (p && p.total) || questions.length, questions, scale: (p && p.scale) || {} };
|
|
18464
|
+
mbAns = new Array(mbPaper.total).fill(null);
|
|
18465
|
+
return mbPaper;
|
|
18466
|
+
}
|
|
18467
|
+
|
|
18468
|
+
function mbAnswered() {
|
|
18469
|
+
let n = 0;
|
|
18470
|
+
for (let i = 0; i < mbAns.length; i += 1) if (mbAns[i] != null) n += 1;
|
|
18471
|
+
return n;
|
|
18472
|
+
}
|
|
18473
|
+
|
|
18474
|
+
/** 末尾连着没答的先去掉:引擎把 null 当「跳过」,但没必要把整段空位传过去 */
|
|
18475
|
+
function mbAnswersForEngine() {
|
|
18476
|
+
const out = mbAns.slice();
|
|
18477
|
+
while (out.length && out[out.length - 1] == null) out.pop();
|
|
18478
|
+
return out;
|
|
18479
|
+
}
|
|
18480
|
+
|
|
18481
|
+
function mbPageCount() {
|
|
18482
|
+
return Math.max(1, Math.ceil((mbPaper ? mbPaper.total : 0) / MBTI_PER_PAGE));
|
|
18483
|
+
}
|
|
18484
|
+
|
|
18485
|
+
function refreshMbtiMeta() {
|
|
18486
|
+
const total = mbPaper ? mbPaper.total : 0;
|
|
18487
|
+
const answered = mbAnswered();
|
|
18488
|
+
const pages = mbPageCount();
|
|
18489
|
+
const count = el('mbti-count');
|
|
18490
|
+
if (count) count.textContent = `第 ${mbPage + 1} / ${pages} 页 · 已答 ${answered} / ${total}`;
|
|
18491
|
+
const fill = el('mbti-fill');
|
|
18492
|
+
if (fill) fill.style.width = total ? `${Math.round((answered / total) * 100)}%` : '0%';
|
|
18493
|
+
const prev = el('mbti-prev');
|
|
18494
|
+
if (prev) prev.disabled = mbPage <= 0;
|
|
18495
|
+
const next = el('mbti-next');
|
|
18496
|
+
if (next) next.style.display = mbPage >= pages - 1 ? 'none' : '';
|
|
18497
|
+
const sub = el('mbti-submit');
|
|
18498
|
+
if (sub) sub.disabled = answered < MBTI_MIN;
|
|
18499
|
+
const hint = el('mbti-hint');
|
|
18500
|
+
if (hint) {
|
|
18501
|
+
hint.classList.remove('warn');
|
|
18502
|
+
hint.textContent = answered >= MBTI_MIN
|
|
18503
|
+
? `已够 ${MBTI_MIN} 题,可以看结果;答完 ${total} 题会更准。`
|
|
18504
|
+
: `答满 ${MBTI_MIN} 题可先看结果(还差 ${MBTI_MIN - answered} 题)。`;
|
|
18505
|
+
}
|
|
18506
|
+
}
|
|
18507
|
+
|
|
18508
|
+
/** 渲染当前页 4 题。用 createElement 而不是 innerHTML:题面来自引擎,
|
|
18509
|
+
* 但少一层拼接就少一个注入面,也免得转义漏一处就出问题 */
|
|
18510
|
+
function renderMbti() {
|
|
18511
|
+
const host = el('mbti-qs');
|
|
18512
|
+
if (!host) return;
|
|
18513
|
+
const paper = ensureMbtiPaper();
|
|
18514
|
+
mbPage = Math.min(Math.max(0, mbPage), mbPageCount() - 1);
|
|
18515
|
+
const start = mbPage * MBTI_PER_PAGE;
|
|
18516
|
+
host.textContent = '';
|
|
18517
|
+
paper.questions.slice(start, start + MBTI_PER_PAGE).forEach((q, k) => {
|
|
18518
|
+
const i = start + k;
|
|
18519
|
+
const row = document.createElement('div');
|
|
18520
|
+
row.className = 'mb-q';
|
|
18521
|
+
const qt = document.createElement('div');
|
|
18522
|
+
qt.className = 'mb-qt';
|
|
18523
|
+
const no = document.createElement('b');
|
|
18524
|
+
no.textContent = pad(i + 1);
|
|
18525
|
+
const tx = document.createElement('span');
|
|
18526
|
+
tx.textContent = q.text;
|
|
18527
|
+
qt.append(no, tx);
|
|
18528
|
+
const opts = document.createElement('div');
|
|
18529
|
+
opts.className = 'mb-opts';
|
|
18530
|
+
opts.setAttribute('role', 'radiogroup');
|
|
18531
|
+
opts.setAttribute('aria-label', `第 ${i + 1} 题`);
|
|
18532
|
+
[1, 2, 3, 4, 5].forEach((n) => {
|
|
18533
|
+
const lab = document.createElement('label');
|
|
18534
|
+
lab.className = 'mb-o' + (mbAns[i] === n ? ' on' : '');
|
|
18535
|
+
const inp = document.createElement('input');
|
|
18536
|
+
inp.type = 'radio';
|
|
18537
|
+
inp.name = `mbq${i}`;
|
|
18538
|
+
inp.value = String(n);
|
|
18539
|
+
inp.checked = mbAns[i] === n;
|
|
18540
|
+
const b = document.createElement('b');
|
|
18541
|
+
b.textContent = String(n);
|
|
18542
|
+
const say = document.createElement('span');
|
|
18543
|
+
say.textContent = (paper.scale && paper.scale[n]) || '';
|
|
18544
|
+
lab.append(inp, b, say);
|
|
18545
|
+
opts.appendChild(lab);
|
|
18546
|
+
});
|
|
18547
|
+
row.append(qt, opts);
|
|
18548
|
+
host.appendChild(row);
|
|
18549
|
+
});
|
|
18550
|
+
refreshMbtiMeta();
|
|
18551
|
+
}
|
|
18552
|
+
|
|
18553
|
+
function onMbtiPick(e) {
|
|
18554
|
+
const inp = e.target;
|
|
18555
|
+
if (!inp || inp.type !== 'radio' || String(inp.name || '').indexOf('mbq') !== 0) return;
|
|
18556
|
+
const i = Number(String(inp.name).slice(3));
|
|
18557
|
+
if (!Number.isInteger(i) || i < 0 || i >= mbAns.length) return;
|
|
18558
|
+
mbAns[i] = Number(inp.value) || null;
|
|
18559
|
+
// 只改这一题的选中态,不整页重渲染:键盘刚选完还能继续按方向键换选项
|
|
18560
|
+
const row = inp.closest('.mb-q');
|
|
18561
|
+
if (row) row.querySelectorAll('.mb-o').forEach((lab) => lab.classList.toggle('on', lab.contains(inp)));
|
|
18562
|
+
refreshMbtiMeta();
|
|
18563
|
+
}
|
|
18564
|
+
|
|
18565
|
+
function mbTurn(delta) {
|
|
18566
|
+
mbPage = Math.min(Math.max(0, mbPage + delta), mbPageCount() - 1);
|
|
18567
|
+
renderMbti();
|
|
18568
|
+
const stepper = el('for-mbti');
|
|
18569
|
+
if (stepper && stepper.scrollIntoView) stepper.scrollIntoView({ block: 'nearest' });
|
|
18570
|
+
}
|
|
18571
|
+
|
|
18572
|
+
/** 不够 12 题时:提示差几题,并把光标放到本页第一个没答的题上 */
|
|
18573
|
+
function mbNudge() {
|
|
18574
|
+
const hint = el('mbti-hint');
|
|
18575
|
+
if (hint) {
|
|
18576
|
+
hint.classList.add('warn');
|
|
18577
|
+
hint.textContent = `至少答 ${MBTI_MIN} 题才能出结果,还差 ${Math.max(0, MBTI_MIN - mbAnswered())} 题。`;
|
|
18578
|
+
}
|
|
18579
|
+
const host = el('mbti-qs');
|
|
18580
|
+
if (host) {
|
|
18581
|
+
const rows = host.querySelectorAll('.mb-q');
|
|
18582
|
+
for (let k = 0; k < rows.length; k += 1) {
|
|
18583
|
+
if (mbAns[mbPage * MBTI_PER_PAGE + k] == null) {
|
|
18584
|
+
const inp = rows[k].querySelector('input');
|
|
18585
|
+
if (inp && inp.focus) inp.focus({ preventScroll: true });
|
|
18586
|
+
break;
|
|
18587
|
+
}
|
|
18588
|
+
}
|
|
18589
|
+
}
|
|
18590
|
+
const stepper = el('for-mbti');
|
|
18591
|
+
if (stepper && stepper.scrollIntoView) stepper.scrollIntoView({ block: 'nearest' });
|
|
18592
|
+
}
|
|
18593
|
+
|
|
18594
|
+
function mbClear() {
|
|
18595
|
+
mbAns = new Array(mbPaper ? mbPaper.total : 0).fill(null);
|
|
18596
|
+
mbPage = 0;
|
|
18597
|
+
renderMbti();
|
|
18598
|
+
// 清空是「重新答」:旧结果留在下面会让人以为答案还在
|
|
18599
|
+
if (last && last.tab === 'mbti') { last = null; el('out').replaceChildren(); }
|
|
18600
|
+
}
|
|
18601
|
+
|
|
18602
|
+
function mbSubmit() {
|
|
18603
|
+
if (mbAnswered() < MBTI_MIN) { mbNudge(); return; }
|
|
18604
|
+
run();
|
|
18605
|
+
}
|
|
18606
|
+
|
|
18607
|
+
/** 切到人格 tab:答够了就直接出结果,否则清空结果区,只留问卷 */
|
|
18608
|
+
function mbEnter() {
|
|
18609
|
+
renderMbti();
|
|
18610
|
+
if (mbAnswered() >= MBTI_MIN) { run(); return; }
|
|
18611
|
+
last = null;
|
|
18612
|
+
el('out').replaceChildren();
|
|
18613
|
+
}
|
|
18614
|
+
|
|
17583
18615
|
window.addEventListener('DOMContentLoaded', () => {
|
|
17584
18616
|
document.querySelectorAll('.tab').forEach((b) => b.addEventListener('click', () => {
|
|
17585
18617
|
setTab(b.dataset.tab);
|
|
17586
|
-
|
|
18618
|
+
// 人格 tab 的输入就是问卷本身:没答够时不自动算,免得一进来就弹错
|
|
18619
|
+
if (b.dataset.tab === 'mbti') mbEnter(); else run();
|
|
17587
18620
|
}));
|
|
18621
|
+
const mbHost = el('mbti-qs');
|
|
18622
|
+
if (mbHost) {
|
|
18623
|
+
renderMbti();
|
|
18624
|
+
mbHost.addEventListener('change', onMbtiPick);
|
|
18625
|
+
const mbPrev = el('mbti-prev');
|
|
18626
|
+
if (mbPrev) mbPrev.addEventListener('click', () => mbTurn(-1));
|
|
18627
|
+
const mbNext = el('mbti-next');
|
|
18628
|
+
if (mbNext) mbNext.addEventListener('click', () => mbTurn(1));
|
|
18629
|
+
const mbSub = el('mbti-submit');
|
|
18630
|
+
if (mbSub) mbSub.addEventListener('click', mbSubmit);
|
|
18631
|
+
const mbClr = el('mbti-clear');
|
|
18632
|
+
if (mbClr) mbClr.addEventListener('click', mbClear);
|
|
18633
|
+
}
|
|
17588
18634
|
document.querySelectorAll('#for-meihua .seg button').forEach((b) => b.addEventListener('click', () => {
|
|
17589
18635
|
mhMode = b.dataset.mode;
|
|
17590
18636
|
syncMhMode();
|