dsh-metaphysics 0.18.4 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +16 -13
- package/client.js +754 -67
- package/engine/almanac.js +137 -3
- package/engine/bazi.js +2 -1
- package/engine/convert.js +137 -0
- package/engine/geju.js +67 -46
- package/engine/geo.js +1 -1
- package/engine/index.js +52 -5
- package/engine/interpret.js +1365 -1356
- package/engine/tiaohou.js +228 -0
- package/engine/zeri.js +29 -2
- package/index.js +15 -5
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +2 -2
package/client.js
CHANGED
|
@@ -746,7 +746,7 @@ function resolveAddress(input) {
|
|
|
746
746
|
|
|
747
747
|
const DETAIL = /(区|县|镇|乡|村|小区|街道|路|号|巷|弄|组|队)/;
|
|
748
748
|
|
|
749
|
-
const USER_AGENT = 'dsh-metaphysics/0.
|
|
749
|
+
const USER_AGENT = 'dsh-metaphysics/0.20.0 (+https://github.com/xuanfu-web/dsh-metaphysics)';
|
|
750
750
|
|
|
751
751
|
async function onlineLookup(text, { timeoutMs = 2500 } = {}) {
|
|
752
752
|
if (typeof fetch !== 'function') return null;
|
|
@@ -1280,8 +1280,216 @@ const RULE_TABLE = RULES.reduce((acc, r) => { acc[r.name] = { cat: r.cat, luck:
|
|
|
1280
1280
|
return { PILLAR_KEYS, PILLAR_LABEL, CATEGORY_ORDER, computeBaziShensha, RULE_TABLE };
|
|
1281
1281
|
})();
|
|
1282
1282
|
|
|
1283
|
+
__mods.tiaohou = (function () {
|
|
1284
|
+
|
|
1285
|
+
const STEM_ELEMENT = {
|
|
1286
|
+
甲: '木', 乙: '木', 丙: '火', 丁: '火', 戊: '土',
|
|
1287
|
+
己: '土', 庚: '金', 辛: '金', 壬: '水', 癸: '水',
|
|
1288
|
+
};
|
|
1289
|
+
|
|
1290
|
+
const SEASON_TEMP = {
|
|
1291
|
+
亥: -1.8, 子: -2, 丑: -1.5,
|
|
1292
|
+
寅: -0.4, 卯: 0.2, 辰: 0.5,
|
|
1293
|
+
巳: 1.3, 午: 2, 未: 1.5,
|
|
1294
|
+
申: 0.6, 酉: 0.2, 戌: -0.2,
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1297
|
+
const SEASON_NAME = {
|
|
1298
|
+
亥: '初冬', 子: '仲冬', 丑: '季冬',
|
|
1299
|
+
寅: '初春', 卯: '仲春', 辰: '季春',
|
|
1300
|
+
巳: '初夏', 午: '仲夏', 未: '季夏',
|
|
1301
|
+
申: '初秋', 酉: '仲秋', 戌: '季秋',
|
|
1302
|
+
};
|
|
1303
|
+
|
|
1304
|
+
const WET_BRANCH = { 丑: 1, 辰: 1, 子: 0.6, 亥: 0.5 };
|
|
1305
|
+
const DRY_BRANCH = { 未: 1, 戌: 1, 午: 0.4, 巳: 0.4 };
|
|
1306
|
+
|
|
1307
|
+
const NEED = {
|
|
1308
|
+
寒湿: { element: '火', stem: '丙', avoid: '水', why: '冻土要太阳来解,水再多只会更冷' },
|
|
1309
|
+
寒燥: { element: '火', stem: '丙', avoid: '水', why: '天寒地干,先要一点阳和之气' },
|
|
1310
|
+
寒: { element: '火', stem: '丙', avoid: '水', why: '冬令气寒,非火不暖' },
|
|
1311
|
+
温热: { element: '水', stem: '壬', avoid: '火', why: '火气初旺,得水润泽才好用' },
|
|
1312
|
+
燥热: { element: '水', stem: '壬', avoid: '火', why: '火炎土燥,非水不润' },
|
|
1313
|
+
热: { element: '水', stem: '壬', avoid: '火', why: '夏令炎威,先求一泓清水' },
|
|
1314
|
+
湿滞: { element: '火', stem: '丙', avoid: '水', why: '湿气郁结,要火来蒸腾' },
|
|
1315
|
+
燥: { element: '水', stem: '壬', avoid: '火', why: '气燥不润,得水则舒' },
|
|
1316
|
+
平和: { element: null, stem: null, avoid: null, why: '寒暖相济,气候不是这一盘的主要矛盾' },
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1319
|
+
const KIND_NAME = {
|
|
1320
|
+
寒湿: '寒湿', 寒燥: '寒燥', 寒: '寒',
|
|
1321
|
+
温热: '温热', 燥热: '燥热', 热: '热',
|
|
1322
|
+
湿滞: '湿滞', 燥: '燥', 平和: '平和',
|
|
1323
|
+
};
|
|
1324
|
+
|
|
1325
|
+
const DAY_FEEL = {
|
|
1326
|
+
寒湿: {
|
|
1327
|
+
木: '木是花草藤萝,冰封的土里抽不出芽——它不缺雨水,缺的是一轮太阳',
|
|
1328
|
+
火: '火在冬天最怕被水浇,一点火苗要护住,才谈得上发光',
|
|
1329
|
+
土: '土冻成一块,再厚也长不出东西,得先晒透',
|
|
1330
|
+
金: '金在寒水里泡久了,锋刃会发滞,要火来炼一炼',
|
|
1331
|
+
水: '水本就冷,再加寒就是死水;要火把它烧活',
|
|
1332
|
+
},
|
|
1333
|
+
寒燥: {
|
|
1334
|
+
木: '木在干冷里最难熬,既缺暖气,又缺一点滋润',
|
|
1335
|
+
火: '火在寒天里要先活下来,才有余力照别人',
|
|
1336
|
+
土: '土冷而干,板结着,得暖气与一点水汽一起松',
|
|
1337
|
+
金: '金寒则脆,得火炼、得土养,才成器',
|
|
1338
|
+
水: '水在寒天里收得太紧,要一点火气化开',
|
|
1339
|
+
},
|
|
1340
|
+
寒: {
|
|
1341
|
+
木: '冬木先要暖,暖了才谈得上发荣',
|
|
1342
|
+
火: '火在冬天要护住,别被冷风吹散',
|
|
1343
|
+
土: '土寒不生物,先暖后养',
|
|
1344
|
+
金: '金寒则钝,得火则利',
|
|
1345
|
+
水: '水寒则滞,得火则行',
|
|
1346
|
+
},
|
|
1347
|
+
温热: {
|
|
1348
|
+
木: '木在暖和里长得快,但要防长得太急、根扎不深',
|
|
1349
|
+
火: '火得时令,容易旺过头,要留一点水来收',
|
|
1350
|
+
土: '土被火烤着,容易燥,得水润一润',
|
|
1351
|
+
金: '金在暖处容易软,需要一点水土把它养住',
|
|
1352
|
+
水: '水在暖处容易蒸干,要源头不断',
|
|
1353
|
+
},
|
|
1354
|
+
燥热: {
|
|
1355
|
+
木: '木被火烤着,叶子先焦,得先补水',
|
|
1356
|
+
火: '火已经够旺了,再添柴只会烧到自己',
|
|
1357
|
+
土: '土燥则裂,得水润、得木疏',
|
|
1358
|
+
金: '金在燥热里容易发烫变形,要水来淬',
|
|
1359
|
+
水: '水在燥热里最珍贵,一滴都不能浪费',
|
|
1360
|
+
},
|
|
1361
|
+
热: {
|
|
1362
|
+
木: '木在暑天要水,不然只长叶不结果',
|
|
1363
|
+
火: '火已经当令,收着用比放出去更划算',
|
|
1364
|
+
土: '土热则燥,得水则安',
|
|
1365
|
+
金: '金在暑天要水来洗,才见光泽',
|
|
1366
|
+
水: '水在暑天是命脉,要保住源头',
|
|
1367
|
+
},
|
|
1368
|
+
湿滞: {
|
|
1369
|
+
木: '木泡在水里会烂根,先要疏土透气',
|
|
1370
|
+
火: '火在湿气里点不着,得先除湿',
|
|
1371
|
+
土: '土湿成泥,得火蒸腾、得木来疏',
|
|
1372
|
+
金: '金埋在湿土里会生锈,要见火见光',
|
|
1373
|
+
水: '水已经太多,再添就是泛滥',
|
|
1374
|
+
},
|
|
1375
|
+
燥: {
|
|
1376
|
+
木: '木在燥气里容易枯,先要一点水',
|
|
1377
|
+
火: '火在燥处容易失控,要收',
|
|
1378
|
+
土: '土燥不毛,得水润、得木疏',
|
|
1379
|
+
金: '金在燥处要水来洗,才不刺手',
|
|
1380
|
+
水: '水在燥处最容易被耗干,要护住',
|
|
1381
|
+
},
|
|
1382
|
+
平和: {
|
|
1383
|
+
木: '寒暖还算相济,木有生长的余地',
|
|
1384
|
+
火: '气候不偏,火可以按自己的节奏用',
|
|
1385
|
+
土: '土不燥不湿,能养也能载',
|
|
1386
|
+
金: '金不寒不燥,成器只差打磨',
|
|
1387
|
+
水: '水不冰不涸,能流得动',
|
|
1388
|
+
},
|
|
1389
|
+
};
|
|
1390
|
+
|
|
1391
|
+
const round2 = (n) => Math.round(n * 100) / 100;
|
|
1392
|
+
|
|
1393
|
+
function judgeClimate({ monthBranch, dayStem, wuxing = {}, branches = [] }) {
|
|
1394
|
+
const fire = Number(wuxing['火'] || 0);
|
|
1395
|
+
const water = Number(wuxing['水'] || 0);
|
|
1396
|
+
let wet = 0;
|
|
1397
|
+
let dry = 0;
|
|
1398
|
+
let wetCount = 0;
|
|
1399
|
+
let dryCount = 0;
|
|
1400
|
+
for (const b of branches) {
|
|
1401
|
+
if (WET_BRANCH[b]) { wet += WET_BRANCH[b]; if (b === '丑' || b === '辰') wetCount += 1; }
|
|
1402
|
+
if (DRY_BRANCH[b]) { dry += DRY_BRANCH[b]; if (b === '未' || b === '戌') dryCount += 1; }
|
|
1403
|
+
}
|
|
1404
|
+
const seasonT = SEASON_TEMP[monthBranch] ?? 0;
|
|
1405
|
+
const temp = round2(seasonT + 0.45 * fire - 0.4 * water);
|
|
1406
|
+
const damp = round2(wet - dry + 0.25 * water - 0.25 * fire);
|
|
1407
|
+
|
|
1408
|
+
const cold = temp <= -0.8;
|
|
1409
|
+
const hot = temp >= 0.9;
|
|
1410
|
+
const wetSide = damp >= 0.8;
|
|
1411
|
+
const drySide = damp <= -0.8;
|
|
1412
|
+
|
|
1413
|
+
let kind = '平和';
|
|
1414
|
+
if (cold && wetSide) kind = '寒湿';
|
|
1415
|
+
else if (cold && drySide) kind = '寒燥';
|
|
1416
|
+
else if (cold) kind = '寒';
|
|
1417
|
+
else if (hot && drySide) kind = '燥热';
|
|
1418
|
+
else if (hot) kind = '温热';
|
|
1419
|
+
else if (hot && damp >= 0.8) kind = '湿滞';
|
|
1420
|
+
else if (drySide) kind = '燥';
|
|
1421
|
+
else if (wetSide) kind = '湿滞';
|
|
1422
|
+
|
|
1423
|
+
const need = NEED[kind] || NEED.平和;
|
|
1424
|
+
const dayElement = STEM_ELEMENT[dayStem] || '土';
|
|
1425
|
+
const evidence = [
|
|
1426
|
+
`${SEASON_NAME[monthBranch] || monthBranch}${monthBranch}月`,
|
|
1427
|
+
`火${fire}`,
|
|
1428
|
+
`水${water}`,
|
|
1429
|
+
wetCount ? `湿土${wetCount}处` : '',
|
|
1430
|
+
dryCount ? `燥土${dryCount}处` : '',
|
|
1431
|
+
].filter(Boolean);
|
|
1432
|
+
|
|
1433
|
+
const priority = Math.abs(temp) >= 1.2 || Math.abs(damp) >= 1.2 ? '调候优先' : '扶抑为主';
|
|
1434
|
+
const narration = buildNarration({ kind, monthBranch, dayElement, need, temp, damp, fire, water });
|
|
1435
|
+
|
|
1436
|
+
return {
|
|
1437
|
+
kind,
|
|
1438
|
+
label: KIND_NAME[kind] || kind,
|
|
1439
|
+
temp,
|
|
1440
|
+
damp,
|
|
1441
|
+
cold,
|
|
1442
|
+
hot,
|
|
1443
|
+
wet: wetSide,
|
|
1444
|
+
dry: drySide,
|
|
1445
|
+
need: need.element ? { element: need.element, stem: need.stem, why: need.why } : null,
|
|
1446
|
+
avoidElement: need.avoid,
|
|
1447
|
+
dayElement,
|
|
1448
|
+
priority,
|
|
1449
|
+
evidence,
|
|
1450
|
+
narration,
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
function buildNarration({ kind, monthBranch, dayElement, need, fire, water }) {
|
|
1455
|
+
const feel = (DAY_FEEL[kind] || DAY_FEEL.平和)[dayElement] || '';
|
|
1456
|
+
const season = SEASON_NAME[monthBranch] || '';
|
|
1457
|
+
const head = `${season ? season : ''}${monthBranch}月出生,全局火${fire}、水${water},这一盘的气候是「${KIND_NAME[kind] || kind}」`;
|
|
1458
|
+
if (!need.element) {
|
|
1459
|
+
return `${head}。${feel}。调候不是这一盘的主要矛盾,取用仍以扶抑为主,寒暖只作微调。`;
|
|
1460
|
+
}
|
|
1461
|
+
return `${head}。${feel}。所以这一局要的不是更多的${kind.includes('寒') ? '水' : '火'},而是${need.stem}${need.element}——${need.why}。`;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
function arbitrate(climate, favors = [], avoids = []) {
|
|
1465
|
+
if (!climate || !climate.need) return { clash: false, text: '气候平和,按扶抑取用即可。' };
|
|
1466
|
+
const needEl = climate.need.element;
|
|
1467
|
+
const inFavor = favors.includes(needEl);
|
|
1468
|
+
const inAvoid = avoids.includes(needEl);
|
|
1469
|
+
const same = inFavor && !inAvoid;
|
|
1470
|
+
if (same) return { clash: false, text: `调候要${climate.need.stem}${needEl},扶抑也以${needEl}为喜——两套取法同向,不必取舍。` };
|
|
1471
|
+
return {
|
|
1472
|
+
clash: true,
|
|
1473
|
+
text: `调候要${climate.need.stem}${needEl},扶抑却把${needEl}列为${inAvoid ? '忌' : '闲'};两者不一致,本盘按调候优先取${needEl},扶抑次之——因为寒暖失衡时,再补强弱也难受。`,
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
function climateText(climate) {
|
|
1478
|
+
if (!climate) return '';
|
|
1479
|
+
const ev = (climate.evidence || []).join('、');
|
|
1480
|
+
const arb = climate.need
|
|
1481
|
+
? `调候取${climate.need.stem}${climate.need.element}(${climate.need.why}),忌${climate.avoidElement}。`
|
|
1482
|
+
: '气候平和,调候不作主取。';
|
|
1483
|
+
return `${climate.label}(${ev})。${climate.narration}${arb}${climate.priority === '调候优先' ? ' 本盘调候优先于扶抑。' : ''}`;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
return { judgeClimate, arbitrate, climateText };
|
|
1487
|
+
})();
|
|
1488
|
+
|
|
1283
1489
|
__mods.geju = (function () {
|
|
1284
1490
|
|
|
1491
|
+
const { judgeClimate, arbitrate } = __mods.tiaohou;
|
|
1492
|
+
|
|
1285
1493
|
const STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
|
|
1286
1494
|
const BRANCHES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];
|
|
1287
1495
|
|
|
@@ -1459,38 +1667,35 @@ function specialPatterns(pillars, dayStem, monthBranch, strength, wuxing, gods)
|
|
|
1459
1667
|
return out;
|
|
1460
1668
|
}
|
|
1461
1669
|
|
|
1462
|
-
|
|
1463
|
-
亥: ['火', '冬月寒水当令,最喜火暖局'],
|
|
1464
|
-
子: ['火', '仲冬水旺,最喜火暖局'],
|
|
1465
|
-
丑: ['火', '季冬湿寒,喜火解冻'],
|
|
1466
|
-
巳: ['水', '初夏火旺,喜水制衡'],
|
|
1467
|
-
午: ['水', '仲夏火炎,最喜水调候'],
|
|
1468
|
-
未: ['水', '季夏燥土,喜水润局'],
|
|
1469
|
-
寅: ['火', '初春尚寒,得火而发'],
|
|
1470
|
-
卯: ['火', '仲春木旺,喜火吐秀'],
|
|
1471
|
-
辰: ['金', '季春湿土,喜金水疏泄'],
|
|
1472
|
-
申: ['火', '初秋金旺,喜火炼金'],
|
|
1473
|
-
酉: ['火', '仲秋金锐,喜火制'],
|
|
1474
|
-
戌: ['水', '季秋燥土,喜水润泽'],
|
|
1475
|
-
};
|
|
1476
|
-
|
|
1477
|
-
function yongshenOf(dayStem, monthBranch, strength, wuxing) {
|
|
1670
|
+
function yongshenOf(dayStem, monthBranch, strength, wuxing, branches = []) {
|
|
1478
1671
|
const roles = elementRoles(dayStem);
|
|
1479
1672
|
const me = roles.me;
|
|
1480
1673
|
const weak = strength.level === '身弱' || strength.level === '偏弱';
|
|
1481
1674
|
const strong = strength.level === '身强' || strength.level === '偏强';
|
|
1482
1675
|
|
|
1483
|
-
const
|
|
1484
|
-
const
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
: ['正印', '偏印', '食神', '伤官'];
|
|
1676
|
+
const baseFavor = weak ? [roles.inMe, me] : strong ? [roles.shi, roles.cai, roles.guan] : [roles.inMe, me, roles.shi];
|
|
1677
|
+
const baseAvoid = weak ? [roles.shi, roles.cai, roles.guan] : strong ? [me, roles.inMe] : [roles.guan, roles.cai];
|
|
1678
|
+
let favor = baseFavor.slice();
|
|
1679
|
+
let avoid = baseAvoid.slice();
|
|
1488
1680
|
|
|
1489
|
-
const
|
|
1490
|
-
const
|
|
1681
|
+
const climate = judgeClimate({ monthBranch, dayStem, wuxing, branches });
|
|
1682
|
+
const arb = arbitrate(climate, baseFavor, baseAvoid);
|
|
1683
|
+
if (climate.need && climate.priority === '调候优先') {
|
|
1684
|
+
const needEl = climate.need.element;
|
|
1685
|
+
if (!favor.includes(needEl)) favor.unshift(needEl);
|
|
1686
|
+
avoid = avoid.filter((e) => e !== needEl);
|
|
1687
|
+
if (climate.avoidElement && !avoid.includes(climate.avoidElement)) avoid.unshift(climate.avoidElement);
|
|
1688
|
+
}
|
|
1491
1689
|
|
|
1492
1690
|
const roleName = (el) => (el === me ? '比劫' : el === roles.inMe ? '印'
|
|
1493
1691
|
: el === roles.shi ? '食伤' : el === roles.cai ? '财' : '官杀');
|
|
1692
|
+
const expand = {
|
|
1693
|
+
比劫: ['比肩', '劫财'], 印: ['正印', '偏印'], 食伤: ['食神', '伤官'],
|
|
1694
|
+
财: ['正财', '偏财'], 官杀: ['正官', '七杀'],
|
|
1695
|
+
};
|
|
1696
|
+
const favorTenGods = Array.from(new Set(favor.flatMap((el) => expand[roleName(el)] || [])));
|
|
1697
|
+
const avoidTenGods = Array.from(new Set(avoid.flatMap((el) => expand[roleName(el)] || [])));
|
|
1698
|
+
|
|
1494
1699
|
const detail = [
|
|
1495
1700
|
`日主${dayStem}${me},${strength.level}(${strength.score} 分):`,
|
|
1496
1701
|
weak
|
|
@@ -1498,24 +1703,22 @@ function yongshenOf(dayStem, monthBranch, strength, wuxing) {
|
|
|
1498
1703
|
: strong
|
|
1499
1704
|
? `喜${roles.shi}(食伤)泄秀、${roles.cai}(财)耗、${roles.guan}(官杀)制;忌${me}(比劫)与${roles.inMe}(印)再助。`
|
|
1500
1705
|
: '身中和,先取调候与通关,喜忌随大运流年动态变化。',
|
|
1501
|
-
|
|
1502
|
-
|
|
1706
|
+
`调候:${climate.label}(${(climate.evidence || []).join('、')})${climate.need ? `,取${climate.need.stem}${climate.need.element},忌${climate.avoidElement}` : ',气候平和'}。`,
|
|
1707
|
+
arb.text,
|
|
1708
|
+
arb.clash ? '取舍:本盘按「调候优先、扶抑次之」取用;若你更认同扶抑派,可把调候当环境偏好,强弱判断不受影响。' : '',
|
|
1503
1709
|
].filter(Boolean).join('');
|
|
1504
1710
|
|
|
1505
1711
|
return {
|
|
1506
|
-
method: '扶抑为主 +
|
|
1712
|
+
method: climate.priority === '调候优先' ? '调候优先 + 扶抑校验' : '扶抑为主 + 调候校验',
|
|
1507
1713
|
level: strength.level,
|
|
1508
1714
|
favor,
|
|
1509
1715
|
avoid,
|
|
1510
1716
|
favorRoles: favor.map(roleName),
|
|
1511
1717
|
avoidRoles: avoid.map(roleName),
|
|
1512
|
-
favorTenGods
|
|
1513
|
-
avoidTenGods
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
? ['比肩', '劫财', '正印', '偏印']
|
|
1517
|
-
: ['正官', '七杀', '正财', '偏财'],
|
|
1518
|
-
tiaohou,
|
|
1718
|
+
favorTenGods,
|
|
1719
|
+
avoidTenGods,
|
|
1720
|
+
tiaohou: { ...climate, ...arb, element: climate.need ? climate.need.element : null },
|
|
1721
|
+
climate,
|
|
1519
1722
|
detail,
|
|
1520
1723
|
};
|
|
1521
1724
|
}
|
|
@@ -1534,33 +1737,54 @@ function scoreLuck(ganzhi, frame) {
|
|
|
1534
1737
|
const branch = ganzhi[1];
|
|
1535
1738
|
const stemEl = STEM_ELEMENT[stem];
|
|
1536
1739
|
const branchEl = BRANCH_ELEMENT[branch];
|
|
1740
|
+
const th = ys.tiaohou || ys.climate || null;
|
|
1537
1741
|
const scoreEl = (el) => {
|
|
1538
1742
|
let s = 0;
|
|
1539
1743
|
if (ys.favor.includes(el)) s += 1;
|
|
1540
1744
|
if (ys.avoid.includes(el)) s -= 1;
|
|
1541
|
-
if (ys.tiaohou && el === ys.tiaohou.element) s += 0.4;
|
|
1542
1745
|
return s;
|
|
1543
1746
|
};
|
|
1544
1747
|
let score = scoreEl(stemEl) * 1.0 + scoreEl(branchEl) * 0.8;
|
|
1545
1748
|
for (const h of (HIDDEN[branch] || []).slice(1)) {
|
|
1546
1749
|
score += scoreEl(STEM_ELEMENT[h]) * 0.2;
|
|
1547
1750
|
}
|
|
1548
|
-
score = Math.round(score * 10) / 10;
|
|
1549
1751
|
|
|
1550
|
-
const godStem = tenGod(frame.dayStem, stem);
|
|
1551
|
-
const bonus = ys.favorTenGods.includes(godStem) ? 0.3 : 0;
|
|
1552
|
-
const total = Math.round((score + bonus) * 10) / 10;
|
|
1553
|
-
|
|
1554
|
-
const tier = TIERS.find(([min]) => total >= min)[1];
|
|
1555
1752
|
const reasons = [];
|
|
1556
1753
|
if (ys.favor.includes(stemEl)) reasons.push(`天干${stem}${stemEl}为用神`);
|
|
1557
1754
|
else if (ys.avoid.includes(stemEl)) reasons.push(`天干${stem}${stemEl}为忌神`);
|
|
1558
1755
|
else reasons.push(`天干${stem}${stemEl}不喜不忌`);
|
|
1559
1756
|
if (ys.favor.includes(branchEl)) reasons.push(`地支${branch}${branchEl}助用`);
|
|
1560
1757
|
else if (ys.avoid.includes(branchEl)) reasons.push(`地支${branch}${branchEl}助忌`);
|
|
1561
|
-
|
|
1562
|
-
|
|
1758
|
+
|
|
1759
|
+
if (th && th.need && th.priority === '调候优先') {
|
|
1760
|
+
const needEl = th.need.element;
|
|
1761
|
+
const oppEl = th.avoidElement;
|
|
1762
|
+
const cold = String(th.kind).includes('寒');
|
|
1763
|
+
if (stemEl === needEl) {
|
|
1764
|
+
score += 1.1;
|
|
1765
|
+
reasons.push(`${th.label}之局得${stem}${stemEl},${cold ? '解冻' : '得润'}`);
|
|
1766
|
+
} else if (stemEl === oppEl) {
|
|
1767
|
+
score -= 0.9;
|
|
1768
|
+
reasons.push(`${th.label}之局再逢${stem}${stemEl},${cold ? '冻木难生' : '燥上加燥'}`);
|
|
1769
|
+
}
|
|
1770
|
+
if (branchEl === needEl) {
|
|
1771
|
+
score += 0.9;
|
|
1772
|
+
reasons.push(`地支${branch}${branchEl}合调候`);
|
|
1773
|
+
} else if (branchEl === oppEl) {
|
|
1774
|
+
score -= 1.0;
|
|
1775
|
+
reasons.push(`地支${branch}${branchEl}加重${th.label}`);
|
|
1776
|
+
}
|
|
1777
|
+
if (cold && (stemEl === '水' || branchEl === '水')) score -= 0.3;
|
|
1778
|
+
} else if (th && th.need && (stemEl === th.need.element || branchEl === th.need.element)) {
|
|
1779
|
+
reasons.push(`合调候(${th.need.element})`);
|
|
1563
1780
|
}
|
|
1781
|
+
|
|
1782
|
+
const godStem = tenGod(frame.dayStem, stem);
|
|
1783
|
+
const bonus = ys.favorTenGods.includes(godStem) ? 0.3 : 0;
|
|
1784
|
+
let total = Math.round((score + bonus) * 10) / 10;
|
|
1785
|
+
total = Math.max(-4, Math.min(4, total));
|
|
1786
|
+
|
|
1787
|
+
const tier = TIERS.find(([min]) => total >= min)[1];
|
|
1564
1788
|
return { ganzhi, score: total, tier, stemTenGod: godStem, reasons, note: `${godStem}运,${tier}(${total})` };
|
|
1565
1789
|
}
|
|
1566
1790
|
|
|
@@ -1569,7 +1793,7 @@ function analyzeBaziFrame({ pillars, dayStem, monthBranch, strength, wuxing }) {
|
|
|
1569
1793
|
const month = monthPattern(pillars, dayStem, monthBranch);
|
|
1570
1794
|
const special = specialPatterns(pillars, dayStem, monthBranch, strength, wuxing, gods);
|
|
1571
1795
|
const geju = [month, ...special];
|
|
1572
|
-
const yongshen = yongshenOf(dayStem, monthBranch, strength, wuxing);
|
|
1796
|
+
const yongshen = yongshenOf(dayStem, monthBranch, strength, wuxing, Object.values(pillars).map((p) => p.branch));
|
|
1573
1797
|
return {
|
|
1574
1798
|
geju,
|
|
1575
1799
|
primary: month,
|
|
@@ -2042,6 +2266,7 @@ function buildBazi(input) {
|
|
|
2042
2266
|
},
|
|
2043
2267
|
strength,
|
|
2044
2268
|
frame,
|
|
2269
|
+
climate: frame.yongshen.climate || frame.yongshen.tiaohou || null,
|
|
2045
2270
|
liunian,
|
|
2046
2271
|
liunianFrom: thisYear,
|
|
2047
2272
|
};
|
|
@@ -5732,6 +5957,7 @@ return { TRIGRAM, YAO_POSITION, MOVING_NATURE, HEX64, HEX_BY_CORE, ZIWEI_STARS,
|
|
|
5732
5957
|
|
|
5733
5958
|
__mods.almanac = (function () {
|
|
5734
5959
|
const { solarToLunar } = __mods.lunar;
|
|
5960
|
+
const { nayinOf } = __mods.nayin;
|
|
5735
5961
|
const { toJDN, fromJDN, dayGanzhiIndex, ganzhiName, termWindow, termInstantJd, partsToJd, STEMS, BRANCHES, TERM_NAMES } = __mods.calendar;
|
|
5736
5962
|
const { HEX64 } = __mods['interpret-data'];
|
|
5737
5963
|
const { assertCivil, daysInMonth } = __mods.validate;
|
|
@@ -5803,6 +6029,80 @@ function lunarMonthText(month, isLeap = false) {
|
|
|
5803
6029
|
return `${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月`;
|
|
5804
6030
|
}
|
|
5805
6031
|
|
|
6032
|
+
const TIAN_SHEN = ['青龙', '明堂', '天刑', '朱雀', '金匮', '天德', '白虎', '玉堂', '天牢', '玄武', '司命', '勾陈'];
|
|
6033
|
+
const TIAN_SHEN_TYPE = {
|
|
6034
|
+
青龙: '黄道', 明堂: '黄道', 金匮: '黄道', 天德: '黄道', 玉堂: '黄道', 司命: '黄道',
|
|
6035
|
+
天刑: '黑道', 朱雀: '黑道', 白虎: '黑道', 天牢: '黑道', 玄武: '黑道', 勾陈: '黑道',
|
|
6036
|
+
};
|
|
6037
|
+
const TIAN_SHEN_OFFSET = { 子: 4, 丑: 2, 寅: 0, 卯: 10, 辰: 8, 巳: 6, 午: 4, 未: 2, 申: 0, 酉: 10, 戌: 8, 亥: 6 };
|
|
6038
|
+
|
|
6039
|
+
function tianShenOf(branch, anchorBranch) {
|
|
6040
|
+
const b = BRANCHES.indexOf(branch);
|
|
6041
|
+
const off = TIAN_SHEN_OFFSET[anchorBranch];
|
|
6042
|
+
if (b < 0 || off == null) return null;
|
|
6043
|
+
const name = TIAN_SHEN[(b + off) % 12];
|
|
6044
|
+
const type = TIAN_SHEN_TYPE[name];
|
|
6045
|
+
return { name, type, luck: type === '黄道' ? '吉' : '凶' };
|
|
6046
|
+
}
|
|
6047
|
+
|
|
6048
|
+
const MANSIONS = {
|
|
6049
|
+
角: { luck: '吉', zheng: '木', animal: '蛟', gong: '东' }, 亢: { luck: '凶', zheng: '金', animal: '龙', gong: '东' },
|
|
6050
|
+
氐: { luck: '凶', zheng: '土', animal: '貉', gong: '东' }, 房: { luck: '吉', zheng: '日', animal: '兔', gong: '东' },
|
|
6051
|
+
心: { luck: '凶', zheng: '月', animal: '狐', gong: '东' }, 尾: { luck: '吉', zheng: '火', animal: '虎', gong: '东' },
|
|
6052
|
+
箕: { luck: '吉', zheng: '水', animal: '豹', gong: '东' }, 斗: { luck: '吉', zheng: '木', animal: '獬', gong: '北' },
|
|
6053
|
+
牛: { luck: '凶', zheng: '金', animal: '牛', gong: '北' }, 女: { luck: '凶', zheng: '土', animal: '蝠', gong: '北' },
|
|
6054
|
+
虚: { luck: '凶', zheng: '日', animal: '鼠', gong: '北' }, 危: { luck: '凶', zheng: '月', animal: '燕', gong: '北' },
|
|
6055
|
+
室: { luck: '吉', zheng: '火', animal: '猪', gong: '北' }, 壁: { luck: '吉', zheng: '水', animal: '獝', gong: '北' },
|
|
6056
|
+
奎: { luck: '凶', zheng: '木', animal: '狼', gong: '西' }, 娄: { luck: '吉', zheng: '金', animal: '狗', gong: '西' },
|
|
6057
|
+
胃: { luck: '吉', zheng: '土', animal: '彘', gong: '西' }, 昴: { luck: '凶', zheng: '日', animal: '鸡', gong: '西' },
|
|
6058
|
+
毕: { luck: '吉', zheng: '月', animal: '乌', gong: '西' }, 觜: { luck: '凶', zheng: '火', animal: '猴', gong: '西' },
|
|
6059
|
+
参: { luck: '吉', zheng: '水', animal: '猿', gong: '西' }, 井: { luck: '吉', zheng: '木', animal: '犴', gong: '南' },
|
|
6060
|
+
鬼: { luck: '凶', zheng: '金', animal: '羊', gong: '南' }, 柳: { luck: '凶', zheng: '土', animal: '獐', gong: '南' },
|
|
6061
|
+
星: { luck: '凶', zheng: '日', animal: '马', gong: '南' }, 张: { luck: '吉', zheng: '月', animal: '鹿', gong: '南' },
|
|
6062
|
+
翼: { luck: '凶', zheng: '火', animal: '蛇', gong: '南' }, 轸: { luck: '吉', zheng: '水', animal: '蚓', gong: '南' },
|
|
6063
|
+
};
|
|
6064
|
+
const XIU_GROUPS = {
|
|
6065
|
+
A: ['虚', '毕', '翼', '箕', '奎', '鬼', '氐'],
|
|
6066
|
+
B: ['房', '危', '觜', '轸', '斗', '娄', '柳'],
|
|
6067
|
+
C: ['星', '心', '室', '参', '角', '牛', '胃'],
|
|
6068
|
+
D: ['昴', '张', '尾', '壁', '井', '亢', '女'],
|
|
6069
|
+
};
|
|
6070
|
+
const XIU_GROUP_OF = { 子: 'A', 辰: 'A', 申: 'A', 丑: 'B', 巳: 'B', 酉: 'B', 寅: 'C', 午: 'C', 戌: 'C', 卯: 'D', 未: 'D', 亥: 'D' };
|
|
6071
|
+
|
|
6072
|
+
function xiuOf(dayBranch, weekdayIndex) {
|
|
6073
|
+
const g = XIU_GROUP_OF[dayBranch];
|
|
6074
|
+
if (!g) return null;
|
|
6075
|
+
const name = XIU_GROUPS[g][weekdayIndex];
|
|
6076
|
+
const info = MANSIONS[name];
|
|
6077
|
+
return info ? { name, ...info } : null;
|
|
6078
|
+
}
|
|
6079
|
+
|
|
6080
|
+
const DIR_OF = { 坎: '正北', 艮: '东北', 震: '正东', 巽: '东南', 离: '正南', 坤: '西南', 兑: '正西', 乾: '西北' };
|
|
6081
|
+
const POS_XI = { 甲: '艮', 乙: '乾', 丙: '坤', 丁: '离', 戊: '巽', 己: '艮', 庚: '乾', 辛: '坤', 壬: '离', 癸: '巽' };
|
|
6082
|
+
const POS_CAI = { 甲: '艮', 乙: '艮', 丙: '坤', 丁: '坤', 戊: '坎', 己: '坎', 庚: '震', 辛: '震', 壬: '离', 癸: '离' };
|
|
6083
|
+
const POS_FU = { 甲: '坎', 乙: '坤', 丙: '乾', 丁: '巽', 戊: '艮', 己: '坎', 庚: '坤', 辛: '乾', 壬: '巽', 癸: '艮' };
|
|
6084
|
+
const POS_YANG_GUI = { 甲: '坤', 乙: '坤', 丙: '兑', 丁: '乾', 戊: '艮', 己: '坎', 庚: '离', 辛: '艮', 壬: '震', 癸: '巽' };
|
|
6085
|
+
const POS_YIN_GUI = { 甲: '艮', 乙: '坎', 丙: '乾', 丁: '兑', 戊: '坤', 己: '坤', 庚: '艮', 辛: '离', 壬: '巽', 癸: '震' };
|
|
6086
|
+
const posOf = (map, stem) => (map[stem] ? { gua: map[stem], dir: DIR_OF[map[stem]] } : null);
|
|
6087
|
+
|
|
6088
|
+
const TAI_SHEN = {
|
|
6089
|
+
甲子: '占门碓 外东南', 乙丑: '碓磨厕 外东南', 丙寅: '厨灶炉 外正南', 丁卯: '仓库门 外正南', 戊辰: '房床栖 外正南',
|
|
6090
|
+
己巳: '占门床 外正南', 庚午: '占碓磨 外正南', 辛未: '厨灶厕 外西南', 壬申: '仓库炉 外西南', 癸酉: '房床门 外西南',
|
|
6091
|
+
甲戌: '占门栖 外西南', 乙亥: '碓磨床 外西南', 丙子: '厨灶碓 外西南', 丁丑: '仓库厕 外正西', 戊寅: '房床炉 外正西',
|
|
6092
|
+
己卯: '占大门 外正西', 庚辰: '碓磨栖 外正西', 辛巳: '厨灶床 外正西', 壬午: '仓库碓 外西北', 癸未: '房床厕 外西北',
|
|
6093
|
+
甲申: '占门炉 外西北', 乙酉: '碓磨门 外西北', 丙戌: '厨灶栖 外西北', 丁亥: '仓库床 外西北', 戊子: '房床碓 外正北',
|
|
6094
|
+
己丑: '占门厕 外正北', 庚寅: '碓磨炉 外正北', 辛卯: '厨灶门 外正北', 壬辰: '仓库栖 外正北', 癸巳: '占房床 房内北',
|
|
6095
|
+
甲午: '占门碓 房内北', 乙未: '碓磨厕 房内北', 丙申: '厨灶炉 房内北', 丁酉: '仓库门 房内北', 戊戌: '房床栖 房内中',
|
|
6096
|
+
己亥: '占门床 房内中', 庚子: '占碓磨 房内南', 辛丑: '厨灶厕 房内南', 壬寅: '仓库炉 房内南', 癸卯: '房床门 房内西',
|
|
6097
|
+
甲辰: '占门栖 房内东', 乙巳: '碓磨床 房内东', 丙午: '厨灶碓 房内东', 丁未: '仓库厕 房内东', 戊申: '房床炉 房内中',
|
|
6098
|
+
己酉: '占大门 外东北', 庚戌: '碓磨栖 外东北', 辛亥: '厨灶床 外东北', 壬子: '仓库碓 外东北', 癸丑: '房床厕 外东北',
|
|
6099
|
+
甲寅: '占门炉 外东北', 乙卯: '碓磨门 外正东', 丙辰: '厨灶栖 外正东', 丁巳: '仓库床 外正东', 戊午: '房床碓 外正东',
|
|
6100
|
+
己未: '占门厕 外正东', 庚申: '碓磨炉 外东南', 辛酉: '厨灶门 外东南', 壬戌: '仓库栖 外东南', 癸亥: '占房床 外东南',
|
|
6101
|
+
};
|
|
6102
|
+
|
|
6103
|
+
const LIUHE = { 子: '丑', 丑: '子', 寅: '亥', 亥: '寅', 卯: '戌', 戌: '卯', 辰: '酉', 酉: '辰', 巳: '申', 申: '巳', 午: '未', 未: '午' };
|
|
6104
|
+
const SANHE = { 申: '申子辰', 子: '申子辰', 辰: '申子辰', 亥: '亥卯未', 卯: '亥卯未', 未: '亥卯未', 寅: '寅午戌', 午: '寅午戌', 戌: '寅午戌', 巳: '巳酉丑', 酉: '巳酉丑', 丑: '巳酉丑' };
|
|
6105
|
+
|
|
5806
6106
|
function dailyHexagram(year, month, day) {
|
|
5807
6107
|
const names = Object.keys(HEX64);
|
|
5808
6108
|
if (!names.length) return null;
|
|
@@ -5858,7 +6158,41 @@ function buildAlmanac(input) {
|
|
|
5858
6158
|
return `${p.year}-${String(p.month).padStart(2, '0')}-${String(p.day).padStart(2, '0')}`;
|
|
5859
6159
|
};
|
|
5860
6160
|
|
|
5861
|
-
const
|
|
6161
|
+
const weekdayIdx = (jdn + 1) % 7;
|
|
6162
|
+
const weekday = ['日', '一', '二', '三', '四', '五', '六'][weekdayIdx];
|
|
6163
|
+
const dayGod = tianShenOf(dayBranch, BRANCHES[monthBranchIdx]);
|
|
6164
|
+
const xiu = xiuOf(dayBranch, weekdayIdx);
|
|
6165
|
+
const taiShen = TAI_SHEN[dayGz.name] || null;
|
|
6166
|
+
const hourBase = (STEMS.indexOf(dayGz.stem) % 5) * 2;
|
|
6167
|
+
const hours = BRANCHES.map((zhi, i) => {
|
|
6168
|
+
const gan = STEMS[(hourBase + i) % 10];
|
|
6169
|
+
const gz = ganzhiName(hourComposite((hourBase + i) % 10, i));
|
|
6170
|
+
const shen = tianShenOf(zhi, dayBranch);
|
|
6171
|
+
return {
|
|
6172
|
+
zhi,
|
|
6173
|
+
name: `${zhi}时`,
|
|
6174
|
+
ganZhi: gz.name,
|
|
6175
|
+
gan,
|
|
6176
|
+
shen: shen ? shen.name : null,
|
|
6177
|
+
type: shen ? shen.type : null,
|
|
6178
|
+
luck: shen ? shen.luck : null,
|
|
6179
|
+
};
|
|
6180
|
+
});
|
|
6181
|
+
const sanheGroup = SANHE[dayBranch] || '';
|
|
6182
|
+
const liuheBranch = LIUHE[dayBranch] || null;
|
|
6183
|
+
const lucky = {
|
|
6184
|
+
liuhe: liuheBranch ? SHENGXIAO[BRANCHES.indexOf(liuheBranch)] : null,
|
|
6185
|
+
sanhe: [...sanheGroup].filter((b) => b !== dayBranch).map((b) => SHENGXIAO[BRANCHES.indexOf(b)]),
|
|
6186
|
+
};
|
|
6187
|
+
const positions = {
|
|
6188
|
+
caiShen: CAI_SHEN[dayGz.stem] || null,
|
|
6189
|
+
xiShen: XI_SHEN[dayGz.stem] || null,
|
|
6190
|
+
fuShen: posOf(POS_FU, dayGz.stem),
|
|
6191
|
+
yangGui: posOf(POS_YANG_GUI, dayGz.stem),
|
|
6192
|
+
yinGui: posOf(POS_YIN_GUI, dayGz.stem),
|
|
6193
|
+
xiShenFull: posOf(POS_XI, dayGz.stem),
|
|
6194
|
+
caiShenFull: posOf(POS_CAI, dayGz.stem),
|
|
6195
|
+
};
|
|
5862
6196
|
const lunarText = `农历${springGz.name}年${lunarMonthText(lunar.month, lunar.isLeap)}${dayText(lunar.day)}`;
|
|
5863
6197
|
const boundaryNote = yearGz.name !== springGz.name
|
|
5864
6198
|
? `年界:本条按立春界作${yearGz.name}年·属${SHENGXIAO[BRANCHES.indexOf(yearGz.branch)]}(命理排盘用);春节界为${springGz.name}年·属${SHENGXIAO[BRANCHES.indexOf(springGz.branch)]},两种都对,取用场合不同`
|
|
@@ -5870,7 +6204,7 @@ function buildAlmanac(input) {
|
|
|
5870
6204
|
date: `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
|
|
5871
6205
|
weekday: `星期${weekday}`,
|
|
5872
6206
|
...(boundaryNote ? { boundaryNote } : {}),
|
|
5873
|
-
scope: '
|
|
6207
|
+
scope: '通行口径:宜忌按建除十二神简表;已收录值日十二神(黄道/黑道)、时辰吉凶、二十八宿、胎神、吉神方位、纳音、六合三合吉配;逐日全量吉神凶煞与彭祖百忌未收录',
|
|
5874
6208
|
},
|
|
5875
6209
|
lunar: {
|
|
5876
6210
|
year: springYear,
|
|
@@ -5891,7 +6225,13 @@ function buildAlmanac(input) {
|
|
|
5891
6225
|
prev: prevTerm ? { name: termName(prevTerm), date: fmtJdDate(prevTerm.jd) } : null,
|
|
5892
6226
|
next: nextTerm ? { name: termName(nextTerm), date: fmtJdDate(nextTerm.jd) } : null,
|
|
5893
6227
|
},
|
|
5894
|
-
positions
|
|
6228
|
+
positions,
|
|
6229
|
+
dayGod,
|
|
6230
|
+
xiu,
|
|
6231
|
+
taiShen,
|
|
6232
|
+
nayin: { day: nayinOf(dayGanzhiIndex(jdn)) },
|
|
6233
|
+
lucky,
|
|
6234
|
+
hours,
|
|
5895
6235
|
zhiXing,
|
|
5896
6236
|
yi: ZHIXING_YI[zhiXing].slice(),
|
|
5897
6237
|
ji: ZHIXING_JI[zhiXing].slice(),
|
|
@@ -5904,6 +6244,7 @@ function buildAlmanac(input) {
|
|
|
5904
6244
|
sources: [
|
|
5905
6245
|
'农历与节气:本地天文历法(定朔 + 节气黄经)',
|
|
5906
6246
|
'建除十二神与冲煞:传统通行口径',
|
|
6247
|
+
'值日/时家十二神(青龙…勾陈)、二十八宿、胎神、吉神方位:通行表',
|
|
5907
6248
|
'宜忌:建除十二神通行简表(非逐日全量黄历)',
|
|
5908
6249
|
'每日一卦:按公历日期确定性取卦(同日同卦)',
|
|
5909
6250
|
],
|
|
@@ -5918,7 +6259,14 @@ function monthComposite(stemIdx, branchIdx) {
|
|
|
5918
6259
|
return 0;
|
|
5919
6260
|
}
|
|
5920
6261
|
|
|
5921
|
-
|
|
6262
|
+
function hourComposite(stemIdx, branchIdx) {
|
|
6263
|
+
for (let i = 0; i < 60; i++) {
|
|
6264
|
+
if (i % 10 === stemIdx && i % 12 === branchIdx) return i;
|
|
6265
|
+
}
|
|
6266
|
+
return 0;
|
|
6267
|
+
}
|
|
6268
|
+
|
|
6269
|
+
return { ZHIXING, ZHIXING_YI, ZHIXING_JI, SHENGXIAO, hourToBranch, zhixingOf, lunarMonthText, TIAN_SHEN, TIAN_SHEN_TYPE, tianShenOf, MANSIONS, xiuOf, dailyHexagram, buildAlmanac };
|
|
5922
6270
|
})();
|
|
5923
6271
|
|
|
5924
6272
|
__mods.star = (function () {
|
|
@@ -6304,26 +6652,52 @@ const { buildAlmanac, SHENGXIAO } = __mods.almanac;
|
|
|
6304
6652
|
const TASKS = {
|
|
6305
6653
|
嫁娶: { yi: ['嫁娶', '结亲', '订盟', '纳采'], related: ['会亲友', '裁衣'], category: 'marriage' },
|
|
6306
6654
|
订婚: { yi: ['订盟', '纳采'], related: ['嫁娶', '会亲友'], category: 'marriage' },
|
|
6655
|
+
领证: { yi: ['嫁娶', '纳采'], related: ['订盟', '会亲友'], category: 'marriage' },
|
|
6656
|
+
提亲: { yi: ['纳采', '订盟'], related: ['会亲友'], category: 'marriage' },
|
|
6657
|
+
收送聘金: { yi: ['纳采', '订盟'], related: ['嫁娶'], category: 'marriage' },
|
|
6658
|
+
满月酒: { yi: ['祭祀', '祈福'], related: ['会亲友'], category: 'celebration' },
|
|
6307
6659
|
开业: { yi: ['开市', '立券', '交易'], related: ['纳财', '挂匾'], category: 'business' },
|
|
6660
|
+
交易: { yi: ['交易', '立券'], related: ['开市', '纳财'], category: 'business' },
|
|
6661
|
+
投资: { yi: ['纳财', '交易'], related: ['立券'], category: 'business' },
|
|
6662
|
+
签订合同: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
6663
|
+
签约: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
6664
|
+
纳财: { yi: ['纳财', '收账'], related: ['开市', '立券'], category: 'contract' },
|
|
6308
6665
|
入宅: { yi: ['入宅', '移徙'], related: ['安床', '修造', '扫舍'], category: 'move' },
|
|
6309
6666
|
搬家: { yi: ['移徙', '入宅'], related: ['安床', '修造'], category: 'move' },
|
|
6667
|
+
搬家入宅: { yi: ['入宅', '移徙'], related: ['安床', '扫舍'], category: 'move' },
|
|
6310
6668
|
动土: { yi: ['动土', '修造'], related: ['竖柱', '上梁'], category: 'construction' },
|
|
6311
6669
|
装修: { yi: ['修造', '修饰垣墙'], related: ['动土'], category: 'construction' },
|
|
6670
|
+
装修建造: { yi: ['修造', '动土'], related: ['竖柱', '上梁'], category: 'construction' },
|
|
6671
|
+
试车买车: { yi: ['交易', '纳财'], related: ['出行'], category: 'purchase' },
|
|
6312
6672
|
安葬: { yi: ['安葬', '破土'], related: ['立碑', '埋穴'], category: 'burial' },
|
|
6313
6673
|
出行: { yi: ['出行'], related: ['上任', '赴任'], category: 'travel' },
|
|
6674
|
+
旅行: { yi: ['出行'], related: ['上任', '赴任'], category: 'travel' },
|
|
6675
|
+
赴任: { yi: ['上任', '赴任'], related: ['出行'], category: 'travel' },
|
|
6676
|
+
访亲友: { yi: ['会亲友'], related: ['出行'], category: 'visit' },
|
|
6677
|
+
入学: { yi: ['入学'], related: ['开市', '修造'], category: 'study' },
|
|
6314
6678
|
祭祀: { yi: ['祭祀'], related: ['祈福', '求嗣'], category: 'worship' },
|
|
6315
|
-
签约: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
6316
6679
|
求医: { yi: ['求医', '疗病'], related: ['针灸'], category: 'medical' },
|
|
6317
|
-
|
|
6680
|
+
};
|
|
6681
|
+
|
|
6682
|
+
const TASK_GROUPS = {
|
|
6683
|
+
常用: ['嫁娶', '搬家入宅', '出行', '开业', '签订合同', '祭祀'],
|
|
6684
|
+
婚嫁: ['嫁娶', '订婚', '领证', '提亲', '收送聘金', '满月酒'],
|
|
6685
|
+
生活: ['搬家', '入宅', '旅行', '访亲友', '入学', '求医', '祭祀'],
|
|
6686
|
+
建造: ['动土', '装修', '装修建造', '安葬', '试车买车'],
|
|
6687
|
+
工商: ['开业', '交易', '投资', '签订合同', '签约', '纳财', '赴任'],
|
|
6318
6688
|
};
|
|
6319
6689
|
|
|
6320
6690
|
const ZHIXING_FAVOR = {
|
|
6321
6691
|
marriage: ['满', '定', '成', '开'],
|
|
6692
|
+
celebration: ['满', '成', '开', '平'],
|
|
6322
6693
|
business: ['开', '成', '满', '收'],
|
|
6323
6694
|
move: ['定', '成', '开', '除'],
|
|
6324
6695
|
construction: ['建', '除', '成', '开'],
|
|
6696
|
+
purchase: ['成', '开', '满'],
|
|
6325
6697
|
burial: ['除', '定', '闭', '破'],
|
|
6326
6698
|
travel: ['建', '成', '开', '除'],
|
|
6699
|
+
visit: ['满', '平', '定', '成'],
|
|
6700
|
+
study: ['成', '开', '建'],
|
|
6327
6701
|
worship: ['除', '满', '平', '定', '执', '成', '开'],
|
|
6328
6702
|
contract: ['定', '成', '收', '开'],
|
|
6329
6703
|
medical: ['除', '开'],
|
|
@@ -6417,7 +6791,133 @@ function buildZeri(input) {
|
|
|
6417
6791
|
};
|
|
6418
6792
|
}
|
|
6419
6793
|
|
|
6420
|
-
return { TASKS, buildZeri };
|
|
6794
|
+
return { TASKS, TASK_GROUPS, buildZeri };
|
|
6795
|
+
})();
|
|
6796
|
+
|
|
6797
|
+
__mods.convert = (function () {
|
|
6798
|
+
const { solarToLunar } = __mods.lunar;
|
|
6799
|
+
const { fromJDN, toJDN } = __mods.calendar;
|
|
6800
|
+
const { buildAlmanac } = __mods.almanac;
|
|
6801
|
+
const { assertCivil, daysInMonth } = __mods.validate;
|
|
6802
|
+
|
|
6803
|
+
const WEEK = ['日', '一', '二', '三', '四', '五', '六'];
|
|
6804
|
+
const MONTH_TEXT = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊'];
|
|
6805
|
+
const DAY_TENS = ['初', '十', '廿'];
|
|
6806
|
+
const DAY_UNITS = ['十', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
|
|
6807
|
+
|
|
6808
|
+
function dayText(day) {
|
|
6809
|
+
if (day === 10) return '初十';
|
|
6810
|
+
if (day === 20) return '二十';
|
|
6811
|
+
if (day === 30) return '三十';
|
|
6812
|
+
return `${DAY_TENS[Math.floor(day / 10)]}${DAY_UNITS[day % 10]}`;
|
|
6813
|
+
}
|
|
6814
|
+
|
|
6815
|
+
function lunarText(year, month, day, isLeap) {
|
|
6816
|
+
return `农历${year}年${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月${dayText(day)}`;
|
|
6817
|
+
}
|
|
6818
|
+
|
|
6819
|
+
function lunarNewYearJdn(lunarYear) {
|
|
6820
|
+
const from = toJDN(lunarYear, 1, 20);
|
|
6821
|
+
const to = toJDN(lunarYear, 2, 25);
|
|
6822
|
+
for (let jdn = from; jdn <= to; jdn++) {
|
|
6823
|
+
const p = fromJDN(jdn);
|
|
6824
|
+
const l = solarToLunar(p.year, p.month, p.day);
|
|
6825
|
+
if (l.lunarYear === lunarYear && l.month === 1 && l.day === 1) return jdn;
|
|
6826
|
+
}
|
|
6827
|
+
return null;
|
|
6828
|
+
}
|
|
6829
|
+
|
|
6830
|
+
function lunarMonths(lunarYear) {
|
|
6831
|
+
const first = lunarNewYearJdn(lunarYear);
|
|
6832
|
+
if (first == null) return [];
|
|
6833
|
+
const out = [];
|
|
6834
|
+
let cur = first;
|
|
6835
|
+
for (let i = 0; i < 14; i++) {
|
|
6836
|
+
const p = fromJDN(cur);
|
|
6837
|
+
const l = solarToLunar(p.year, p.month, p.day);
|
|
6838
|
+
if (i > 0 && l.month === 1 && !l.isLeap) break;
|
|
6839
|
+
let next = null;
|
|
6840
|
+
for (let k = 29; k <= 31; k++) {
|
|
6841
|
+
const d = fromJDN(cur + k);
|
|
6842
|
+
const l2 = solarToLunar(d.year, d.month, d.day);
|
|
6843
|
+
if (l2.day === 1) { next = cur + k; break; }
|
|
6844
|
+
}
|
|
6845
|
+
if (next == null) break;
|
|
6846
|
+
out.push({ month: l.month, isLeap: l.isLeap, startJdn: cur, length: next - cur });
|
|
6847
|
+
cur = next;
|
|
6848
|
+
}
|
|
6849
|
+
return out;
|
|
6850
|
+
}
|
|
6851
|
+
|
|
6852
|
+
function buildConvert(input) {
|
|
6853
|
+
const mode = input.mode === 'lunar2solar' ? 'lunar2solar' : 'solar2lunar';
|
|
6854
|
+
let solar;
|
|
6855
|
+
let lunar;
|
|
6856
|
+
let note = null;
|
|
6857
|
+
if (mode === 'solar2lunar') {
|
|
6858
|
+
solar = { year: input.year, month: input.month, day: input.day };
|
|
6859
|
+
assertCivil(solar, '公农历转换');
|
|
6860
|
+
if (solar.day > daysInMonth(solar.year, solar.month)) {
|
|
6861
|
+
throw new Error(`非法日期:${solar.year} 年 ${solar.month} 月没有 ${solar.day} 日`);
|
|
6862
|
+
}
|
|
6863
|
+
lunar = solarToLunar(solar.year, solar.month, solar.day);
|
|
6864
|
+
} else {
|
|
6865
|
+
const y = Number(input.lunarYear);
|
|
6866
|
+
const m = Number(input.lunarMonth);
|
|
6867
|
+
const d = Number(input.lunarDay);
|
|
6868
|
+
if (![y, m, d].every(Number.isInteger)) throw new Error('农历转换需要 lunarYear / lunarMonth / lunarDay');
|
|
6869
|
+
if (m < 1 || m > 12) throw new Error('农历月份须在 1–12');
|
|
6870
|
+
const months = lunarMonths(y);
|
|
6871
|
+
if (!months.length) throw new Error(`农历 ${y} 年超出本地历法覆盖范围(1900–2100)`);
|
|
6872
|
+
const isLeap = input.isLeapMonth === true;
|
|
6873
|
+
const hit = months.find((x) => x.month === m && x.isLeap === isLeap);
|
|
6874
|
+
if (!hit) {
|
|
6875
|
+
const leapMonths = months.filter((x) => x.isLeap).map((x) => `闰${MONTH_TEXT[x.month - 1]}月`);
|
|
6876
|
+
throw new Error(`农历 ${y} 年没有${leapMonths.length ? `该月(该年闰月为 ${leapMonths.join('、')})` : '闰月'}:${isLeap ? '请确认闰月标记' : '请确认月份'}`);
|
|
6877
|
+
}
|
|
6878
|
+
if (d < 1 || d > hit.length) throw new Error(`农历 ${y} 年${isLeap ? '闰' : ''}${MONTH_TEXT[m - 1]}月只有 ${hit.length} 天,没有 ${d} 日`);
|
|
6879
|
+
const p = fromJDN(hit.startJdn + d - 1);
|
|
6880
|
+
solar = { year: p.year, month: p.month, day: p.day };
|
|
6881
|
+
const check = solarToLunar(p.year, p.month, p.day);
|
|
6882
|
+
if (check.month !== m || check.day !== d || check.isLeap !== isLeap) {
|
|
6883
|
+
note = '反查结果与目标农历日不完全一致,已按本地历法实际月首回推';
|
|
6884
|
+
}
|
|
6885
|
+
lunar = check;
|
|
6886
|
+
}
|
|
6887
|
+
|
|
6888
|
+
const a = buildAlmanac(solar);
|
|
6889
|
+
const jdn = toJDN(solar.year, solar.month, solar.day);
|
|
6890
|
+
const solarText = `${solar.year}-${String(solar.month).padStart(2, '0')}-${String(solar.day).padStart(2, '0')}`;
|
|
6891
|
+
return {
|
|
6892
|
+
system: 'convert',
|
|
6893
|
+
meta: {
|
|
6894
|
+
mode,
|
|
6895
|
+
solarDate: solarText,
|
|
6896
|
+
weekday: `星期${WEEK[(jdn + 1) % 7]}`,
|
|
6897
|
+
...(note ? { note } : {}),
|
|
6898
|
+
scope: '公农历互转按本地定朔历(1900–2100);农历闰月须显式指定,不自动猜同名月',
|
|
6899
|
+
},
|
|
6900
|
+
solar: { year: solar.year, month: solar.month, day: solar.day, text: solarText },
|
|
6901
|
+
lunar: {
|
|
6902
|
+
year: lunar.lunarYear,
|
|
6903
|
+
month: lunar.month,
|
|
6904
|
+
day: lunar.day,
|
|
6905
|
+
isLeap: lunar.isLeap,
|
|
6906
|
+
text: lunarText(lunar.lunarYear, lunar.month, lunar.day, lunar.isLeap),
|
|
6907
|
+
},
|
|
6908
|
+
ganzhi: {
|
|
6909
|
+
year: a.ganzhi.year,
|
|
6910
|
+
month: a.ganzhi.month,
|
|
6911
|
+
day: a.ganzhi.day,
|
|
6912
|
+
shengXiao: a.ganzhi.shengXiao,
|
|
6913
|
+
springYear: a.ganzhi.springYear,
|
|
6914
|
+
},
|
|
6915
|
+
sources: ['农历:本地定朔 + 节气黄经历法(engine/lunar.js)', '干支与生肖:与黄历同口径(年按立春界,另列春节界)'],
|
|
6916
|
+
disclaimer: '历法换算为确定性计算;民俗历法各版本在极少数日期(交节当日、闰月边界)存在日界差异,已注明口径。',
|
|
6917
|
+
};
|
|
6918
|
+
}
|
|
6919
|
+
|
|
6920
|
+
return { buildConvert };
|
|
6421
6921
|
})();
|
|
6422
6922
|
|
|
6423
6923
|
__mods['interpret-plain'] = (function () {
|
|
@@ -7001,6 +7501,7 @@ function baziInterpret(r) {
|
|
|
7001
7501
|
const st = isObj(r.strength) ? r.strength : {};
|
|
7002
7502
|
const frame = isObj(r.frame) ? r.frame : {};
|
|
7003
7503
|
const ys = isObj(frame.yongshen) ? frame.yongshen : {};
|
|
7504
|
+
const cli = r.climate || (isObj(ys.climate) ? ys.climate : (isObj(ys.tiaohou) ? ys.tiaohou : null));
|
|
7004
7505
|
const wx = isObj(r.wuxing) ? r.wuxing : {};
|
|
7005
7506
|
const level = pick(st, 'level', '中和');
|
|
7006
7507
|
const favor = Array.isArray(ys.favor) ? ys.favor : [];
|
|
@@ -7184,10 +7685,12 @@ function baziInterpret(r) {
|
|
|
7184
7685
|
else if (!good.includes(curTier) && !good.includes(lnTier)) out.push('大运与流年都偏逆:以守住基本盘为主,减少新增承诺。');
|
|
7185
7686
|
else out.push('大运与流年同向偏顺:可以把想做但一直拖着的事排上日程。');
|
|
7186
7687
|
}
|
|
7187
|
-
const
|
|
7188
|
-
if (
|
|
7189
|
-
|
|
7190
|
-
|
|
7688
|
+
const th = ys.tiaohou && ys.tiaohou.need ? ys.tiaohou : null;
|
|
7689
|
+
if (th) {
|
|
7690
|
+
out.push(th.clash
|
|
7691
|
+
? `调候要${th.need.stem}${th.need.element},扶抑不在喜用里:两套取法有分歧,本盘按调候优先——寒暖失衡时,再补强弱也难受。`
|
|
7692
|
+
: `调候要${th.need.stem}${th.need.element},与扶抑用神同向:取用上不打架,${th.need.element}相关的行业与环境优先。`);
|
|
7693
|
+
}
|
|
7191
7694
|
return out.join(' ');
|
|
7192
7695
|
})(),
|
|
7193
7696
|
},
|
|
@@ -7196,6 +7699,12 @@ function baziInterpret(r) {
|
|
|
7196
7699
|
text: `喜用:${join(favor)}(对应十神:${join(ys.favorTenGods || ys.favorRoles || [])});忌:${join(avoid)}(对应十神:${join(ys.avoidTenGods || ys.avoidRoles || [])})。` +
|
|
7197
7700
|
`${pick(ys, 'detail', '')}`,
|
|
7198
7701
|
},
|
|
7702
|
+
...(cli ? [{
|
|
7703
|
+
key: 'climate', label: '寒暖燥湿',
|
|
7704
|
+
text: `${cli.narration}${cli.need
|
|
7705
|
+
? `调候取${cli.need.stem}${cli.need.element},忌${cli.avoidElement};${cli.clash ? '与扶抑冲突,本盘以调候为先' : '与扶抑同向'}`
|
|
7706
|
+
: '气候平和,调候不作主取'}。`,
|
|
7707
|
+
}] : []),
|
|
7199
7708
|
{
|
|
7200
7709
|
key: 'geju', label: '格局依据',
|
|
7201
7710
|
text: (Array.isArray(frame.geju) ? frame.geju : []).map((g) => `${g.name}(${g.kind}):${g.evidence}`).join(';') || '未取到格局',
|
|
@@ -7206,7 +7715,7 @@ function baziInterpret(r) {
|
|
|
7206
7715
|
},
|
|
7207
7716
|
{
|
|
7208
7717
|
key: 'limits', label: '未纳入',
|
|
7209
|
-
text: '
|
|
7718
|
+
text: '本盘没有计算:流月与流日、神煞的加权轻重、地支藏干的动态引化(合冲后再论)。取用按「调候优先、扶抑校验」;调候由月令与全局寒暖燥湿判定,未逐条录入穷通宝鉴 120 条,各派取法仍有分歧;真太阳时未含历史时区与夏令时。把这些补上会改变"强弱"的边际判断,所以这里只给方向,不下断语。',
|
|
7210
7719
|
},
|
|
7211
7720
|
];
|
|
7212
7721
|
|
|
@@ -8590,6 +9099,7 @@ const { buildChenggu } = __mods.chenggu;
|
|
|
8590
9099
|
const { buildXiaoliuren } = __mods.xiaoliuren;
|
|
8591
9100
|
const { buildStar } = __mods.star;
|
|
8592
9101
|
const { buildNumerology } = __mods.numerology;
|
|
9102
|
+
const { buildConvert } = __mods.convert;
|
|
8593
9103
|
const { buildTrend } = __mods.trend;
|
|
8594
9104
|
const { buildFengshui } = __mods.fengshui;
|
|
8595
9105
|
const { buildName } = __mods.name;
|
|
@@ -8667,6 +9177,7 @@ function baziText(r) {
|
|
|
8667
9177
|
` ${r.frame.geju.map((g) => `${g.name}[${g.kind}]`).join(' ')}`,
|
|
8668
9178
|
`用神:喜${r.frame.yongshen.favor.join('')}(${r.frame.yongshen.favorTenGods.join('、')}) 忌${r.frame.yongshen.avoid.join('')}(${r.frame.yongshen.avoidTenGods.join('、')}) ${r.frame.yongshen.method}`,
|
|
8669
9179
|
` ${r.frame.yongshen.detail}`,
|
|
9180
|
+
`寒暖:${r.climate ? `${r.climate.label}(${(r.climate.evidence || []).join('、')})${r.climate.need ? ` 调候取${r.climate.need.stem}${r.climate.need.element} 忌${r.climate.avoidElement}` : ''}` : '—'}`,
|
|
8670
9181
|
`十神权重:${Object.entries(r.frame.godStats.groups).map(([k, v]) => `${k}${v}`).join(' ')}`,
|
|
8671
9182
|
] : [];
|
|
8672
9183
|
return [
|
|
@@ -9144,6 +9655,26 @@ function computeRaw(args = {}) {
|
|
|
9144
9655
|
const result = buildChenggu({ year: dt.year, month: dt.month, day: dt.day, hour, minute: hasTime ? dt.minute : 0 });
|
|
9145
9656
|
return { ...result, summary: chengguText(result) };
|
|
9146
9657
|
}
|
|
9658
|
+
if (system === 'convert') {
|
|
9659
|
+
const mode = args.mode === 'lunar2solar' ? 'lunar2solar' : 'solar2lunar';
|
|
9660
|
+
let result;
|
|
9661
|
+
if (mode === 'lunar2solar') {
|
|
9662
|
+
if (args.lunarYear == null || args.lunarMonth == null || args.lunarDay == null) {
|
|
9663
|
+
throw fail('E_INPUT', '农历转公历需要 lunarYear / lunarMonth / lunarDay(闰月另加 isLeapMonth: true)');
|
|
9664
|
+
}
|
|
9665
|
+
result = buildConvert({
|
|
9666
|
+
mode,
|
|
9667
|
+
lunarYear: Number(args.lunarYear),
|
|
9668
|
+
lunarMonth: Number(args.lunarMonth),
|
|
9669
|
+
lunarDay: Number(args.lunarDay),
|
|
9670
|
+
isLeapMonth: args.isLeapMonth === true,
|
|
9671
|
+
});
|
|
9672
|
+
} else {
|
|
9673
|
+
const dt = parseDateTime(args.datetime);
|
|
9674
|
+
result = buildConvert({ mode, year: dt.year, month: dt.month, day: dt.day });
|
|
9675
|
+
}
|
|
9676
|
+
return { ...result, summary: convertText(result) };
|
|
9677
|
+
}
|
|
9147
9678
|
if (system === 'xiaoliuren') {
|
|
9148
9679
|
const dt = args.datetime ? parseDateTime(args.datetime) : null;
|
|
9149
9680
|
const result = buildXiaoliuren({
|
|
@@ -9227,21 +9758,34 @@ function computeRaw(args = {}) {
|
|
|
9227
9758
|
return { ...result, summary: nameText(result) };
|
|
9228
9759
|
}
|
|
9229
9760
|
if (!system) {
|
|
9230
|
-
throw fail('E_INPUT', '缺少 system,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name
|
|
9761
|
+
throw fail('E_INPUT', '缺少 system,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name(起名)、convert(公农历互转)。');
|
|
9231
9762
|
}
|
|
9232
|
-
throw fail('E_SYSTEM', `未知体系「${system}」,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name
|
|
9763
|
+
throw fail('E_SYSTEM', `未知体系「${system}」,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name(起名)、convert(公农历互转)。`);
|
|
9233
9764
|
}
|
|
9234
9765
|
|
|
9235
9766
|
function almanacText(r) {
|
|
9236
9767
|
const g = r.ganzhi;
|
|
9237
9768
|
const jq = r.jieQi && r.jieQi.next ? ` 下一节:${r.jieQi.next.name} ${r.jieQi.next.date}` : '';
|
|
9769
|
+
const god = r.dayGod ? `值日:${r.dayGod.name}(${r.dayGod.type}·${r.dayGod.luck})` : '';
|
|
9770
|
+
const xiu = r.xiu ? `二十八宿:${r.xiu.name}宿(${r.xiu.luck}·${r.xiu.zheng}·${r.xiu.animal})` : '';
|
|
9771
|
+
const tai = r.taiShen ? `胎神:${r.taiShen}` : '';
|
|
9772
|
+
const pos = r.positions
|
|
9773
|
+
? `吉神方位:喜神${r.positions.xiShen || '—'} 财神${r.positions.caiShen || '—'} 福神${r.positions.fuShen ? r.positions.fuShen.dir : '—'} 阳贵${r.positions.yangGui ? r.positions.yangGui.dir : '—'} 阴贵${r.positions.yinGui ? r.positions.yinGui.dir : '—'}`
|
|
9774
|
+
: '';
|
|
9775
|
+
const lucky = r.lucky ? `吉配生肖:六合${r.lucky.liuhe || '—'} 三合${(r.lucky.sanhe || []).join('、') || '—'}` : '';
|
|
9776
|
+
const nayin = r.nayin && r.nayin.day ? `日柱纳音:${r.nayin.day.name}` : '';
|
|
9777
|
+
const hours = (r.hours || []).map((h) => `${h.zhi}${h.ganZhi.slice(0, 1)}·${h.shen}${h.luck === '吉' ? '吉' : '凶'}`).join(' ');
|
|
9238
9778
|
return [
|
|
9239
9779
|
`【黄历】${r.meta.date} ${r.meta.weekday} ${r.lunar.text}`,
|
|
9240
9780
|
`干支:${g.year}年 ${g.month}月 ${g.day}日 属${g.shengXiao}`,
|
|
9241
9781
|
...(r.meta.boundaryNote ? [` ${r.meta.boundaryNote}`] : []),
|
|
9242
|
-
`建除:${r.zhiXing}日 冲:${r.chong.text}${r.chong.sha ? `(${r.chong.sha})` : ''}
|
|
9782
|
+
`建除:${r.zhiXing}日 冲:${r.chong.text}${r.chong.sha ? `(${r.chong.sha})` : ''} ${god}`,
|
|
9783
|
+
[xiu, nayin, tai].filter(Boolean).join(' '),
|
|
9243
9784
|
`宜:${r.yi.join('、')}`,
|
|
9244
9785
|
`忌:${r.ji.join('、')}`,
|
|
9786
|
+
pos,
|
|
9787
|
+
lucky,
|
|
9788
|
+
hours ? `时辰吉凶:${hours}` : '',
|
|
9245
9789
|
`节气:上一节 ${r.jieQi.prev ? `${r.jieQi.prev.name} ${r.jieQi.prev.date}` : '—'}${jq}`,
|
|
9246
9790
|
r.dailyHexagram ? `每日一卦:${r.dailyHexagram.name} ${r.dailyHexagram.meaning || ''}` : '',
|
|
9247
9791
|
`口径:${r.meta.scope}`,
|
|
@@ -9297,6 +9841,17 @@ function starText(r) {
|
|
|
9297
9841
|
].join('\n');
|
|
9298
9842
|
}
|
|
9299
9843
|
|
|
9844
|
+
function convertText(r) {
|
|
9845
|
+
const g = r.ganzhi;
|
|
9846
|
+
const dir = r.meta.mode === 'lunar2solar' ? '农历 → 公历' : '公历 → 农历';
|
|
9847
|
+
return [
|
|
9848
|
+
`【公农历转换·${dir}】${r.lunar.text} ⇄ ${r.solar.text} ${r.meta.weekday}`,
|
|
9849
|
+
`干支:${g.year}年 ${g.month}月 ${g.day}日 属${g.shengXiao}${g.springYear && g.springYear !== g.year ? `(春节界为${g.springYear}年)` : ''}`,
|
|
9850
|
+
...(r.meta.note ? [`注:${r.meta.note}`] : []),
|
|
9851
|
+
`口径:${r.meta.scope}`,
|
|
9852
|
+
].join('\n');
|
|
9853
|
+
}
|
|
9854
|
+
|
|
9300
9855
|
function numerologyText(r) {
|
|
9301
9856
|
return [
|
|
9302
9857
|
`【生命数字】${r.meta.date}(西方数字学,与八字/紫微不可互证)`,
|
|
@@ -9391,7 +9946,7 @@ function renderText(result) {
|
|
|
9391
9946
|
return parts.filter(Boolean).join('\n\n');
|
|
9392
9947
|
}
|
|
9393
9948
|
|
|
9394
|
-
return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAddress, resolveAddress, buildBazi, buildLiuyao, tossLines, followup, pastSignals, verifyFit, rectifyBirth, crossCheck, crossText, buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buildNumerology, buildTrend, buildFengshui, buildName, parseDateTime, compute, interpretText, renderText };
|
|
9949
|
+
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 };
|
|
9395
9950
|
})();
|
|
9396
9951
|
|
|
9397
9952
|
const Engine = __mods.index;
|
|
@@ -9921,7 +10476,52 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
9921
10476
|
@media print{.mp-cg{break-inside:avoid}}
|
|
9922
10477
|
@media (max-width:640px){.mp-cg-w{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
|
9923
10478
|
.mp-quick-h{font-size:13px;color:var(--lu);margin-bottom:6px;font-family:system-ui,sans-serif}
|
|
10479
|
+
.mp-cli{margin:10px 0;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--card)}
|
|
10480
|
+
.mp-cli-h{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ink)}
|
|
10481
|
+
.mp-cli-h b{font-size:13px}
|
|
10482
|
+
.mp-cli-k{font-weight:700;color:var(--lu)}
|
|
10483
|
+
.mp-cli-p{margin-left:auto;font-size:11.5px;color:var(--quan);background:var(--bg);border:1px solid var(--line);border-radius:999px;padding:1px 8px}
|
|
10484
|
+
.mp-cli-bar{position:relative;margin:9px 0 4px;height:8px;border-radius:999px;background:linear-gradient(90deg,var(--quan) 0%,var(--line) 50%,var(--ji) 100%)}
|
|
10485
|
+
.mp-cli-bar i{position:absolute;top:-3px;width:14px;height:14px;margin-left:-7px;border-radius:50%;background:var(--card);border:2px solid var(--ink);box-shadow:0 0 0 2px var(--card)}
|
|
10486
|
+
.mp-cli-axis{display:flex;justify-content:space-between;font-size:11px;color:var(--ink3);margin-bottom:8px}
|
|
10487
|
+
.mp-cli-row{display:flex;flex-wrap:wrap;gap:6px 10px;align-items:center;font-size:12.5px;color:var(--ink2)}
|
|
10488
|
+
.mp-cli-row em{font-style:normal;color:var(--ink3)}
|
|
10489
|
+
.mp-cli-row b{color:var(--ink)}
|
|
10490
|
+
.mp-cli-narr{margin-top:8px;font-size:13px;line-height:1.85;color:var(--ink2);border-left:2px solid var(--quan);padding-left:9px}
|
|
10491
|
+
@media print{.mp-cli{break-inside:avoid}}
|
|
9924
10492
|
.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)}
|
|
10493
|
+
.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}
|
|
10494
|
+
.mp-al-h{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;border-bottom:1px solid var(--hair);padding-bottom:8px;margin-bottom:9px}
|
|
10495
|
+
.mp-al-h b{font-size:18px;color:var(--ink);font-weight:700;font-variant-numeric:tabular-nums}
|
|
10496
|
+
.mp-al-h i{font-style:normal;font-size:12px;color:var(--muted)}
|
|
10497
|
+
.mp-al-gz{font-size:12.5px;color:var(--ink2);margin-bottom:9px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
10498
|
+
.mp-al-badge{font-size:11px;border:1px solid var(--line);border-radius:999px;padding:1px 8px}
|
|
10499
|
+
.mp-al-badge.good{color:var(--lu);border-color:var(--lu)}
|
|
10500
|
+
.mp-al-badge.bad{color:var(--ji);border-color:var(--ji)}
|
|
10501
|
+
.mp-al-yiji{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:6px 0 9px}
|
|
10502
|
+
.mp-al-col em,.mp-al-row>em{font-style:normal;font-size:10.5px;color:var(--muted);display:block;margin-bottom:4px}
|
|
10503
|
+
.mp-al-chips{display:flex;flex-wrap:wrap;gap:4px}
|
|
10504
|
+
.mp-al-chip{font-size:11.5px;padding:1px 7px;border:1px solid var(--line);border-radius:999px;color:var(--ink2);white-space:nowrap}
|
|
10505
|
+
.mp-al-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:6px;overflow:hidden;margin:8px 0}
|
|
10506
|
+
.mp-al-cell{background:var(--card);padding:6px 8px;min-width:0}
|
|
10507
|
+
.mp-al-cell em{display:block;font-style:normal;font-size:10.5px;color:var(--muted);margin-bottom:2px}
|
|
10508
|
+
.mp-al-cell b{font-size:12.5px;color:var(--ink);font-weight:600;line-height:1.45;display:block}
|
|
10509
|
+
.mp-al-row{margin:9px 0}
|
|
10510
|
+
.mp-al-hours{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:5px}
|
|
10511
|
+
.mp-al-hour{display:flex;align-items:baseline;gap:3px;border:1px solid var(--hair);border-radius:5px;padding:3px 6px;font-size:11px;color:var(--ink2);background:var(--band)}
|
|
10512
|
+
.mp-al-hour i{font-style:normal;font-weight:600;color:var(--ink)}
|
|
10513
|
+
.mp-al-hour em{font-style:normal;color:var(--muted)}
|
|
10514
|
+
.mp-al-hour b{font-weight:500}
|
|
10515
|
+
.mp-al-hour u{text-decoration:none;margin-left:auto;font-size:10.5px}
|
|
10516
|
+
.mp-al-hour.good{border-color:var(--lu);color:var(--lu)}
|
|
10517
|
+
.mp-al-hour.good i{color:var(--lu)}
|
|
10518
|
+
.mp-al-hour.bad{border-color:var(--hair)}
|
|
10519
|
+
.mp-al-hour.bad u{color:var(--ji)}
|
|
10520
|
+
.mp-al-hex{margin-top:8px;font-size:12px;color:var(--ink2)}
|
|
10521
|
+
.mp-al-hex b{color:var(--quan)}
|
|
10522
|
+
.mp-al-note{margin-top:9px;padding-top:8px;border-top:1px dashed var(--line);font-size:11px;line-height:1.7;color:var(--muted)}
|
|
10523
|
+
@media print{.mp-al{break-inside:avoid}}
|
|
10524
|
+
@media (max-width:640px){.mp-al{margin:10px;padding:10px}.mp-al-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.mp-al-yiji{grid-template-columns:1fr}}.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)}
|
|
9925
10525
|
.mp-it-dis{padding:11px 16px;border-top:1px solid var(--line);background:var(--band);font-size:12px;line-height:1.75;color:var(--muted);font-family:system-ui,sans-serif}
|
|
9926
10526
|
|
|
9927
10527
|
@media (max-width:640px){
|
|
@@ -10715,7 +11315,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
10715
11315
|
const num = (v) => (typeof v === 'number' && isFinite(v) ? v : 0);
|
|
10716
11316
|
const dyScore = (d) => (d.luck ? num(d.luck.score) : 0);
|
|
10717
11317
|
|
|
10718
|
-
const VMAX =
|
|
11318
|
+
const VMAX = 4.2;
|
|
10719
11319
|
const VMIN = -2.2;
|
|
10720
11320
|
const startAge = num(r.dayun.startAge && r.dayun.startAge.years);
|
|
10721
11321
|
const dyEnd = dyList.length
|
|
@@ -10731,7 +11331,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
10731
11331
|
const pw = W - M.l - M.r;
|
|
10732
11332
|
const ph = H - M.t - M.b;
|
|
10733
11333
|
const X = (age) => M.l + ((age - a0) / span) * pw;
|
|
10734
|
-
const Y = (v) => M.t + ph - ((v - VMIN) / (VMAX - VMIN)) * ph;
|
|
11334
|
+
const Y = (v) => M.t + ph - ((Math.max(VMIN, Math.min(VMAX, v)) - VMIN) / (VMAX - VMIN)) * ph;
|
|
10735
11335
|
|
|
10736
11336
|
const BANDS = [
|
|
10737
11337
|
{ from: 1.2, to: VMAX, cls: 'b-good' },
|
|
@@ -11056,6 +11656,21 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
11056
11656
|
<div class="pp-tl">喜 ${fr.yongshen.favor.map(el).join('')} 忌 ${fr.yongshen.avoid.map(el).join('')} <span class="pp-dim">${esc(fr.yongshen.method)}</span></div>
|
|
11057
11657
|
<div class="pp-chips">${fr.yongshen.favorTenGods.map((t) => `<span class="pp-chip ok">${esc(t)}</span>`).join('')}${fr.yongshen.avoidTenGods ? fr.yongshen.avoidTenGods.map((t) => `<span class="pp-chip warn">${esc(t)}</span>`).join('') : ''}</div>
|
|
11058
11658
|
<div class="pp-tl pp-dim">${esc(fr.yongshen.detail)}</div>` : '';
|
|
11659
|
+
const cli = r.climate || (fr.yongshen && fr.yongshen.climate) || null;
|
|
11660
|
+
const cliCard = cli ? (() => {
|
|
11661
|
+
const pct = Math.max(2, Math.min(98, Math.round(((Number(cli.temp) || 0) + 3) / 6 * 100)));
|
|
11662
|
+
const need = cli.need ? `<em>调候取</em><b>${esc(cli.need.stem + cli.need.element)}</b>` : '<em>气候平和</em>';
|
|
11663
|
+
const avoid = cli.need ? `<em>忌</em><b>${esc(cli.avoidElement)}</b>` : '';
|
|
11664
|
+
const ev = (cli.evidence || []).length ? `<em>依据</em><span>${esc(cli.evidence.join('、'))}</span>` : '';
|
|
11665
|
+
const pri = cli.priority === '调候优先' ? '<span class="mp-cli-p">调候优先</span>' : '<span class="mp-cli-p">扶抑为主</span>';
|
|
11666
|
+
return `<section class="mp-cli" aria-label="寒暖燥湿">
|
|
11667
|
+
<div class="mp-cli-h"><b>寒暖燥湿</b><span class="mp-cli-k">${esc(cli.label || '')}</span>${pri}</div>
|
|
11668
|
+
<div class="mp-cli-bar" title="寒 ← → 热"><i style="left:${pct}%"></i></div>
|
|
11669
|
+
<div class="mp-cli-axis"><span>寒</span><span>平</span><span>热</span></div>
|
|
11670
|
+
<div class="mp-cli-row">${need}${avoid}${ev}</div>
|
|
11671
|
+
<div class="mp-cli-narr">${esc(cli.narration || '')}</div>
|
|
11672
|
+
</section>`;
|
|
11673
|
+
})() : '';
|
|
11059
11674
|
const gods = fr.godStats ? `<div class="pp-chips">${Object.entries(fr.godStats.groups).map(([k, v]) => `<span class="pp-chip">${k} ${v}</span>`).join('')}</div>` : '';
|
|
11060
11675
|
|
|
11061
11676
|
const dy = r.dayun.list.map((d) => {
|
|
@@ -11081,6 +11696,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
11081
11696
|
${str}
|
|
11082
11697
|
${sect('格局', gj)}
|
|
11083
11698
|
${sect('用神', ys)}
|
|
11699
|
+
${cliCard}
|
|
11084
11700
|
${sect('五行与十神', `<div class="pp-chips">${wx}</div>${gods}`)}
|
|
11085
11701
|
${sect('大运', `${pp.curveHTML(r)}<div class="pp-chips">${dy}</div>`)}
|
|
11086
11702
|
${ln ? sect('流年', ln) : ''}
|
|
@@ -11183,11 +11799,43 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
11183
11799
|
return (html || '') + pp.interpretHTML(it, opt);
|
|
11184
11800
|
};
|
|
11185
11801
|
|
|
11802
|
+
pp.almanacHTML = function (r) {
|
|
11803
|
+
if (!r || !r.meta) return pp.quickHTML(r);
|
|
11804
|
+
const g = r.ganzhi || {};
|
|
11805
|
+
const god = r.dayGod || null;
|
|
11806
|
+
const chips = (list, cls) => (list || []).map((x) => `<span class="mp-al-chip${cls ? ` ${cls}` : ''}">${esc(x)}</span>`).join('');
|
|
11807
|
+
const cell = (k, v) => (v ? `<div class="mp-al-cell"><em>${esc(k)}</em><b>${esc(v)}</b></div>` : '');
|
|
11808
|
+
const xiu = r.xiu ? `${r.xiu.name}宿(${r.xiu.luck}·${r.xiu.zheng}·${r.xiu.animal})` : '';
|
|
11809
|
+
const nayin = r.nayin && r.nayin.day ? r.nayin.day.name : '';
|
|
11810
|
+
const chong = r.chong ? `${r.chong.text}${r.chong.sha ? ` ${r.chong.sha}` : ''}` : '';
|
|
11811
|
+
const hours = (r.hours || []).map((h) => `<span class="mp-al-hour ${h.luck === '吉' ? 'good' : 'bad'}">`
|
|
11812
|
+
+ `<i>${esc(h.zhi)}</i><em>${esc((h.ganZhi || '').slice(0, 1))}</em><b>${esc(h.shen || '')}</b>`
|
|
11813
|
+
+ `<u>${esc(h.luck || '')}</u></span>`).join('');
|
|
11814
|
+
const pos = r.positions || {};
|
|
11815
|
+
const posRow = (k, v) => (v ? `<span class="mp-al-chip">${esc(k)}·${esc(typeof v === 'string' ? v : v.dir || '')}</span>` : '');
|
|
11816
|
+
const lucky = r.lucky || {};
|
|
11817
|
+
const godBadge = god ? `<span class="mp-al-badge ${god.luck === '吉' ? 'good' : 'bad'}">${esc(god.name)}·${esc(god.type)}·${esc(god.luck)}</span>` : '';
|
|
11818
|
+
return `<section class="mp-al" aria-label="黄历">
|
|
11819
|
+
<div class="mp-al-h"><b>${esc(r.meta.date || '')}</b><i>${esc(r.meta.weekday || '')} ${esc((r.lunar || {}).text || '')}</i></div>
|
|
11820
|
+
<div class="mp-al-gz">${esc(g.year || '')}年 ${esc(g.month || '')}月 ${esc(g.day || '')}日 属${esc(g.shengXiao || '')} 建除 ${esc(r.zhiXing || '')}日 ${godBadge}</div>
|
|
11821
|
+
<div class="mp-al-yiji">
|
|
11822
|
+
<div class="mp-al-col"><em>宜</em><div class="mp-al-chips">${chips(r.yi)}</div></div>
|
|
11823
|
+
<div class="mp-al-col"><em>忌</em><div class="mp-al-chips">${chips(r.ji)}</div></div>
|
|
11824
|
+
</div>
|
|
11825
|
+
<div class="mp-al-grid">${cell('二十八宿', xiu)}${cell('日柱纳音', nayin)}${cell('胎神', r.taiShen)}${cell('冲煞', chong)}</div>
|
|
11826
|
+
<div class="mp-al-row"><em>吉神方位</em><div class="mp-al-chips">${posRow('喜神', pos.xiShen)}${posRow('财神', pos.caiShen)}${posRow('福神', pos.fuShen)}${posRow('阳贵', pos.yangGui)}${posRow('阴贵', pos.yinGui)}</div></div>
|
|
11827
|
+
<div class="mp-al-row"><em>时刻吉凶</em><div class="mp-al-hours">${hours}</div></div>
|
|
11828
|
+
<div class="mp-al-row"><em>吉配生肖</em><div class="mp-al-chips">${lucky.liuhe ? `<span class="mp-al-chip">六合·${esc(lucky.liuhe)}</span>` : ''}${chips(lucky.sanhe || [])}</div></div>
|
|
11829
|
+
${r.dailyHexagram ? `<div class="mp-al-hex">每日一卦:<b>${esc(r.dailyHexagram.name)}</b> ${esc(r.dailyHexagram.meaning || '')}</div>` : ''}
|
|
11830
|
+
<div class="mp-al-note">${esc((r.meta && r.meta.scope) || '')}</div>
|
|
11831
|
+
</section>`;
|
|
11832
|
+
};
|
|
11833
|
+
|
|
11186
11834
|
pp.quickHTML = function (r) {
|
|
11187
11835
|
if (!r) return '';
|
|
11188
11836
|
const LABEL = {
|
|
11189
11837
|
almanac: '黄历', zeri: '择日', chenggu: '称骨', xiaoliuren: '小六壬',
|
|
11190
|
-
star: '星座', numerology: '生命数字', trend: '人生 K 线', fengshui: '风水', name: '起名',
|
|
11838
|
+
star: '星座', numerology: '生命数字', trend: '人生 K 线', fengshui: '风水', name: '起名', convert: '公农历转换',
|
|
11191
11839
|
};
|
|
11192
11840
|
const title = LABEL[r.system] || '速查';
|
|
11193
11841
|
const text = r.summary || '';
|
|
@@ -11457,7 +12105,8 @@ const TABS = [
|
|
|
11457
12105
|
{ k: 'qimen', label: '奇门', timeLabel: '起局时刻', hint: '奇门时家转盘:用起局时刻定节气、三元与局数;换局规则决定符头与节气如何对齐。' },
|
|
11458
12106
|
{ k: 'hepan', label: '合盘', timeLabel: '你的出生时刻', hint: '合盘按「日主 + 夫妻宫 + 五行互补」看两个人的相处与互补,需要双方出生信息。' },
|
|
11459
12107
|
{ k: 'tarot', label: '塔罗', timeLabel: '', hint: '塔罗不看时间,只记录抽牌时刻与你的提问。' },
|
|
11460
|
-
{ k: 'almanac', label: '黄历', timeLabel: '', hint: '
|
|
12108
|
+
{ k: 'almanac', label: '黄历', timeLabel: '', hint: '黄历按公历日期查农历、干支、宜忌、时辰吉凶、二十八宿与吉神方位;只做本地计算。' },
|
|
12109
|
+
{ k: 'convert', label: '农历', timeLabel: '', hint: '公农历互转:公历生日可反查农历;只知道农历生日时,可转成公历再排盘。' },
|
|
11461
12110
|
{ k: 'zeri', label: '择日', timeLabel: '', hint: '择日把区间内每天的建除宜忌与事项适配打分排序,并按属相排除冲煞日。' },
|
|
11462
12111
|
{ k: 'chenggu', label: '称骨', timeLabel: '出生时刻', hint: '称骨按农历年、月、日、时的骨重求和;时辰必填。' },
|
|
11463
12112
|
{ k: 'xiaoliuren', label: '小六壬', timeLabel: '起课时刻', hint: '小六壬用农历月/日/时掐指,也可用三个随机数起课。' },
|
|
@@ -11479,7 +12128,7 @@ const TIME_KIND = {
|
|
|
11479
12128
|
ziwei: 'birth', bazi: 'birth', hepan: 'birth',
|
|
11480
12129
|
liuyao: 'cast', meihua: 'cast', daliuren: 'cast', qimen: 'cast',
|
|
11481
12130
|
tarot: 'none',
|
|
11482
|
-
almanac: 'date', zeri: 'date', star: 'date', numerology: 'date',
|
|
12131
|
+
almanac: 'date', zeri: 'date', star: 'date', numerology: 'date', convert: 'date',
|
|
11483
12132
|
chenggu: 'birth', trend: 'birth', fengshui: 'birth', name: 'birth',
|
|
11484
12133
|
xiaoliuren: 'cast',
|
|
11485
12134
|
};
|
|
@@ -11514,6 +12163,9 @@ function App() {
|
|
|
11514
12163
|
const [task, setTask] = useState('开业');
|
|
11515
12164
|
const [days, setDays] = useState('30');
|
|
11516
12165
|
const [shengXiao, setShengXiao] = useState('');
|
|
12166
|
+
const [convMode, setConvMode] = useState('solar2lunar');
|
|
12167
|
+
const [lunarDate, setLunarDate] = useState('');
|
|
12168
|
+
const [leapMonth, setLeapMonth] = useState(false);
|
|
11517
12169
|
const [xlrMode, setXlrMode] = useState('time');
|
|
11518
12170
|
const [num1, setNum1] = useState(''); const [num2, setNum2] = useState(''); const [num3, setNum3] = useState('');
|
|
11519
12171
|
const [toAge, setToAge] = useState('60');
|
|
@@ -11619,6 +12271,24 @@ function App() {
|
|
|
11619
12271
|
delete args.datetime;
|
|
11620
12272
|
}
|
|
11621
12273
|
}
|
|
12274
|
+
if (k === 'convert') {
|
|
12275
|
+
args.system = 'convert';
|
|
12276
|
+
if (convMode === 'lunar2solar') {
|
|
12277
|
+
const m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(String(lunarDate).trim());
|
|
12278
|
+
if (!m) {
|
|
12279
|
+
setError('农历转公历请按「农历年-月-日」填写,例如 2026-9-17;闰月单独勾选。');
|
|
12280
|
+
return;
|
|
12281
|
+
}
|
|
12282
|
+
args.mode = 'lunar2solar';
|
|
12283
|
+
args.lunarYear = Number(m[1]);
|
|
12284
|
+
args.lunarMonth = Number(m[2]);
|
|
12285
|
+
args.lunarDay = Number(m[3]);
|
|
12286
|
+
args.isLeapMonth = leapMonth;
|
|
12287
|
+
delete args.datetime;
|
|
12288
|
+
} else {
|
|
12289
|
+
args.mode = 'solar2lunar';
|
|
12290
|
+
}
|
|
12291
|
+
}
|
|
11622
12292
|
if (k === 'tarot') args.count = Number(count);
|
|
11623
12293
|
if (k === 'hepan') {
|
|
11624
12294
|
args.chart = hpChart;
|
|
@@ -11987,8 +12657,24 @@ function App() {
|
|
|
11987
12657
|
})) : null,
|
|
11988
12658
|
tab === 'zeri' ? field('所办事项', h('select', {
|
|
11989
12659
|
className: 'mp-input', value: task, onChange: (e) => setTask(e.target.value),
|
|
11990
|
-
}, [
|
|
11991
|
-
|
|
12660
|
+
}, [
|
|
12661
|
+
['常用', ['嫁娶', '搬家入宅', '出行', '开业', '签订合同', '祭祀']],
|
|
12662
|
+
['婚嫁', ['嫁娶', '订婚', '领证', '提亲', '收送聘金', '满月酒']],
|
|
12663
|
+
['生活', ['搬家', '入宅', '旅行', '访亲友', '入学', '求医', '祭祀']],
|
|
12664
|
+
['建造', ['动土', '装修', '装修建造', '安葬', '试车买车']],
|
|
12665
|
+
['工商', ['开业', '交易', '投资', '签订合同', '签约', '纳财', '赴任']],
|
|
12666
|
+
].map(([g, items]) => h('optgroup', { key: g, label: g },
|
|
12667
|
+
items.map((t) => h('option', { key: `${g}-${t}`, value: t }, t)))))) : null,
|
|
12668
|
+
tab === 'convert' ? field('转换方向', h('div', { className: 'mp-seg' },
|
|
12669
|
+
h('button', { className: convMode === 'solar2lunar' ? 'on' : '', onClick: () => setConvMode('solar2lunar') }, '公历 → 农历'),
|
|
12670
|
+
h('button', { className: convMode === 'lunar2solar' ? 'on' : '', onClick: () => setConvMode('lunar2solar') }, '农历 → 公历'))) : null,
|
|
12671
|
+
(tab === 'convert' && convMode === 'lunar2solar') ? field('农历日期', h('input', {
|
|
12672
|
+
className: 'mp-input', value: lunarDate, placeholder: '如 2026-9-17',
|
|
12673
|
+
onChange: (e) => setLunarDate(e.target.value),
|
|
12674
|
+
})) : null,
|
|
12675
|
+
(tab === 'convert' && convMode === 'lunar2solar') ? h('label', {
|
|
12676
|
+
className: 'mp-check',
|
|
12677
|
+
}, h('input', { type: 'checkbox', checked: leapMonth, onChange: (e) => setLeapMonth(e.target.checked) }), ' 闰月') : null,
|
|
11992
12678
|
tab === 'zeri' ? field('看多少天', h('input', {
|
|
11993
12679
|
className: 'mp-input', type: 'number', min: 1, max: 60, value: days,
|
|
11994
12680
|
onChange: (e) => setDays(e.target.value),
|
|
@@ -12114,6 +12800,7 @@ function App() {
|
|
|
12114
12800
|
: result.kind === 'tarot' ? PP.tarotHTML(result.r)
|
|
12115
12801
|
: result.kind === 'liuyao' ? PP.liuyaoHTML(result.r)
|
|
12116
12802
|
: result.kind === 'chenggu' ? PP.chengguHTML(result.r)
|
|
12803
|
+
: result.kind === 'almanac' ? PP.almanacHTML(result.r)
|
|
12117
12804
|
: result.kind === 'trend' ? PP.trendHTML(result.r)
|
|
12118
12805
|
: PP.quickHTML(result.r),
|
|
12119
12806
|
result.it,
|