dsh-metaphysics 0.61.0 → 0.61.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 +60 -2
- package/client.js +325 -325
- package/package.json +1 -1
- package//345/221/275/347/220/206/346/216/222/347/233/230.html +161 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-metaphysics",
|
|
3
|
-
"version": "0.61.
|
|
3
|
+
"version": "0.61.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "命理排盘(玄学 xuanxue)for DeepSeek Harness: nineteen systems and eleven quick references (almanac, solar–lunar conversion, …), with climate adjustment (tiaohou), the 120 Qiongtong Baojian entries, 1,062-char name library with per-character pinyin, Kangxi stroke counts, five-grid (五格/三才) analysis and mechanical phonetics checks, a 78-card tarot library on the Rider-Waite-Smith base (per-card English name, image description, core meaning and astrological correspondence, cross-checked against three published sources; court cards carry no zodiac by design and the chart says so), classical quotes (Ziping Zhenquan / Di Tian Sui / San Ming Tong Hui), hexagram body relations (六冲/六合/伏吟/反吟/化进神/化退神) plus yongshen placement (用神落位) with month/day strength (月建日辰旺衰) and whole-hexagram per-line strength (全卦逐爻旺衰) and response-time clues (应期线索:逢值/逢冲/逢合 + 月建五态快慢) for liuyao, plus an MBTI-style 16-type questionnaire and exact dayun handover dates (交运日) with annual suiyun hints (岁运并临/伏吟反吟), palace conditions (击刑/入墓), month states (旺相休囚死) and stem–palace relations (天盘干与宫生克) for qimen, flying four-transformations with chained flights (四化飞星串连), three-way-four-corner composite flights (三方四正复合飞化), switchable leap-month policy (闰月按日切分/整月归次月/整月归本月) eleven school switches (亮度/庚干四化/天马/天空/截空旬空/魁钺/天伤天使/长生/晚子时/身主/杂曜全表) for ziwei, the last one opting in to a 61-star minor-star (杂曜) table where each of the twelve extra stars carries its placement verse and the palace it landed in (verses accepted only when at least two independent published editions give the same table, homonymous stars never merged), caliber diffs for bazi/ziwei/qimen (same inputs, one switch, root-field changes), shadow-chart IDs (same normalized params → same ID; version bumps auto-diff chart fields), step-by-step deduction traces (liuyao najia→liuqin→shiying→fushen→strength; bazi strength score and pattern/yongshen; ziwei pattern conditions), and a bundled offline single-file page (命理排盘.html), a panel-to-chat handoff that asks the Harness about a finished chart, per-tab lazy engine chunks so the first-screen client bundle stays under 100KB gzip, and a public verification report (128 classical hexagram cases, 312 Zi Wei charts × 34 patterns, 12 dayun handover cases) generated from the same source that gates CI.",
|
|
6
6
|
"keywords": [
|
|
@@ -47,6 +47,10 @@ header{display:flex;flex-direction:column;align-items:stretch;gap:12px;margin-bo
|
|
|
47
47
|
.brand-txt small{display:block;font-size:12.5px;letter-spacing:.02em;color:var(--dim);font-weight:400;margin-top:3px}
|
|
48
48
|
.ver{display:inline-block;margin-left:8px;vertical-align:3px;padding:2px 8px;border:1px solid var(--line);border-radius:999px;background:var(--panel2);
|
|
49
49
|
color:var(--dim);font:600 11px/1.5 system-ui,sans-serif;letter-spacing:.04em}
|
|
50
|
+
/* 未发版改动小牌:紧跟版本徽标,鼠标悬停看逐条。字色用 --ink2 而不是 --dim——
|
|
51
|
+
这行是 11px 小字,压在 --panel2 上,用 --dim 浅色档只有 4.41:1,够不着 AA 的 4.5。 */
|
|
52
|
+
.ver-note{display:inline-block;margin-left:6px;vertical-align:3px;padding:2px 8px;border:1px solid var(--line);border-radius:999px;background:var(--panel2);
|
|
53
|
+
color:var(--ink2);font:400 11px/1.5 "Microsoft YaHei","PingFang SC",system-ui,sans-serif;letter-spacing:0;cursor:help}
|
|
50
54
|
/* 等宽网格铺满一行:每格同宽、末行左对齐,不会出现右对齐造成的锯齿缺口 */
|
|
51
55
|
.tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(74px,1fr));grid-auto-rows:minmax(36px,auto);gap:6px}
|
|
52
56
|
.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;
|
|
@@ -105,6 +109,8 @@ body.view-flat .start{display:none}
|
|
|
105
109
|
#mh-num input{width:124px}
|
|
106
110
|
#changing{width:132px}
|
|
107
111
|
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--gold);box-shadow:var(--ring);background:var(--panel)}
|
|
112
|
+
/* 日期格式写错:输入过程中就转红,失焦会退回最近一次有效值 */
|
|
113
|
+
.field input[aria-invalid="true"]{border-color:var(--bad);box-shadow:0 0 0 2px rgba(167,44,35,.12)}
|
|
108
114
|
.field.check{flex-direction:row;align-items:center;gap:8px;padding-bottom:8px}
|
|
109
115
|
/* 所问之事:多行文本,样式与输入框一致;整组可伸缩,空间不足时自动换行独占一行 */
|
|
110
116
|
.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}
|
|
@@ -247,6 +253,8 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
|
|
|
247
253
|
.view-switch{flex:none}
|
|
248
254
|
.view-switch .seg button{white-space:nowrap}
|
|
249
255
|
.brand .seal{width:34px;height:34px;border-radius:9px;font-size:17px}
|
|
256
|
+
/* 窄屏标题一行都紧张,未发版小牌让位给「方法与验证」里的完整清单,不在这里挤 */
|
|
257
|
+
.ver-note{display:none}
|
|
250
258
|
/* 一行副标题 + 省略号:窄屏下让它换行会把「分组/平铺」顶到下一排,整块头重脚轻 */
|
|
251
259
|
.brand-txt{min-width:0;overflow:hidden}
|
|
252
260
|
.brand-txt small{font-size:11.5px;line-height:1.5;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
@@ -354,7 +362,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
|
|
|
354
362
|
<div class="wrap">
|
|
355
363
|
<header>
|
|
356
364
|
<div class="brand-row">
|
|
357
|
-
<div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.61.
|
|
365
|
+
<div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.61.2</span><small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></span></div>
|
|
358
366
|
<div class="view-switch">
|
|
359
367
|
<span class="hint">熟练了可以换回平铺</span>
|
|
360
368
|
<span class="seg" role="group" aria-label="首屏样式">
|
|
@@ -440,7 +448,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
|
|
|
440
448
|
<div class="bar">
|
|
441
449
|
<!-- 初始值是「命盘类(紫微/八字)」的示例默认:出生时间必然是过去,不取当前时刻。
|
|
442
450
|
切到六爻/梅花/六壬等起卦类 tab 时,web-ui.js 会自动把这两个框换成你的本机当前时刻。 -->
|
|
443
|
-
<label class="field" id="for-date"><span id="lbl-date">出生日期(公历)</span><input id="date" type="
|
|
451
|
+
<label class="field" id="for-date"><span id="lbl-date">出生日期(公历)</span><input id="date" type="text" inputmode="numeric" autocomplete="off" placeholder="年-月-日,如 1990-05-12" value="1990-05-12"></label>
|
|
444
452
|
<label class="field" id="for-time"><span id="lbl-time">出生时刻</span><input id="time" type="time" value="14:30"></label>
|
|
445
453
|
<!-- 时辰未知:只在八字/人生K线出现。勾上=不排时柱、起运降到按日,结果首行固定提示。
|
|
446
454
|
紫微/合盘不提供这个勾选——它们没有时支就整盘不成立,给了勾选等于诱导出一个假盘。 -->
|
|
@@ -458,7 +466,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
|
|
|
458
466
|
<label class="field" id="for-liuyao" style="display:none">六爻<input id="lines" placeholder="9 7 8 8 7 6,空则随机"></label>
|
|
459
467
|
<!-- 合盘:第二个人的出生信息;合盘方式决定用八字还是紫微两盘对照 -->
|
|
460
468
|
<div class="grp" id="for-hepan" style="display:none">
|
|
461
|
-
<label class="field">对方出生日期<input id="pdate" type="
|
|
469
|
+
<label class="field">对方出生日期<input id="pdate" type="text" inputmode="numeric" autocomplete="off" placeholder="年-月-日,如 1992-08-15" value="1992-08-15"></label>
|
|
462
470
|
<label class="field">对方出生时刻<input id="ptime" type="time" value="10:00"></label>
|
|
463
471
|
<label class="field">对方性别
|
|
464
472
|
<select id="pgender"><option value="female">女</option><option value="male">男</option></select>
|
|
@@ -474,7 +482,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
|
|
|
474
482
|
<input id="h3on" type="checkbox"> 三方合盘(加入第三人)
|
|
475
483
|
</label>
|
|
476
484
|
<div class="grp" id="for-hepan3" style="display:none">
|
|
477
|
-
<label class="field">第三方出生日期<input id="p2date" type="
|
|
485
|
+
<label class="field">第三方出生日期<input id="p2date" type="text" inputmode="numeric" autocomplete="off" placeholder="年-月-日,如 1990-01-01" value="1990-01-01"></label>
|
|
478
486
|
<label class="field">第三方出生时刻<input id="p2time" type="time" value="12:00"></label>
|
|
479
487
|
<label class="field">第三方性别
|
|
480
488
|
<select id="p2gender"><option value="female">女</option><option value="male">男</option></select>
|
|
@@ -595,7 +603,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
|
|
|
595
603
|
<label class="field" id="fs-advise2" style="display:none">朝向<input id="facing" placeholder="如 午 / 巽" value="午"></label>
|
|
596
604
|
<label class="field" id="fs-period" style="display:none">运(1–9)<input id="fsperiod" type="number" min="1" max="9" value="9"></label>
|
|
597
605
|
<label class="field" id="fs-offset" style="display:none">兼向度数<input id="fsoffset" type="number" min="-7.5" max="7.5" step="0.5" placeholder="0 = 正向;±4.5 以上用替卦"></label>
|
|
598
|
-
<label class="field" id="fs-date" style="display:none">飞星日期<input id="fsdate" type="
|
|
606
|
+
<label class="field" id="fs-date" style="display:none">飞星日期<input id="fsdate" type="text" inputmode="numeric" autocomplete="off" placeholder="年-月-日,如 2026-11-03"></label>
|
|
599
607
|
<label class="field" id="fs-time" style="display:none">时刻<input id="fstime" type="time" value="12:00"></label>
|
|
600
608
|
</div>
|
|
601
609
|
<!-- 人格问卷:4 题一页、1–5 打分。题目与 1–5 的说明由 web-ui 从引擎取,
|
|
@@ -645,7 +653,8 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
|
|
|
645
653
|
<h3>对拍:把典籍当期望值</h3>
|
|
646
654
|
<ul><li>六爻:京房八宫卦序与世应,64 卦全表;旬空六旬表</li><li>六壬:日干寄宫、中气换将;紫微:纳音定五行局、紫微天府相照</li><li>卦例:《增删卜易》9 条 +《卜筮正宗》128 条(93 成对 + 35 静卦),核本变卦 / 动爻数 / 卦宫 / 缺爻 / 旬空</li><li>奇门:20 个时辰 × 9 宫,核四柱 / 局数 / 值符 / 值使 / 星门神 / 天盘干</li></ul>
|
|
647
655
|
<h3>工程验证</h3>
|
|
648
|
-
<ul><li>测试:
|
|
656
|
+
<ul><li>测试:154 个测试文件 / 7637 条断言;七道闸(回归 · 断言基线 · 测试可失败自检 · HTML 注入面 · 工程约定 · 产物宿主形态 · 随机扫射)</li><li>可复现:seed / asOf 显式;同一输入同一输出</li><li>口径:晚子时、真太阳时、奇门三流派、闰月归月都可切换,并有字段级差异对照</li></ul>
|
|
657
|
+
|
|
649
658
|
<h3>已知边界(不猜)</h3>
|
|
650
659
|
<ul><li>六爻应期(具体哪天应验)不做;卦例只录动爻个数,不录爻位</li><li>财富/健康只给结构判断与档位,不给金额区间、不作诊断</li><li>紫微飞星已做「单一支化逐宫追到成环」与「三方四正 16 条按落宫归堆」,但都未叠大限流年四化、不折吉凶;八字交运日已能算到日/时,但未与第三方排盘案例批量对拍</li></ul>
|
|
651
660
|
<p class="note">内容用于传统文化学习与自我探索,不构成医疗、投资、法律或人事决策依据。</p>
|
|
@@ -26311,7 +26320,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
26311
26320
|
})();
|
|
26312
26321
|
|
|
26313
26322
|
window.Engine = __mods.index;
|
|
26314
|
-
window.__MP_VER = "0.61.
|
|
26323
|
+
window.__MP_VER = "0.61.2";
|
|
26315
26324
|
</script>
|
|
26316
26325
|
<script>
|
|
26317
26326
|
// 两个 UI 共用的表单规则:宿主面板(src/app.js)与独立页(src/web-ui.js)。
|
|
@@ -29796,6 +29805,9 @@ window.__MP_VER = "0.61.0";
|
|
|
29796
29805
|
hourUnknown: hu,
|
|
29797
29806
|
gender: String(src.gender || ''),
|
|
29798
29807
|
address: String(src.address || ''),
|
|
29808
|
+
// 两个开关也换一张盘:不随档案存,载入时就会跟着表单此刻的勾选排
|
|
29809
|
+
trueSolar: src.trueSolar !== false,
|
|
29810
|
+
lateZi: src.lateZi !== false,
|
|
29799
29811
|
pinned: false,
|
|
29800
29812
|
createdAt: Date.now(),
|
|
29801
29813
|
lastUsedAt: 0,
|
|
@@ -30266,6 +30278,86 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30266
30278
|
|
|
30267
30279
|
const el = (id) => document.getElementById(id);
|
|
30268
30280
|
const pad = (n) => String(n).padStart(2, '0');
|
|
30281
|
+
|
|
30282
|
+
// ── 公历日期输入:固定「年-月-日」 ─────────────────────────────
|
|
30283
|
+
// 原生 date 控件的顺序跟随浏览器区域,容易出现月/日/年或日/月/年。
|
|
30284
|
+
// 改成文本输入 + 数字掩码:显示始终是 YYYY-MM-DD,也认 1990/5/12、1990年5月12日。
|
|
30285
|
+
function isoDateOk(s) {
|
|
30286
|
+
const ymd = /^(\d{4})-(\d{2})-(\d{2})$/.exec(String(s || ''));
|
|
30287
|
+
if (!ymd) return false;
|
|
30288
|
+
const y = Number(ymd[1]);
|
|
30289
|
+
const mo = Number(ymd[2]);
|
|
30290
|
+
const d = Number(ymd[3]);
|
|
30291
|
+
if (mo < 1 || mo > 12 || d < 1) return false;
|
|
30292
|
+
const leap = (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0;
|
|
30293
|
+
const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
30294
|
+
return d <= days[mo - 1];
|
|
30295
|
+
}
|
|
30296
|
+
function normalizeDateText(raw) {
|
|
30297
|
+
const ymd = /^(\d{4})\s*[年./-]\s*(\d{1,2})\s*[月./-]\s*(\d{1,2})\s*日?$/.exec(String(raw || '').trim());
|
|
30298
|
+
if (!ymd) return '';
|
|
30299
|
+
const iso = `${ymd[1]}-${pad(ymd[2])}-${pad(ymd[3])}`;
|
|
30300
|
+
return isoDateOk(iso) ? iso : '';
|
|
30301
|
+
}
|
|
30302
|
+
function maskDateText(raw) {
|
|
30303
|
+
const s = String(raw || '').trim();
|
|
30304
|
+
// 连字符日期在输入过程中原样保留(含只打出「1990-5-」的中间态):刚敲下「1」
|
|
30305
|
+
// 就补成「01」,再敲「2」会变成 012 被截掉。等失焦时再统一补零;
|
|
30306
|
+
// 斜杠/中文/点号视为粘贴,直接归一。
|
|
30307
|
+
if (/^\d{0,4}(-\d{0,2}){0,2}$/.test(s)) return s;
|
|
30308
|
+
if (/[年月日/.]/.test(s)) {
|
|
30309
|
+
const full = normalizeDateText(s);
|
|
30310
|
+
if (full) return full;
|
|
30311
|
+
}
|
|
30312
|
+
const digits = s.replace(/\D/g, '').slice(0, 8);
|
|
30313
|
+
if (digits.length <= 4) return digits;
|
|
30314
|
+
if (digits.length <= 6) return `${digits.slice(0, 4)}-${digits.slice(4)}`;
|
|
30315
|
+
return `${digits.slice(0, 4)}-${digits.slice(4, 6)}-${digits.slice(6)}`;
|
|
30316
|
+
}
|
|
30317
|
+
/** 程序填值(示例 / 切 tab):同步掩码与「最近一次有效值」 */
|
|
30318
|
+
function setDateField(id, iso) {
|
|
30319
|
+
const input = el(id);
|
|
30320
|
+
if (!input) return;
|
|
30321
|
+
const v = normalizeDateText(iso) || '';
|
|
30322
|
+
input.value = v;
|
|
30323
|
+
input.dataset.last = v;
|
|
30324
|
+
input.setAttribute('aria-invalid', 'false');
|
|
30325
|
+
}
|
|
30326
|
+
function bindDateInput(id) {
|
|
30327
|
+
const input = el(id);
|
|
30328
|
+
if (!input) return;
|
|
30329
|
+
const initial = normalizeDateText(input.value);
|
|
30330
|
+
if (initial) input.value = initial;
|
|
30331
|
+
input.dataset.last = initial || '';
|
|
30332
|
+
input.setAttribute('type', 'text');
|
|
30333
|
+
input.setAttribute('inputmode', 'numeric');
|
|
30334
|
+
input.setAttribute('autocomplete', 'off');
|
|
30335
|
+
input.setAttribute('placeholder', '年-月-日,如 1990-05-12');
|
|
30336
|
+
input.addEventListener('input', () => {
|
|
30337
|
+
const next = maskDateText(input.value);
|
|
30338
|
+
if (input.value !== next) input.value = next;
|
|
30339
|
+
const iso = normalizeDateText(next);
|
|
30340
|
+
if (iso) input.dataset.last = iso;
|
|
30341
|
+
input.setAttribute('aria-invalid', iso || !next.trim() ? 'false' : 'true');
|
|
30342
|
+
});
|
|
30343
|
+
input.addEventListener('blur', () => {
|
|
30344
|
+
const raw = input.value.trim();
|
|
30345
|
+
if (!raw) { input.setAttribute('aria-invalid', 'false'); return; }
|
|
30346
|
+
const iso = normalizeDateText(raw);
|
|
30347
|
+
if (iso) {
|
|
30348
|
+
input.value = iso;
|
|
30349
|
+
input.dataset.last = iso;
|
|
30350
|
+
input.setAttribute('aria-invalid', 'false');
|
|
30351
|
+
return;
|
|
30352
|
+
}
|
|
30353
|
+
// 写错了就退回最近一次有效值,别把一个非法日期留在框里等着排盘
|
|
30354
|
+
input.value = input.dataset.last || '';
|
|
30355
|
+
input.setAttribute('aria-invalid', 'false');
|
|
30356
|
+
});
|
|
30357
|
+
}
|
|
30358
|
+
function bindDateInputs() {
|
|
30359
|
+
['date', 'pdate', 'p2date', 'fsdate'].forEach(bindDateInput);
|
|
30360
|
+
}
|
|
30269
30361
|
// 首屏耗时只在本机显示,不上报
|
|
30270
30362
|
const mpNow = () => (typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now());
|
|
30271
30363
|
|
|
@@ -30375,10 +30467,16 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30375
30467
|
const puts = [['date', p.date], ['time', p.hourUnknown ? '' : p.time], ['gender', p.gender], ['addr', p.address]];
|
|
30376
30468
|
for (const pair of puts) {
|
|
30377
30469
|
const node = el(pair[0]);
|
|
30378
|
-
|
|
30470
|
+
// 空出生地也要写回去:留着上一个地址,这张盘的真太阳时就会按别人的地方算
|
|
30471
|
+
if (node) node.value = pair[1] || '';
|
|
30379
30472
|
}
|
|
30380
30473
|
const hu = el('hourunknown');
|
|
30381
30474
|
if (hu) hu.checked = !!p.hourUnknown;
|
|
30475
|
+
// 旧档案没存开关:按默认(都开)处理,别沿用表单此刻的勾选
|
|
30476
|
+
const tsBox = el('ts');
|
|
30477
|
+
if (tsBox) tsBox.checked = p.trueSolar !== false;
|
|
30478
|
+
const lzBox = el('latezi');
|
|
30479
|
+
if (lzBox) lzBox.checked = p.lateZi !== false;
|
|
30382
30480
|
// 把这次回填当成「用户填的」:否则切走再切回出生类体系时会被上一次的自动值顶掉
|
|
30383
30481
|
onManualEdit();
|
|
30384
30482
|
run();
|
|
@@ -30391,9 +30489,14 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30391
30489
|
const hu = el('hourunknown');
|
|
30392
30490
|
const box = el('profwrap');
|
|
30393
30491
|
const nameEl = box ? box.querySelector('.mp-prof-name') : null;
|
|
30492
|
+
const tsBox = el('ts');
|
|
30493
|
+
const lzBox = el('latezi');
|
|
30394
30494
|
return PP.profFromForm({
|
|
30395
30495
|
kind: tab, date: v('date'), time: v('time'), gender: v('gender'), address: v('addr'),
|
|
30396
30496
|
hourUnknown: !!(hu && hu.checked),
|
|
30497
|
+
// 两个开关决定时柱:随档案存下来,载入才能回到当初那张盘
|
|
30498
|
+
trueSolar: !(tsBox && !tsBox.checked),
|
|
30499
|
+
lateZi: !(lzBox && !lzBox.checked),
|
|
30397
30500
|
}, nameEl ? nameEl.value : '', profEditing || undefined);
|
|
30398
30501
|
}
|
|
30399
30502
|
|
|
@@ -30424,7 +30527,8 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30424
30527
|
const puts = [['date', p.date], ['time', p.hourUnknown ? '' : p.time], ['gender', p.gender], ['addr', p.address]];
|
|
30425
30528
|
for (const pair of puts) {
|
|
30426
30529
|
const node = el(pair[0]);
|
|
30427
|
-
|
|
30530
|
+
// 同上:这张档案没存地址就把框清空,别让「更新」把别人的地址存进来
|
|
30531
|
+
if (node) node.value = pair[1] || '';
|
|
30428
30532
|
}
|
|
30429
30533
|
const hu = el('hourunknown');
|
|
30430
30534
|
if (hu) hu.checked = !!p.hourUnknown;
|
|
@@ -30562,7 +30666,7 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30562
30666
|
|
|
30563
30667
|
/** 程序填值:写入 input 并记下「这是程序填的」,不置手动标记 */
|
|
30564
30668
|
function fillDateTime(v) {
|
|
30565
|
-
|
|
30669
|
+
setDateField('date', v.date);
|
|
30566
30670
|
el('time').value = v.time;
|
|
30567
30671
|
autoDate = v.date;
|
|
30568
30672
|
autoTime = v.time;
|
|
@@ -30576,9 +30680,10 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30576
30680
|
fillDateTime(manual[k] || defaultFor(k));
|
|
30577
30681
|
}
|
|
30578
30682
|
|
|
30579
|
-
/** 当前 tab
|
|
30683
|
+
/** 当前 tab 是否真的用到日期/时刻(塔罗、人格不看时间;梅花「数字起卦」也不用)
|
|
30684
|
+
* 与 syncMhMode 里的显隐共用这一处判断:字段既然藏起来了,run() 就不能拿它拦人。 */
|
|
30580
30685
|
function usesTimeInput() {
|
|
30581
|
-
return !(tab === 'meihua' && mhMode === 'number');
|
|
30686
|
+
return tab !== 'tarot' && tab !== 'mbti' && !(tab === 'meihua' && mhMode === 'number');
|
|
30582
30687
|
}
|
|
30583
30688
|
|
|
30584
30689
|
/** 用户手动改了日期或时刻 */
|
|
@@ -30865,11 +30970,11 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30865
30970
|
day: Number(last.date.slice(8, 10)),
|
|
30866
30971
|
minute: Number(last.time.slice(3, 5)) || 0,
|
|
30867
30972
|
},
|
|
30868
|
-
gender:
|
|
30973
|
+
gender: last.gender,
|
|
30869
30974
|
events,
|
|
30870
|
-
lateZi:
|
|
30871
|
-
trueSolar:
|
|
30872
|
-
address:
|
|
30975
|
+
lateZi: last.lateZi !== false,
|
|
30976
|
+
trueSolar: last.trueSolar !== false,
|
|
30977
|
+
address: last.address || undefined,
|
|
30873
30978
|
}) : { error: '当前页面未加载生时校正模块' };
|
|
30874
30979
|
} catch (e) { rectOut = { error: e && e.message ? e.message : String(e) }; }
|
|
30875
30980
|
const out = el('rectout');
|
|
@@ -30939,6 +31044,21 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30939
31044
|
const myRun = ++runSeq;
|
|
30940
31045
|
const startTab = tab;
|
|
30941
31046
|
const date = el('date').value;
|
|
31047
|
+
if (usesTimeInput() && !isoDateOk(date)) {
|
|
31048
|
+
last = null;
|
|
31049
|
+
el('out').innerHTML = '<div class="err">请填写公历日期,按「年-月-日」输入,例如 1990-05-12。</div>';
|
|
31050
|
+
return;
|
|
31051
|
+
}
|
|
31052
|
+
if (tab === 'hepan' && !isoDateOk(el('pdate').value)) {
|
|
31053
|
+
last = null;
|
|
31054
|
+
el('out').innerHTML = '<div class="err">请填写对方的公历出生日期,按「年-月-日」输入,例如 1992-08-15。</div>';
|
|
31055
|
+
return;
|
|
31056
|
+
}
|
|
31057
|
+
if (tab === 'hepan' && el('h3on') && el('h3on').checked && !isoDateOk(el('p2date').value)) {
|
|
31058
|
+
last = null;
|
|
31059
|
+
el('out').innerHTML = '<div class="err">请填写第三方的公历出生日期,按「年-月-日」输入,例如 1990-01-01。</div>';
|
|
31060
|
+
return;
|
|
31061
|
+
}
|
|
30942
31062
|
// 勾了「时辰未知」就不读钟点:读出来的只是占位值,用它排出来的时柱是编的
|
|
30943
31063
|
const hourUnknown = !!(el('hourunknown') && el('hourunknown').checked) && (tab === 'bazi' || tab === 'trend');
|
|
30944
31064
|
const time = hourUnknown ? '12:00' : el('time').value;
|
|
@@ -30958,7 +31078,8 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
30958
31078
|
// 推导链只覆盖六爻 / 八字 / 紫微
|
|
30959
31079
|
args.trace = tab === 'liuyao' || tab === 'bazi' || tab === 'ziwei' || tab === 'qimen' || tab === 'daliuren';
|
|
30960
31080
|
if (tab !== 'tarot') args.datetime = `${date}T${time}`;
|
|
30961
|
-
|
|
31081
|
+
// 人生K线也是出生盘:出生地决定真太阳时,落进时柱后会改变整条运程
|
|
31082
|
+
if (tab === 'bazi' || tab === 'ziwei' || tab === 'hepan' || tab === 'trend') {
|
|
30962
31083
|
// 合盘主方同样要性别与出生地:引擎里合盘的性别是必填,地址决定真太阳时
|
|
30963
31084
|
args.gender = el('gender').value;
|
|
30964
31085
|
if (hourUnknown) args.hourUnknown = true;
|
|
@@ -31040,8 +31161,9 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
31040
31161
|
args.num3 = Number(el('num3').value) || undefined;
|
|
31041
31162
|
} else {
|
|
31042
31163
|
args.date = date;
|
|
31043
|
-
|
|
31044
|
-
|
|
31164
|
+
// Number('') 是 0:时刻框被清空时不能悄悄按子时起课,退回正午
|
|
31165
|
+
const hm = /^(\d{1,2}):/.exec(String(time));
|
|
31166
|
+
args.hour = hm ? Number(hm[1]) : 12;
|
|
31045
31167
|
}
|
|
31046
31168
|
}
|
|
31047
31169
|
if (tab === 'convert') {
|
|
@@ -31060,7 +31182,8 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
31060
31182
|
if (nums.length) args.answers = nums;
|
|
31061
31183
|
}
|
|
31062
31184
|
if (tab === 'trend' && hourUnknown) args.hourUnknown = true;
|
|
31063
|
-
|
|
31185
|
+
// 性别 / 出生地 / 两个开关已在上面的出生盘分支里给齐,这里只补 K 线自己的参数
|
|
31186
|
+
if (tab === 'trend') args.toAge = Number(el('toage').value) || 60;
|
|
31064
31187
|
if (tab === 'fengshui') {
|
|
31065
31188
|
args.action = fsMode;
|
|
31066
31189
|
if (fsMode === 'natal') { args.gender = el('gender').value; }
|
|
@@ -31073,6 +31196,11 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
31073
31196
|
const off = el('fsoffset') ? el('fsoffset').value.trim() : '';
|
|
31074
31197
|
if (off !== '') args.sittingOffset = Number(off);
|
|
31075
31198
|
const fd = el('fsdate') ? el('fsdate').value.trim() : '';
|
|
31199
|
+
if (fd && !isoDateOk(fd)) {
|
|
31200
|
+
last = null;
|
|
31201
|
+
el('out').innerHTML = '<div class="err">飞星日期请按「年-月-日」填写,例如 2026-11-03。</div>';
|
|
31202
|
+
return;
|
|
31203
|
+
}
|
|
31076
31204
|
if (fd) args.fortuneDate = fd;
|
|
31077
31205
|
const ft = el('fstime') ? el('fstime').value.trim() : '';
|
|
31078
31206
|
if (ft) args.fortuneTime = ft;
|
|
@@ -31141,7 +31269,16 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
31141
31269
|
: tab === 'mbti' ? window.__PP.mbtiHTML(r)
|
|
31142
31270
|
: tab === 'fengshui' ? window.__PP.fengshuiHTML(r)
|
|
31143
31271
|
: window.__PP.quickHTML(r));
|
|
31144
|
-
|
|
31272
|
+
// 新盘就是新的一轮:上一次的自评、贴合度、候选时辰不能跟着贴到这张盘上
|
|
31273
|
+
// (它们只在模块里存着,重绘不会自己清)。
|
|
31274
|
+
pastMarks = {}; pastFit = null; rectOut = null;
|
|
31275
|
+
// 生时校正要按「这张盘自己的输入」反推:档案/表单在排完之后还能改,
|
|
31276
|
+
// 只读 last.date 而性别、出生地读表单,候选时辰就会贴到另一张盘上
|
|
31277
|
+
last = { r, html, tab, date, time, timed, trend, caliber, shadowDiff,
|
|
31278
|
+
gender: args.gender || el('gender').value,
|
|
31279
|
+
address: typeof args.address === 'string' ? args.address : '',
|
|
31280
|
+
trueSolar: typeof args.trueSolar === 'boolean' ? args.trueSolar : true,
|
|
31281
|
+
lateZi: typeof args.lateZi === 'boolean' ? args.lateZi : true };
|
|
31145
31282
|
const paintStart = mpNow();
|
|
31146
31283
|
paint();
|
|
31147
31284
|
// 渲染=组 HTML + 写入 DOM 的同步时间;浏览器真正绘制在下一帧,这里不假装量到
|
|
@@ -31264,7 +31401,7 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
31264
31401
|
const mhNum = tab === 'meihua' && mhMode === 'number';
|
|
31265
31402
|
el('mh-num').style.display = mhNum ? '' : 'none';
|
|
31266
31403
|
// 梅花「数字起卦」不参与时间计算,日期/时刻在此模式下隐藏,避免误导;人格问卷同样与日期无关
|
|
31267
|
-
const showDT =
|
|
31404
|
+
const showDT = usesTimeInput();
|
|
31268
31405
|
el('for-date').style.display = showDT ? '' : 'none';
|
|
31269
31406
|
// 「时辰未知」只对八字与人生K线开放:紫微/合盘没有时支就没有盘,不提供这个勾选
|
|
31270
31407
|
const canUnknown = tab === 'bazi' || tab === 'trend';
|
|
@@ -31464,6 +31601,7 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
31464
31601
|
}
|
|
31465
31602
|
|
|
31466
31603
|
window.addEventListener('DOMContentLoaded', () => {
|
|
31604
|
+
bindDateInputs();
|
|
31467
31605
|
// 两套入口(平铺 tab 与分组卡片)走同一条激活路径,避免行为分叉
|
|
31468
31606
|
document.querySelectorAll('.tab, .tool').forEach((b) => b.addEventListener('click', () => activate(b.dataset.tab)));
|
|
31469
31607
|
document.querySelectorAll('.view-switch [data-view]').forEach((b) => b.addEventListener('click', () => {
|
|
@@ -31523,7 +31661,7 @@ document.head.appendChild(Object.assign(document.createElement('style'), { textC
|
|
|
31523
31661
|
// 看示例:填固定示例盘并切到八字,走与真实排盘完全相同的渲染路径
|
|
31524
31662
|
const sampleBtn = el('sample');
|
|
31525
31663
|
if (sampleBtn) sampleBtn.addEventListener('click', () => {
|
|
31526
|
-
|
|
31664
|
+
setDateField('date', SAMPLE.date);
|
|
31527
31665
|
el('time').value = SAMPLE.time;
|
|
31528
31666
|
el('gender').value = 'male';
|
|
31529
31667
|
el('addr').value = '河北石家庄';
|