dsh-metaphysics 0.18.4 → 0.19.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 +10 -0
- package/README.md +12 -11
- package/client.js +440 -17
- package/engine/almanac.js +137 -3
- package/engine/convert.js +137 -0
- package/engine/geo.js +1 -1
- package/engine/index.js +51 -5
- 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.19.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;
|
|
@@ -5732,6 +5732,7 @@ return { TRIGRAM, YAO_POSITION, MOVING_NATURE, HEX64, HEX_BY_CORE, ZIWEI_STARS,
|
|
|
5732
5732
|
|
|
5733
5733
|
__mods.almanac = (function () {
|
|
5734
5734
|
const { solarToLunar } = __mods.lunar;
|
|
5735
|
+
const { nayinOf } = __mods.nayin;
|
|
5735
5736
|
const { toJDN, fromJDN, dayGanzhiIndex, ganzhiName, termWindow, termInstantJd, partsToJd, STEMS, BRANCHES, TERM_NAMES } = __mods.calendar;
|
|
5736
5737
|
const { HEX64 } = __mods['interpret-data'];
|
|
5737
5738
|
const { assertCivil, daysInMonth } = __mods.validate;
|
|
@@ -5803,6 +5804,80 @@ function lunarMonthText(month, isLeap = false) {
|
|
|
5803
5804
|
return `${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月`;
|
|
5804
5805
|
}
|
|
5805
5806
|
|
|
5807
|
+
const TIAN_SHEN = ['青龙', '明堂', '天刑', '朱雀', '金匮', '天德', '白虎', '玉堂', '天牢', '玄武', '司命', '勾陈'];
|
|
5808
|
+
const TIAN_SHEN_TYPE = {
|
|
5809
|
+
青龙: '黄道', 明堂: '黄道', 金匮: '黄道', 天德: '黄道', 玉堂: '黄道', 司命: '黄道',
|
|
5810
|
+
天刑: '黑道', 朱雀: '黑道', 白虎: '黑道', 天牢: '黑道', 玄武: '黑道', 勾陈: '黑道',
|
|
5811
|
+
};
|
|
5812
|
+
const TIAN_SHEN_OFFSET = { 子: 4, 丑: 2, 寅: 0, 卯: 10, 辰: 8, 巳: 6, 午: 4, 未: 2, 申: 0, 酉: 10, 戌: 8, 亥: 6 };
|
|
5813
|
+
|
|
5814
|
+
function tianShenOf(branch, anchorBranch) {
|
|
5815
|
+
const b = BRANCHES.indexOf(branch);
|
|
5816
|
+
const off = TIAN_SHEN_OFFSET[anchorBranch];
|
|
5817
|
+
if (b < 0 || off == null) return null;
|
|
5818
|
+
const name = TIAN_SHEN[(b + off) % 12];
|
|
5819
|
+
const type = TIAN_SHEN_TYPE[name];
|
|
5820
|
+
return { name, type, luck: type === '黄道' ? '吉' : '凶' };
|
|
5821
|
+
}
|
|
5822
|
+
|
|
5823
|
+
const MANSIONS = {
|
|
5824
|
+
角: { luck: '吉', zheng: '木', animal: '蛟', gong: '东' }, 亢: { luck: '凶', zheng: '金', animal: '龙', gong: '东' },
|
|
5825
|
+
氐: { luck: '凶', zheng: '土', animal: '貉', gong: '东' }, 房: { luck: '吉', zheng: '日', animal: '兔', gong: '东' },
|
|
5826
|
+
心: { luck: '凶', zheng: '月', animal: '狐', gong: '东' }, 尾: { luck: '吉', zheng: '火', animal: '虎', gong: '东' },
|
|
5827
|
+
箕: { luck: '吉', zheng: '水', animal: '豹', gong: '东' }, 斗: { luck: '吉', zheng: '木', animal: '獬', gong: '北' },
|
|
5828
|
+
牛: { luck: '凶', zheng: '金', animal: '牛', gong: '北' }, 女: { luck: '凶', zheng: '土', animal: '蝠', gong: '北' },
|
|
5829
|
+
虚: { luck: '凶', zheng: '日', animal: '鼠', gong: '北' }, 危: { luck: '凶', zheng: '月', animal: '燕', gong: '北' },
|
|
5830
|
+
室: { luck: '吉', zheng: '火', animal: '猪', gong: '北' }, 壁: { luck: '吉', zheng: '水', animal: '獝', gong: '北' },
|
|
5831
|
+
奎: { luck: '凶', zheng: '木', animal: '狼', gong: '西' }, 娄: { luck: '吉', zheng: '金', animal: '狗', gong: '西' },
|
|
5832
|
+
胃: { luck: '吉', zheng: '土', animal: '彘', gong: '西' }, 昴: { luck: '凶', zheng: '日', animal: '鸡', gong: '西' },
|
|
5833
|
+
毕: { luck: '吉', zheng: '月', animal: '乌', gong: '西' }, 觜: { luck: '凶', zheng: '火', animal: '猴', gong: '西' },
|
|
5834
|
+
参: { luck: '吉', zheng: '水', animal: '猿', gong: '西' }, 井: { luck: '吉', zheng: '木', animal: '犴', gong: '南' },
|
|
5835
|
+
鬼: { luck: '凶', zheng: '金', animal: '羊', gong: '南' }, 柳: { luck: '凶', zheng: '土', animal: '獐', gong: '南' },
|
|
5836
|
+
星: { luck: '凶', zheng: '日', animal: '马', gong: '南' }, 张: { luck: '吉', zheng: '月', animal: '鹿', gong: '南' },
|
|
5837
|
+
翼: { luck: '凶', zheng: '火', animal: '蛇', gong: '南' }, 轸: { luck: '吉', zheng: '水', animal: '蚓', gong: '南' },
|
|
5838
|
+
};
|
|
5839
|
+
const XIU_GROUPS = {
|
|
5840
|
+
A: ['虚', '毕', '翼', '箕', '奎', '鬼', '氐'],
|
|
5841
|
+
B: ['房', '危', '觜', '轸', '斗', '娄', '柳'],
|
|
5842
|
+
C: ['星', '心', '室', '参', '角', '牛', '胃'],
|
|
5843
|
+
D: ['昴', '张', '尾', '壁', '井', '亢', '女'],
|
|
5844
|
+
};
|
|
5845
|
+
const XIU_GROUP_OF = { 子: 'A', 辰: 'A', 申: 'A', 丑: 'B', 巳: 'B', 酉: 'B', 寅: 'C', 午: 'C', 戌: 'C', 卯: 'D', 未: 'D', 亥: 'D' };
|
|
5846
|
+
|
|
5847
|
+
function xiuOf(dayBranch, weekdayIndex) {
|
|
5848
|
+
const g = XIU_GROUP_OF[dayBranch];
|
|
5849
|
+
if (!g) return null;
|
|
5850
|
+
const name = XIU_GROUPS[g][weekdayIndex];
|
|
5851
|
+
const info = MANSIONS[name];
|
|
5852
|
+
return info ? { name, ...info } : null;
|
|
5853
|
+
}
|
|
5854
|
+
|
|
5855
|
+
const DIR_OF = { 坎: '正北', 艮: '东北', 震: '正东', 巽: '东南', 离: '正南', 坤: '西南', 兑: '正西', 乾: '西北' };
|
|
5856
|
+
const POS_XI = { 甲: '艮', 乙: '乾', 丙: '坤', 丁: '离', 戊: '巽', 己: '艮', 庚: '乾', 辛: '坤', 壬: '离', 癸: '巽' };
|
|
5857
|
+
const POS_CAI = { 甲: '艮', 乙: '艮', 丙: '坤', 丁: '坤', 戊: '坎', 己: '坎', 庚: '震', 辛: '震', 壬: '离', 癸: '离' };
|
|
5858
|
+
const POS_FU = { 甲: '坎', 乙: '坤', 丙: '乾', 丁: '巽', 戊: '艮', 己: '坎', 庚: '坤', 辛: '乾', 壬: '巽', 癸: '艮' };
|
|
5859
|
+
const POS_YANG_GUI = { 甲: '坤', 乙: '坤', 丙: '兑', 丁: '乾', 戊: '艮', 己: '坎', 庚: '离', 辛: '艮', 壬: '震', 癸: '巽' };
|
|
5860
|
+
const POS_YIN_GUI = { 甲: '艮', 乙: '坎', 丙: '乾', 丁: '兑', 戊: '坤', 己: '坤', 庚: '艮', 辛: '离', 壬: '巽', 癸: '震' };
|
|
5861
|
+
const posOf = (map, stem) => (map[stem] ? { gua: map[stem], dir: DIR_OF[map[stem]] } : null);
|
|
5862
|
+
|
|
5863
|
+
const TAI_SHEN = {
|
|
5864
|
+
甲子: '占门碓 外东南', 乙丑: '碓磨厕 外东南', 丙寅: '厨灶炉 外正南', 丁卯: '仓库门 外正南', 戊辰: '房床栖 外正南',
|
|
5865
|
+
己巳: '占门床 外正南', 庚午: '占碓磨 外正南', 辛未: '厨灶厕 外西南', 壬申: '仓库炉 外西南', 癸酉: '房床门 外西南',
|
|
5866
|
+
甲戌: '占门栖 外西南', 乙亥: '碓磨床 外西南', 丙子: '厨灶碓 外西南', 丁丑: '仓库厕 外正西', 戊寅: '房床炉 外正西',
|
|
5867
|
+
己卯: '占大门 外正西', 庚辰: '碓磨栖 外正西', 辛巳: '厨灶床 外正西', 壬午: '仓库碓 外西北', 癸未: '房床厕 外西北',
|
|
5868
|
+
甲申: '占门炉 外西北', 乙酉: '碓磨门 外西北', 丙戌: '厨灶栖 外西北', 丁亥: '仓库床 外西北', 戊子: '房床碓 外正北',
|
|
5869
|
+
己丑: '占门厕 外正北', 庚寅: '碓磨炉 外正北', 辛卯: '厨灶门 外正北', 壬辰: '仓库栖 外正北', 癸巳: '占房床 房内北',
|
|
5870
|
+
甲午: '占门碓 房内北', 乙未: '碓磨厕 房内北', 丙申: '厨灶炉 房内北', 丁酉: '仓库门 房内北', 戊戌: '房床栖 房内中',
|
|
5871
|
+
己亥: '占门床 房内中', 庚子: '占碓磨 房内南', 辛丑: '厨灶厕 房内南', 壬寅: '仓库炉 房内南', 癸卯: '房床门 房内西',
|
|
5872
|
+
甲辰: '占门栖 房内东', 乙巳: '碓磨床 房内东', 丙午: '厨灶碓 房内东', 丁未: '仓库厕 房内东', 戊申: '房床炉 房内中',
|
|
5873
|
+
己酉: '占大门 外东北', 庚戌: '碓磨栖 外东北', 辛亥: '厨灶床 外东北', 壬子: '仓库碓 外东北', 癸丑: '房床厕 外东北',
|
|
5874
|
+
甲寅: '占门炉 外东北', 乙卯: '碓磨门 外正东', 丙辰: '厨灶栖 外正东', 丁巳: '仓库床 外正东', 戊午: '房床碓 外正东',
|
|
5875
|
+
己未: '占门厕 外正东', 庚申: '碓磨炉 外东南', 辛酉: '厨灶门 外东南', 壬戌: '仓库栖 外东南', 癸亥: '占房床 外东南',
|
|
5876
|
+
};
|
|
5877
|
+
|
|
5878
|
+
const LIUHE = { 子: '丑', 丑: '子', 寅: '亥', 亥: '寅', 卯: '戌', 戌: '卯', 辰: '酉', 酉: '辰', 巳: '申', 申: '巳', 午: '未', 未: '午' };
|
|
5879
|
+
const SANHE = { 申: '申子辰', 子: '申子辰', 辰: '申子辰', 亥: '亥卯未', 卯: '亥卯未', 未: '亥卯未', 寅: '寅午戌', 午: '寅午戌', 戌: '寅午戌', 巳: '巳酉丑', 酉: '巳酉丑', 丑: '巳酉丑' };
|
|
5880
|
+
|
|
5806
5881
|
function dailyHexagram(year, month, day) {
|
|
5807
5882
|
const names = Object.keys(HEX64);
|
|
5808
5883
|
if (!names.length) return null;
|
|
@@ -5858,7 +5933,41 @@ function buildAlmanac(input) {
|
|
|
5858
5933
|
return `${p.year}-${String(p.month).padStart(2, '0')}-${String(p.day).padStart(2, '0')}`;
|
|
5859
5934
|
};
|
|
5860
5935
|
|
|
5861
|
-
const
|
|
5936
|
+
const weekdayIdx = (jdn + 1) % 7;
|
|
5937
|
+
const weekday = ['日', '一', '二', '三', '四', '五', '六'][weekdayIdx];
|
|
5938
|
+
const dayGod = tianShenOf(dayBranch, BRANCHES[monthBranchIdx]);
|
|
5939
|
+
const xiu = xiuOf(dayBranch, weekdayIdx);
|
|
5940
|
+
const taiShen = TAI_SHEN[dayGz.name] || null;
|
|
5941
|
+
const hourBase = (STEMS.indexOf(dayGz.stem) % 5) * 2;
|
|
5942
|
+
const hours = BRANCHES.map((zhi, i) => {
|
|
5943
|
+
const gan = STEMS[(hourBase + i) % 10];
|
|
5944
|
+
const gz = ganzhiName(hourComposite((hourBase + i) % 10, i));
|
|
5945
|
+
const shen = tianShenOf(zhi, dayBranch);
|
|
5946
|
+
return {
|
|
5947
|
+
zhi,
|
|
5948
|
+
name: `${zhi}时`,
|
|
5949
|
+
ganZhi: gz.name,
|
|
5950
|
+
gan,
|
|
5951
|
+
shen: shen ? shen.name : null,
|
|
5952
|
+
type: shen ? shen.type : null,
|
|
5953
|
+
luck: shen ? shen.luck : null,
|
|
5954
|
+
};
|
|
5955
|
+
});
|
|
5956
|
+
const sanheGroup = SANHE[dayBranch] || '';
|
|
5957
|
+
const liuheBranch = LIUHE[dayBranch] || null;
|
|
5958
|
+
const lucky = {
|
|
5959
|
+
liuhe: liuheBranch ? SHENGXIAO[BRANCHES.indexOf(liuheBranch)] : null,
|
|
5960
|
+
sanhe: [...sanheGroup].filter((b) => b !== dayBranch).map((b) => SHENGXIAO[BRANCHES.indexOf(b)]),
|
|
5961
|
+
};
|
|
5962
|
+
const positions = {
|
|
5963
|
+
caiShen: CAI_SHEN[dayGz.stem] || null,
|
|
5964
|
+
xiShen: XI_SHEN[dayGz.stem] || null,
|
|
5965
|
+
fuShen: posOf(POS_FU, dayGz.stem),
|
|
5966
|
+
yangGui: posOf(POS_YANG_GUI, dayGz.stem),
|
|
5967
|
+
yinGui: posOf(POS_YIN_GUI, dayGz.stem),
|
|
5968
|
+
xiShenFull: posOf(POS_XI, dayGz.stem),
|
|
5969
|
+
caiShenFull: posOf(POS_CAI, dayGz.stem),
|
|
5970
|
+
};
|
|
5862
5971
|
const lunarText = `农历${springGz.name}年${lunarMonthText(lunar.month, lunar.isLeap)}${dayText(lunar.day)}`;
|
|
5863
5972
|
const boundaryNote = yearGz.name !== springGz.name
|
|
5864
5973
|
? `年界:本条按立春界作${yearGz.name}年·属${SHENGXIAO[BRANCHES.indexOf(yearGz.branch)]}(命理排盘用);春节界为${springGz.name}年·属${SHENGXIAO[BRANCHES.indexOf(springGz.branch)]},两种都对,取用场合不同`
|
|
@@ -5870,7 +5979,7 @@ function buildAlmanac(input) {
|
|
|
5870
5979
|
date: `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
|
|
5871
5980
|
weekday: `星期${weekday}`,
|
|
5872
5981
|
...(boundaryNote ? { boundaryNote } : {}),
|
|
5873
|
-
scope: '
|
|
5982
|
+
scope: '通行口径:宜忌按建除十二神简表;已收录值日十二神(黄道/黑道)、时辰吉凶、二十八宿、胎神、吉神方位、纳音、六合三合吉配;逐日全量吉神凶煞与彭祖百忌未收录',
|
|
5874
5983
|
},
|
|
5875
5984
|
lunar: {
|
|
5876
5985
|
year: springYear,
|
|
@@ -5891,7 +6000,13 @@ function buildAlmanac(input) {
|
|
|
5891
6000
|
prev: prevTerm ? { name: termName(prevTerm), date: fmtJdDate(prevTerm.jd) } : null,
|
|
5892
6001
|
next: nextTerm ? { name: termName(nextTerm), date: fmtJdDate(nextTerm.jd) } : null,
|
|
5893
6002
|
},
|
|
5894
|
-
positions
|
|
6003
|
+
positions,
|
|
6004
|
+
dayGod,
|
|
6005
|
+
xiu,
|
|
6006
|
+
taiShen,
|
|
6007
|
+
nayin: { day: nayinOf(dayGanzhiIndex(jdn)) },
|
|
6008
|
+
lucky,
|
|
6009
|
+
hours,
|
|
5895
6010
|
zhiXing,
|
|
5896
6011
|
yi: ZHIXING_YI[zhiXing].slice(),
|
|
5897
6012
|
ji: ZHIXING_JI[zhiXing].slice(),
|
|
@@ -5904,6 +6019,7 @@ function buildAlmanac(input) {
|
|
|
5904
6019
|
sources: [
|
|
5905
6020
|
'农历与节气:本地天文历法(定朔 + 节气黄经)',
|
|
5906
6021
|
'建除十二神与冲煞:传统通行口径',
|
|
6022
|
+
'值日/时家十二神(青龙…勾陈)、二十八宿、胎神、吉神方位:通行表',
|
|
5907
6023
|
'宜忌:建除十二神通行简表(非逐日全量黄历)',
|
|
5908
6024
|
'每日一卦:按公历日期确定性取卦(同日同卦)',
|
|
5909
6025
|
],
|
|
@@ -5918,7 +6034,14 @@ function monthComposite(stemIdx, branchIdx) {
|
|
|
5918
6034
|
return 0;
|
|
5919
6035
|
}
|
|
5920
6036
|
|
|
5921
|
-
|
|
6037
|
+
function hourComposite(stemIdx, branchIdx) {
|
|
6038
|
+
for (let i = 0; i < 60; i++) {
|
|
6039
|
+
if (i % 10 === stemIdx && i % 12 === branchIdx) return i;
|
|
6040
|
+
}
|
|
6041
|
+
return 0;
|
|
6042
|
+
}
|
|
6043
|
+
|
|
6044
|
+
return { ZHIXING, ZHIXING_YI, ZHIXING_JI, SHENGXIAO, hourToBranch, zhixingOf, lunarMonthText, TIAN_SHEN, TIAN_SHEN_TYPE, tianShenOf, MANSIONS, xiuOf, dailyHexagram, buildAlmanac };
|
|
5922
6045
|
})();
|
|
5923
6046
|
|
|
5924
6047
|
__mods.star = (function () {
|
|
@@ -6304,26 +6427,52 @@ const { buildAlmanac, SHENGXIAO } = __mods.almanac;
|
|
|
6304
6427
|
const TASKS = {
|
|
6305
6428
|
嫁娶: { yi: ['嫁娶', '结亲', '订盟', '纳采'], related: ['会亲友', '裁衣'], category: 'marriage' },
|
|
6306
6429
|
订婚: { yi: ['订盟', '纳采'], related: ['嫁娶', '会亲友'], category: 'marriage' },
|
|
6430
|
+
领证: { yi: ['嫁娶', '纳采'], related: ['订盟', '会亲友'], category: 'marriage' },
|
|
6431
|
+
提亲: { yi: ['纳采', '订盟'], related: ['会亲友'], category: 'marriage' },
|
|
6432
|
+
收送聘金: { yi: ['纳采', '订盟'], related: ['嫁娶'], category: 'marriage' },
|
|
6433
|
+
满月酒: { yi: ['祭祀', '祈福'], related: ['会亲友'], category: 'celebration' },
|
|
6307
6434
|
开业: { yi: ['开市', '立券', '交易'], related: ['纳财', '挂匾'], category: 'business' },
|
|
6435
|
+
交易: { yi: ['交易', '立券'], related: ['开市', '纳财'], category: 'business' },
|
|
6436
|
+
投资: { yi: ['纳财', '交易'], related: ['立券'], category: 'business' },
|
|
6437
|
+
签订合同: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
6438
|
+
签约: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
6439
|
+
纳财: { yi: ['纳财', '收账'], related: ['开市', '立券'], category: 'contract' },
|
|
6308
6440
|
入宅: { yi: ['入宅', '移徙'], related: ['安床', '修造', '扫舍'], category: 'move' },
|
|
6309
6441
|
搬家: { yi: ['移徙', '入宅'], related: ['安床', '修造'], category: 'move' },
|
|
6442
|
+
搬家入宅: { yi: ['入宅', '移徙'], related: ['安床', '扫舍'], category: 'move' },
|
|
6310
6443
|
动土: { yi: ['动土', '修造'], related: ['竖柱', '上梁'], category: 'construction' },
|
|
6311
6444
|
装修: { yi: ['修造', '修饰垣墙'], related: ['动土'], category: 'construction' },
|
|
6445
|
+
装修建造: { yi: ['修造', '动土'], related: ['竖柱', '上梁'], category: 'construction' },
|
|
6446
|
+
试车买车: { yi: ['交易', '纳财'], related: ['出行'], category: 'purchase' },
|
|
6312
6447
|
安葬: { yi: ['安葬', '破土'], related: ['立碑', '埋穴'], category: 'burial' },
|
|
6313
6448
|
出行: { yi: ['出行'], related: ['上任', '赴任'], category: 'travel' },
|
|
6449
|
+
旅行: { yi: ['出行'], related: ['上任', '赴任'], category: 'travel' },
|
|
6450
|
+
赴任: { yi: ['上任', '赴任'], related: ['出行'], category: 'travel' },
|
|
6451
|
+
访亲友: { yi: ['会亲友'], related: ['出行'], category: 'visit' },
|
|
6452
|
+
入学: { yi: ['入学'], related: ['开市', '修造'], category: 'study' },
|
|
6314
6453
|
祭祀: { yi: ['祭祀'], related: ['祈福', '求嗣'], category: 'worship' },
|
|
6315
|
-
签约: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
6316
6454
|
求医: { yi: ['求医', '疗病'], related: ['针灸'], category: 'medical' },
|
|
6317
|
-
|
|
6455
|
+
};
|
|
6456
|
+
|
|
6457
|
+
const TASK_GROUPS = {
|
|
6458
|
+
常用: ['嫁娶', '搬家入宅', '出行', '开业', '签订合同', '祭祀'],
|
|
6459
|
+
婚嫁: ['嫁娶', '订婚', '领证', '提亲', '收送聘金', '满月酒'],
|
|
6460
|
+
生活: ['搬家', '入宅', '旅行', '访亲友', '入学', '求医', '祭祀'],
|
|
6461
|
+
建造: ['动土', '装修', '装修建造', '安葬', '试车买车'],
|
|
6462
|
+
工商: ['开业', '交易', '投资', '签订合同', '签约', '纳财', '赴任'],
|
|
6318
6463
|
};
|
|
6319
6464
|
|
|
6320
6465
|
const ZHIXING_FAVOR = {
|
|
6321
6466
|
marriage: ['满', '定', '成', '开'],
|
|
6467
|
+
celebration: ['满', '成', '开', '平'],
|
|
6322
6468
|
business: ['开', '成', '满', '收'],
|
|
6323
6469
|
move: ['定', '成', '开', '除'],
|
|
6324
6470
|
construction: ['建', '除', '成', '开'],
|
|
6471
|
+
purchase: ['成', '开', '满'],
|
|
6325
6472
|
burial: ['除', '定', '闭', '破'],
|
|
6326
6473
|
travel: ['建', '成', '开', '除'],
|
|
6474
|
+
visit: ['满', '平', '定', '成'],
|
|
6475
|
+
study: ['成', '开', '建'],
|
|
6327
6476
|
worship: ['除', '满', '平', '定', '执', '成', '开'],
|
|
6328
6477
|
contract: ['定', '成', '收', '开'],
|
|
6329
6478
|
medical: ['除', '开'],
|
|
@@ -6417,7 +6566,133 @@ function buildZeri(input) {
|
|
|
6417
6566
|
};
|
|
6418
6567
|
}
|
|
6419
6568
|
|
|
6420
|
-
return { TASKS, buildZeri };
|
|
6569
|
+
return { TASKS, TASK_GROUPS, buildZeri };
|
|
6570
|
+
})();
|
|
6571
|
+
|
|
6572
|
+
__mods.convert = (function () {
|
|
6573
|
+
const { solarToLunar } = __mods.lunar;
|
|
6574
|
+
const { fromJDN, toJDN } = __mods.calendar;
|
|
6575
|
+
const { buildAlmanac } = __mods.almanac;
|
|
6576
|
+
const { assertCivil, daysInMonth } = __mods.validate;
|
|
6577
|
+
|
|
6578
|
+
const WEEK = ['日', '一', '二', '三', '四', '五', '六'];
|
|
6579
|
+
const MONTH_TEXT = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊'];
|
|
6580
|
+
const DAY_TENS = ['初', '十', '廿'];
|
|
6581
|
+
const DAY_UNITS = ['十', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
|
|
6582
|
+
|
|
6583
|
+
function dayText(day) {
|
|
6584
|
+
if (day === 10) return '初十';
|
|
6585
|
+
if (day === 20) return '二十';
|
|
6586
|
+
if (day === 30) return '三十';
|
|
6587
|
+
return `${DAY_TENS[Math.floor(day / 10)]}${DAY_UNITS[day % 10]}`;
|
|
6588
|
+
}
|
|
6589
|
+
|
|
6590
|
+
function lunarText(year, month, day, isLeap) {
|
|
6591
|
+
return `农历${year}年${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月${dayText(day)}`;
|
|
6592
|
+
}
|
|
6593
|
+
|
|
6594
|
+
function lunarNewYearJdn(lunarYear) {
|
|
6595
|
+
const from = toJDN(lunarYear, 1, 20);
|
|
6596
|
+
const to = toJDN(lunarYear, 2, 25);
|
|
6597
|
+
for (let jdn = from; jdn <= to; jdn++) {
|
|
6598
|
+
const p = fromJDN(jdn);
|
|
6599
|
+
const l = solarToLunar(p.year, p.month, p.day);
|
|
6600
|
+
if (l.lunarYear === lunarYear && l.month === 1 && l.day === 1) return jdn;
|
|
6601
|
+
}
|
|
6602
|
+
return null;
|
|
6603
|
+
}
|
|
6604
|
+
|
|
6605
|
+
function lunarMonths(lunarYear) {
|
|
6606
|
+
const first = lunarNewYearJdn(lunarYear);
|
|
6607
|
+
if (first == null) return [];
|
|
6608
|
+
const out = [];
|
|
6609
|
+
let cur = first;
|
|
6610
|
+
for (let i = 0; i < 14; i++) {
|
|
6611
|
+
const p = fromJDN(cur);
|
|
6612
|
+
const l = solarToLunar(p.year, p.month, p.day);
|
|
6613
|
+
if (i > 0 && l.month === 1 && !l.isLeap) break;
|
|
6614
|
+
let next = null;
|
|
6615
|
+
for (let k = 29; k <= 31; k++) {
|
|
6616
|
+
const d = fromJDN(cur + k);
|
|
6617
|
+
const l2 = solarToLunar(d.year, d.month, d.day);
|
|
6618
|
+
if (l2.day === 1) { next = cur + k; break; }
|
|
6619
|
+
}
|
|
6620
|
+
if (next == null) break;
|
|
6621
|
+
out.push({ month: l.month, isLeap: l.isLeap, startJdn: cur, length: next - cur });
|
|
6622
|
+
cur = next;
|
|
6623
|
+
}
|
|
6624
|
+
return out;
|
|
6625
|
+
}
|
|
6626
|
+
|
|
6627
|
+
function buildConvert(input) {
|
|
6628
|
+
const mode = input.mode === 'lunar2solar' ? 'lunar2solar' : 'solar2lunar';
|
|
6629
|
+
let solar;
|
|
6630
|
+
let lunar;
|
|
6631
|
+
let note = null;
|
|
6632
|
+
if (mode === 'solar2lunar') {
|
|
6633
|
+
solar = { year: input.year, month: input.month, day: input.day };
|
|
6634
|
+
assertCivil(solar, '公农历转换');
|
|
6635
|
+
if (solar.day > daysInMonth(solar.year, solar.month)) {
|
|
6636
|
+
throw new Error(`非法日期:${solar.year} 年 ${solar.month} 月没有 ${solar.day} 日`);
|
|
6637
|
+
}
|
|
6638
|
+
lunar = solarToLunar(solar.year, solar.month, solar.day);
|
|
6639
|
+
} else {
|
|
6640
|
+
const y = Number(input.lunarYear);
|
|
6641
|
+
const m = Number(input.lunarMonth);
|
|
6642
|
+
const d = Number(input.lunarDay);
|
|
6643
|
+
if (![y, m, d].every(Number.isInteger)) throw new Error('农历转换需要 lunarYear / lunarMonth / lunarDay');
|
|
6644
|
+
if (m < 1 || m > 12) throw new Error('农历月份须在 1–12');
|
|
6645
|
+
const months = lunarMonths(y);
|
|
6646
|
+
if (!months.length) throw new Error(`农历 ${y} 年超出本地历法覆盖范围(1900–2100)`);
|
|
6647
|
+
const isLeap = input.isLeapMonth === true;
|
|
6648
|
+
const hit = months.find((x) => x.month === m && x.isLeap === isLeap);
|
|
6649
|
+
if (!hit) {
|
|
6650
|
+
const leapMonths = months.filter((x) => x.isLeap).map((x) => `闰${MONTH_TEXT[x.month - 1]}月`);
|
|
6651
|
+
throw new Error(`农历 ${y} 年没有${leapMonths.length ? `该月(该年闰月为 ${leapMonths.join('、')})` : '闰月'}:${isLeap ? '请确认闰月标记' : '请确认月份'}`);
|
|
6652
|
+
}
|
|
6653
|
+
if (d < 1 || d > hit.length) throw new Error(`农历 ${y} 年${isLeap ? '闰' : ''}${MONTH_TEXT[m - 1]}月只有 ${hit.length} 天,没有 ${d} 日`);
|
|
6654
|
+
const p = fromJDN(hit.startJdn + d - 1);
|
|
6655
|
+
solar = { year: p.year, month: p.month, day: p.day };
|
|
6656
|
+
const check = solarToLunar(p.year, p.month, p.day);
|
|
6657
|
+
if (check.month !== m || check.day !== d || check.isLeap !== isLeap) {
|
|
6658
|
+
note = '反查结果与目标农历日不完全一致,已按本地历法实际月首回推';
|
|
6659
|
+
}
|
|
6660
|
+
lunar = check;
|
|
6661
|
+
}
|
|
6662
|
+
|
|
6663
|
+
const a = buildAlmanac(solar);
|
|
6664
|
+
const jdn = toJDN(solar.year, solar.month, solar.day);
|
|
6665
|
+
const solarText = `${solar.year}-${String(solar.month).padStart(2, '0')}-${String(solar.day).padStart(2, '0')}`;
|
|
6666
|
+
return {
|
|
6667
|
+
system: 'convert',
|
|
6668
|
+
meta: {
|
|
6669
|
+
mode,
|
|
6670
|
+
solarDate: solarText,
|
|
6671
|
+
weekday: `星期${WEEK[(jdn + 1) % 7]}`,
|
|
6672
|
+
...(note ? { note } : {}),
|
|
6673
|
+
scope: '公农历互转按本地定朔历(1900–2100);农历闰月须显式指定,不自动猜同名月',
|
|
6674
|
+
},
|
|
6675
|
+
solar: { year: solar.year, month: solar.month, day: solar.day, text: solarText },
|
|
6676
|
+
lunar: {
|
|
6677
|
+
year: lunar.lunarYear,
|
|
6678
|
+
month: lunar.month,
|
|
6679
|
+
day: lunar.day,
|
|
6680
|
+
isLeap: lunar.isLeap,
|
|
6681
|
+
text: lunarText(lunar.lunarYear, lunar.month, lunar.day, lunar.isLeap),
|
|
6682
|
+
},
|
|
6683
|
+
ganzhi: {
|
|
6684
|
+
year: a.ganzhi.year,
|
|
6685
|
+
month: a.ganzhi.month,
|
|
6686
|
+
day: a.ganzhi.day,
|
|
6687
|
+
shengXiao: a.ganzhi.shengXiao,
|
|
6688
|
+
springYear: a.ganzhi.springYear,
|
|
6689
|
+
},
|
|
6690
|
+
sources: ['农历:本地定朔 + 节气黄经历法(engine/lunar.js)', '干支与生肖:与黄历同口径(年按立春界,另列春节界)'],
|
|
6691
|
+
disclaimer: '历法换算为确定性计算;民俗历法各版本在极少数日期(交节当日、闰月边界)存在日界差异,已注明口径。',
|
|
6692
|
+
};
|
|
6693
|
+
}
|
|
6694
|
+
|
|
6695
|
+
return { buildConvert };
|
|
6421
6696
|
})();
|
|
6422
6697
|
|
|
6423
6698
|
__mods['interpret-plain'] = (function () {
|
|
@@ -8590,6 +8865,7 @@ const { buildChenggu } = __mods.chenggu;
|
|
|
8590
8865
|
const { buildXiaoliuren } = __mods.xiaoliuren;
|
|
8591
8866
|
const { buildStar } = __mods.star;
|
|
8592
8867
|
const { buildNumerology } = __mods.numerology;
|
|
8868
|
+
const { buildConvert } = __mods.convert;
|
|
8593
8869
|
const { buildTrend } = __mods.trend;
|
|
8594
8870
|
const { buildFengshui } = __mods.fengshui;
|
|
8595
8871
|
const { buildName } = __mods.name;
|
|
@@ -9144,6 +9420,26 @@ function computeRaw(args = {}) {
|
|
|
9144
9420
|
const result = buildChenggu({ year: dt.year, month: dt.month, day: dt.day, hour, minute: hasTime ? dt.minute : 0 });
|
|
9145
9421
|
return { ...result, summary: chengguText(result) };
|
|
9146
9422
|
}
|
|
9423
|
+
if (system === 'convert') {
|
|
9424
|
+
const mode = args.mode === 'lunar2solar' ? 'lunar2solar' : 'solar2lunar';
|
|
9425
|
+
let result;
|
|
9426
|
+
if (mode === 'lunar2solar') {
|
|
9427
|
+
if (args.lunarYear == null || args.lunarMonth == null || args.lunarDay == null) {
|
|
9428
|
+
throw fail('E_INPUT', '农历转公历需要 lunarYear / lunarMonth / lunarDay(闰月另加 isLeapMonth: true)');
|
|
9429
|
+
}
|
|
9430
|
+
result = buildConvert({
|
|
9431
|
+
mode,
|
|
9432
|
+
lunarYear: Number(args.lunarYear),
|
|
9433
|
+
lunarMonth: Number(args.lunarMonth),
|
|
9434
|
+
lunarDay: Number(args.lunarDay),
|
|
9435
|
+
isLeapMonth: args.isLeapMonth === true,
|
|
9436
|
+
});
|
|
9437
|
+
} else {
|
|
9438
|
+
const dt = parseDateTime(args.datetime);
|
|
9439
|
+
result = buildConvert({ mode, year: dt.year, month: dt.month, day: dt.day });
|
|
9440
|
+
}
|
|
9441
|
+
return { ...result, summary: convertText(result) };
|
|
9442
|
+
}
|
|
9147
9443
|
if (system === 'xiaoliuren') {
|
|
9148
9444
|
const dt = args.datetime ? parseDateTime(args.datetime) : null;
|
|
9149
9445
|
const result = buildXiaoliuren({
|
|
@@ -9227,21 +9523,34 @@ function computeRaw(args = {}) {
|
|
|
9227
9523
|
return { ...result, summary: nameText(result) };
|
|
9228
9524
|
}
|
|
9229
9525
|
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
|
|
9526
|
+
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
9527
|
}
|
|
9232
|
-
throw fail('E_SYSTEM', `未知体系「${system}」,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name
|
|
9528
|
+
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
9529
|
}
|
|
9234
9530
|
|
|
9235
9531
|
function almanacText(r) {
|
|
9236
9532
|
const g = r.ganzhi;
|
|
9237
9533
|
const jq = r.jieQi && r.jieQi.next ? ` 下一节:${r.jieQi.next.name} ${r.jieQi.next.date}` : '';
|
|
9534
|
+
const god = r.dayGod ? `值日:${r.dayGod.name}(${r.dayGod.type}·${r.dayGod.luck})` : '';
|
|
9535
|
+
const xiu = r.xiu ? `二十八宿:${r.xiu.name}宿(${r.xiu.luck}·${r.xiu.zheng}·${r.xiu.animal})` : '';
|
|
9536
|
+
const tai = r.taiShen ? `胎神:${r.taiShen}` : '';
|
|
9537
|
+
const pos = r.positions
|
|
9538
|
+
? `吉神方位:喜神${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 : '—'}`
|
|
9539
|
+
: '';
|
|
9540
|
+
const lucky = r.lucky ? `吉配生肖:六合${r.lucky.liuhe || '—'} 三合${(r.lucky.sanhe || []).join('、') || '—'}` : '';
|
|
9541
|
+
const nayin = r.nayin && r.nayin.day ? `日柱纳音:${r.nayin.day.name}` : '';
|
|
9542
|
+
const hours = (r.hours || []).map((h) => `${h.zhi}${h.ganZhi.slice(0, 1)}·${h.shen}${h.luck === '吉' ? '吉' : '凶'}`).join(' ');
|
|
9238
9543
|
return [
|
|
9239
9544
|
`【黄历】${r.meta.date} ${r.meta.weekday} ${r.lunar.text}`,
|
|
9240
9545
|
`干支:${g.year}年 ${g.month}月 ${g.day}日 属${g.shengXiao}`,
|
|
9241
9546
|
...(r.meta.boundaryNote ? [` ${r.meta.boundaryNote}`] : []),
|
|
9242
|
-
`建除:${r.zhiXing}日 冲:${r.chong.text}${r.chong.sha ? `(${r.chong.sha})` : ''}
|
|
9547
|
+
`建除:${r.zhiXing}日 冲:${r.chong.text}${r.chong.sha ? `(${r.chong.sha})` : ''} ${god}`,
|
|
9548
|
+
[xiu, nayin, tai].filter(Boolean).join(' '),
|
|
9243
9549
|
`宜:${r.yi.join('、')}`,
|
|
9244
9550
|
`忌:${r.ji.join('、')}`,
|
|
9551
|
+
pos,
|
|
9552
|
+
lucky,
|
|
9553
|
+
hours ? `时辰吉凶:${hours}` : '',
|
|
9245
9554
|
`节气:上一节 ${r.jieQi.prev ? `${r.jieQi.prev.name} ${r.jieQi.prev.date}` : '—'}${jq}`,
|
|
9246
9555
|
r.dailyHexagram ? `每日一卦:${r.dailyHexagram.name} ${r.dailyHexagram.meaning || ''}` : '',
|
|
9247
9556
|
`口径:${r.meta.scope}`,
|
|
@@ -9297,6 +9606,17 @@ function starText(r) {
|
|
|
9297
9606
|
].join('\n');
|
|
9298
9607
|
}
|
|
9299
9608
|
|
|
9609
|
+
function convertText(r) {
|
|
9610
|
+
const g = r.ganzhi;
|
|
9611
|
+
const dir = r.meta.mode === 'lunar2solar' ? '农历 → 公历' : '公历 → 农历';
|
|
9612
|
+
return [
|
|
9613
|
+
`【公农历转换·${dir}】${r.lunar.text} ⇄ ${r.solar.text} ${r.meta.weekday}`,
|
|
9614
|
+
`干支:${g.year}年 ${g.month}月 ${g.day}日 属${g.shengXiao}${g.springYear && g.springYear !== g.year ? `(春节界为${g.springYear}年)` : ''}`,
|
|
9615
|
+
...(r.meta.note ? [`注:${r.meta.note}`] : []),
|
|
9616
|
+
`口径:${r.meta.scope}`,
|
|
9617
|
+
].join('\n');
|
|
9618
|
+
}
|
|
9619
|
+
|
|
9300
9620
|
function numerologyText(r) {
|
|
9301
9621
|
return [
|
|
9302
9622
|
`【生命数字】${r.meta.date}(西方数字学,与八字/紫微不可互证)`,
|
|
@@ -9391,7 +9711,7 @@ function renderText(result) {
|
|
|
9391
9711
|
return parts.filter(Boolean).join('\n\n');
|
|
9392
9712
|
}
|
|
9393
9713
|
|
|
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 };
|
|
9714
|
+
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
9715
|
})();
|
|
9396
9716
|
|
|
9397
9717
|
const Engine = __mods.index;
|
|
@@ -9922,6 +10242,38 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
9922
10242
|
@media (max-width:640px){.mp-cg-w{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
|
9923
10243
|
.mp-quick-h{font-size:13px;color:var(--lu);margin-bottom:6px;font-family:system-ui,sans-serif}
|
|
9924
10244
|
.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)}
|
|
10245
|
+
.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}
|
|
10246
|
+
.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}
|
|
10247
|
+
.mp-al-h b{font-size:18px;color:var(--ink);font-weight:700;font-variant-numeric:tabular-nums}
|
|
10248
|
+
.mp-al-h i{font-style:normal;font-size:12px;color:var(--muted)}
|
|
10249
|
+
.mp-al-gz{font-size:12.5px;color:var(--ink2);margin-bottom:9px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
10250
|
+
.mp-al-badge{font-size:11px;border:1px solid var(--line);border-radius:999px;padding:1px 8px}
|
|
10251
|
+
.mp-al-badge.good{color:var(--lu);border-color:var(--lu)}
|
|
10252
|
+
.mp-al-badge.bad{color:var(--ji);border-color:var(--ji)}
|
|
10253
|
+
.mp-al-yiji{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:6px 0 9px}
|
|
10254
|
+
.mp-al-col em,.mp-al-row>em{font-style:normal;font-size:10.5px;color:var(--muted);display:block;margin-bottom:4px}
|
|
10255
|
+
.mp-al-chips{display:flex;flex-wrap:wrap;gap:4px}
|
|
10256
|
+
.mp-al-chip{font-size:11.5px;padding:1px 7px;border:1px solid var(--line);border-radius:999px;color:var(--ink2);white-space:nowrap}
|
|
10257
|
+
.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}
|
|
10258
|
+
.mp-al-cell{background:var(--card);padding:6px 8px;min-width:0}
|
|
10259
|
+
.mp-al-cell em{display:block;font-style:normal;font-size:10.5px;color:var(--muted);margin-bottom:2px}
|
|
10260
|
+
.mp-al-cell b{font-size:12.5px;color:var(--ink);font-weight:600;line-height:1.45;display:block}
|
|
10261
|
+
.mp-al-row{margin:9px 0}
|
|
10262
|
+
.mp-al-hours{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:5px}
|
|
10263
|
+
.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)}
|
|
10264
|
+
.mp-al-hour i{font-style:normal;font-weight:600;color:var(--ink)}
|
|
10265
|
+
.mp-al-hour em{font-style:normal;color:var(--muted)}
|
|
10266
|
+
.mp-al-hour b{font-weight:500}
|
|
10267
|
+
.mp-al-hour u{text-decoration:none;margin-left:auto;font-size:10.5px}
|
|
10268
|
+
.mp-al-hour.good{border-color:var(--lu);color:var(--lu)}
|
|
10269
|
+
.mp-al-hour.good i{color:var(--lu)}
|
|
10270
|
+
.mp-al-hour.bad{border-color:var(--hair)}
|
|
10271
|
+
.mp-al-hour.bad u{color:var(--ji)}
|
|
10272
|
+
.mp-al-hex{margin-top:8px;font-size:12px;color:var(--ink2)}
|
|
10273
|
+
.mp-al-hex b{color:var(--quan)}
|
|
10274
|
+
.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)}
|
|
10275
|
+
@media print{.mp-al{break-inside:avoid}}
|
|
10276
|
+
@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
10277
|
.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
10278
|
|
|
9927
10279
|
@media (max-width:640px){
|
|
@@ -11183,11 +11535,43 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
|
|
|
11183
11535
|
return (html || '') + pp.interpretHTML(it, opt);
|
|
11184
11536
|
};
|
|
11185
11537
|
|
|
11538
|
+
pp.almanacHTML = function (r) {
|
|
11539
|
+
if (!r || !r.meta) return pp.quickHTML(r);
|
|
11540
|
+
const g = r.ganzhi || {};
|
|
11541
|
+
const god = r.dayGod || null;
|
|
11542
|
+
const chips = (list, cls) => (list || []).map((x) => `<span class="mp-al-chip${cls ? ` ${cls}` : ''}">${esc(x)}</span>`).join('');
|
|
11543
|
+
const cell = (k, v) => (v ? `<div class="mp-al-cell"><em>${esc(k)}</em><b>${esc(v)}</b></div>` : '');
|
|
11544
|
+
const xiu = r.xiu ? `${r.xiu.name}宿(${r.xiu.luck}·${r.xiu.zheng}·${r.xiu.animal})` : '';
|
|
11545
|
+
const nayin = r.nayin && r.nayin.day ? r.nayin.day.name : '';
|
|
11546
|
+
const chong = r.chong ? `${r.chong.text}${r.chong.sha ? ` ${r.chong.sha}` : ''}` : '';
|
|
11547
|
+
const hours = (r.hours || []).map((h) => `<span class="mp-al-hour ${h.luck === '吉' ? 'good' : 'bad'}">`
|
|
11548
|
+
+ `<i>${esc(h.zhi)}</i><em>${esc((h.ganZhi || '').slice(0, 1))}</em><b>${esc(h.shen || '')}</b>`
|
|
11549
|
+
+ `<u>${esc(h.luck || '')}</u></span>`).join('');
|
|
11550
|
+
const pos = r.positions || {};
|
|
11551
|
+
const posRow = (k, v) => (v ? `<span class="mp-al-chip">${esc(k)}·${esc(typeof v === 'string' ? v : v.dir || '')}</span>` : '');
|
|
11552
|
+
const lucky = r.lucky || {};
|
|
11553
|
+
const godBadge = god ? `<span class="mp-al-badge ${god.luck === '吉' ? 'good' : 'bad'}">${esc(god.name)}·${esc(god.type)}·${esc(god.luck)}</span>` : '';
|
|
11554
|
+
return `<section class="mp-al" aria-label="黄历">
|
|
11555
|
+
<div class="mp-al-h"><b>${esc(r.meta.date || '')}</b><i>${esc(r.meta.weekday || '')} ${esc((r.lunar || {}).text || '')}</i></div>
|
|
11556
|
+
<div class="mp-al-gz">${esc(g.year || '')}年 ${esc(g.month || '')}月 ${esc(g.day || '')}日 属${esc(g.shengXiao || '')} 建除 ${esc(r.zhiXing || '')}日 ${godBadge}</div>
|
|
11557
|
+
<div class="mp-al-yiji">
|
|
11558
|
+
<div class="mp-al-col"><em>宜</em><div class="mp-al-chips">${chips(r.yi)}</div></div>
|
|
11559
|
+
<div class="mp-al-col"><em>忌</em><div class="mp-al-chips">${chips(r.ji)}</div></div>
|
|
11560
|
+
</div>
|
|
11561
|
+
<div class="mp-al-grid">${cell('二十八宿', xiu)}${cell('日柱纳音', nayin)}${cell('胎神', r.taiShen)}${cell('冲煞', chong)}</div>
|
|
11562
|
+
<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>
|
|
11563
|
+
<div class="mp-al-row"><em>时刻吉凶</em><div class="mp-al-hours">${hours}</div></div>
|
|
11564
|
+
<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>
|
|
11565
|
+
${r.dailyHexagram ? `<div class="mp-al-hex">每日一卦:<b>${esc(r.dailyHexagram.name)}</b> ${esc(r.dailyHexagram.meaning || '')}</div>` : ''}
|
|
11566
|
+
<div class="mp-al-note">${esc((r.meta && r.meta.scope) || '')}</div>
|
|
11567
|
+
</section>`;
|
|
11568
|
+
};
|
|
11569
|
+
|
|
11186
11570
|
pp.quickHTML = function (r) {
|
|
11187
11571
|
if (!r) return '';
|
|
11188
11572
|
const LABEL = {
|
|
11189
11573
|
almanac: '黄历', zeri: '择日', chenggu: '称骨', xiaoliuren: '小六壬',
|
|
11190
|
-
star: '星座', numerology: '生命数字', trend: '人生 K 线', fengshui: '风水', name: '起名',
|
|
11574
|
+
star: '星座', numerology: '生命数字', trend: '人生 K 线', fengshui: '风水', name: '起名', convert: '公农历转换',
|
|
11191
11575
|
};
|
|
11192
11576
|
const title = LABEL[r.system] || '速查';
|
|
11193
11577
|
const text = r.summary || '';
|
|
@@ -11457,7 +11841,8 @@ const TABS = [
|
|
|
11457
11841
|
{ k: 'qimen', label: '奇门', timeLabel: '起局时刻', hint: '奇门时家转盘:用起局时刻定节气、三元与局数;换局规则决定符头与节气如何对齐。' },
|
|
11458
11842
|
{ k: 'hepan', label: '合盘', timeLabel: '你的出生时刻', hint: '合盘按「日主 + 夫妻宫 + 五行互补」看两个人的相处与互补,需要双方出生信息。' },
|
|
11459
11843
|
{ k: 'tarot', label: '塔罗', timeLabel: '', hint: '塔罗不看时间,只记录抽牌时刻与你的提问。' },
|
|
11460
|
-
{ k: 'almanac', label: '黄历', timeLabel: '', hint: '
|
|
11844
|
+
{ k: 'almanac', label: '黄历', timeLabel: '', hint: '黄历按公历日期查农历、干支、宜忌、时辰吉凶、二十八宿与吉神方位;只做本地计算。' },
|
|
11845
|
+
{ k: 'convert', label: '农历', timeLabel: '', hint: '公农历互转:公历生日可反查农历;只知道农历生日时,可转成公历再排盘。' },
|
|
11461
11846
|
{ k: 'zeri', label: '择日', timeLabel: '', hint: '择日把区间内每天的建除宜忌与事项适配打分排序,并按属相排除冲煞日。' },
|
|
11462
11847
|
{ k: 'chenggu', label: '称骨', timeLabel: '出生时刻', hint: '称骨按农历年、月、日、时的骨重求和;时辰必填。' },
|
|
11463
11848
|
{ k: 'xiaoliuren', label: '小六壬', timeLabel: '起课时刻', hint: '小六壬用农历月/日/时掐指,也可用三个随机数起课。' },
|
|
@@ -11479,7 +11864,7 @@ const TIME_KIND = {
|
|
|
11479
11864
|
ziwei: 'birth', bazi: 'birth', hepan: 'birth',
|
|
11480
11865
|
liuyao: 'cast', meihua: 'cast', daliuren: 'cast', qimen: 'cast',
|
|
11481
11866
|
tarot: 'none',
|
|
11482
|
-
almanac: 'date', zeri: 'date', star: 'date', numerology: 'date',
|
|
11867
|
+
almanac: 'date', zeri: 'date', star: 'date', numerology: 'date', convert: 'date',
|
|
11483
11868
|
chenggu: 'birth', trend: 'birth', fengshui: 'birth', name: 'birth',
|
|
11484
11869
|
xiaoliuren: 'cast',
|
|
11485
11870
|
};
|
|
@@ -11514,6 +11899,9 @@ function App() {
|
|
|
11514
11899
|
const [task, setTask] = useState('开业');
|
|
11515
11900
|
const [days, setDays] = useState('30');
|
|
11516
11901
|
const [shengXiao, setShengXiao] = useState('');
|
|
11902
|
+
const [convMode, setConvMode] = useState('solar2lunar');
|
|
11903
|
+
const [lunarDate, setLunarDate] = useState('');
|
|
11904
|
+
const [leapMonth, setLeapMonth] = useState(false);
|
|
11517
11905
|
const [xlrMode, setXlrMode] = useState('time');
|
|
11518
11906
|
const [num1, setNum1] = useState(''); const [num2, setNum2] = useState(''); const [num3, setNum3] = useState('');
|
|
11519
11907
|
const [toAge, setToAge] = useState('60');
|
|
@@ -11619,6 +12007,24 @@ function App() {
|
|
|
11619
12007
|
delete args.datetime;
|
|
11620
12008
|
}
|
|
11621
12009
|
}
|
|
12010
|
+
if (k === 'convert') {
|
|
12011
|
+
args.system = 'convert';
|
|
12012
|
+
if (convMode === 'lunar2solar') {
|
|
12013
|
+
const m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(String(lunarDate).trim());
|
|
12014
|
+
if (!m) {
|
|
12015
|
+
setError('农历转公历请按「农历年-月-日」填写,例如 2026-9-17;闰月单独勾选。');
|
|
12016
|
+
return;
|
|
12017
|
+
}
|
|
12018
|
+
args.mode = 'lunar2solar';
|
|
12019
|
+
args.lunarYear = Number(m[1]);
|
|
12020
|
+
args.lunarMonth = Number(m[2]);
|
|
12021
|
+
args.lunarDay = Number(m[3]);
|
|
12022
|
+
args.isLeapMonth = leapMonth;
|
|
12023
|
+
delete args.datetime;
|
|
12024
|
+
} else {
|
|
12025
|
+
args.mode = 'solar2lunar';
|
|
12026
|
+
}
|
|
12027
|
+
}
|
|
11622
12028
|
if (k === 'tarot') args.count = Number(count);
|
|
11623
12029
|
if (k === 'hepan') {
|
|
11624
12030
|
args.chart = hpChart;
|
|
@@ -11987,8 +12393,24 @@ function App() {
|
|
|
11987
12393
|
})) : null,
|
|
11988
12394
|
tab === 'zeri' ? field('所办事项', h('select', {
|
|
11989
12395
|
className: 'mp-input', value: task, onChange: (e) => setTask(e.target.value),
|
|
11990
|
-
}, [
|
|
11991
|
-
|
|
12396
|
+
}, [
|
|
12397
|
+
['常用', ['嫁娶', '搬家入宅', '出行', '开业', '签订合同', '祭祀']],
|
|
12398
|
+
['婚嫁', ['嫁娶', '订婚', '领证', '提亲', '收送聘金', '满月酒']],
|
|
12399
|
+
['生活', ['搬家', '入宅', '旅行', '访亲友', '入学', '求医', '祭祀']],
|
|
12400
|
+
['建造', ['动土', '装修', '装修建造', '安葬', '试车买车']],
|
|
12401
|
+
['工商', ['开业', '交易', '投资', '签订合同', '签约', '纳财', '赴任']],
|
|
12402
|
+
].map(([g, items]) => h('optgroup', { key: g, label: g },
|
|
12403
|
+
items.map((t) => h('option', { key: `${g}-${t}`, value: t }, t)))))) : null,
|
|
12404
|
+
tab === 'convert' ? field('转换方向', h('div', { className: 'mp-seg' },
|
|
12405
|
+
h('button', { className: convMode === 'solar2lunar' ? 'on' : '', onClick: () => setConvMode('solar2lunar') }, '公历 → 农历'),
|
|
12406
|
+
h('button', { className: convMode === 'lunar2solar' ? 'on' : '', onClick: () => setConvMode('lunar2solar') }, '农历 → 公历'))) : null,
|
|
12407
|
+
(tab === 'convert' && convMode === 'lunar2solar') ? field('农历日期', h('input', {
|
|
12408
|
+
className: 'mp-input', value: lunarDate, placeholder: '如 2026-9-17',
|
|
12409
|
+
onChange: (e) => setLunarDate(e.target.value),
|
|
12410
|
+
})) : null,
|
|
12411
|
+
(tab === 'convert' && convMode === 'lunar2solar') ? h('label', {
|
|
12412
|
+
className: 'mp-check',
|
|
12413
|
+
}, h('input', { type: 'checkbox', checked: leapMonth, onChange: (e) => setLeapMonth(e.target.checked) }), ' 闰月') : null,
|
|
11992
12414
|
tab === 'zeri' ? field('看多少天', h('input', {
|
|
11993
12415
|
className: 'mp-input', type: 'number', min: 1, max: 60, value: days,
|
|
11994
12416
|
onChange: (e) => setDays(e.target.value),
|
|
@@ -12114,6 +12536,7 @@ function App() {
|
|
|
12114
12536
|
: result.kind === 'tarot' ? PP.tarotHTML(result.r)
|
|
12115
12537
|
: result.kind === 'liuyao' ? PP.liuyaoHTML(result.r)
|
|
12116
12538
|
: result.kind === 'chenggu' ? PP.chengguHTML(result.r)
|
|
12539
|
+
: result.kind === 'almanac' ? PP.almanacHTML(result.r)
|
|
12117
12540
|
: result.kind === 'trend' ? PP.trendHTML(result.r)
|
|
12118
12541
|
: PP.quickHTML(result.r),
|
|
12119
12542
|
result.it,
|