dsh-metaphysics 0.18.3 → 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 +25 -0
- package/README.md +13 -12
- package/client.js +565 -25
- package/engine/almanac.js +137 -3
- package/engine/chenggu.js +74 -4
- package/engine/convert.js +137 -0
- package/engine/geo.js +1 -1
- package/engine/index.js +59 -9
- 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/engine/almanac.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// 彭祖百忌、胎神等全量黄历数据未收录——输出里如实标注「未收录」,不臆造。
|
|
8
8
|
// 宜忌只按「建除十二神」通行简表给出(传统择日的第一层判据),不是逐日全量黄历。
|
|
9
9
|
import { solarToLunar } from './lunar.js';
|
|
10
|
+
import { nayinOf } from './nayin.js';
|
|
10
11
|
import {
|
|
11
12
|
toJDN, fromJDN, dayGanzhiIndex, ganzhiName, termWindow, termInstantJd, partsToJd, STEMS, BRANCHES, TERM_NAMES,
|
|
12
13
|
} from './calendar.js';
|
|
@@ -89,6 +90,89 @@ export function lunarMonthText(month, isLeap = false) {
|
|
|
89
90
|
return `${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月`;
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
/** 黄道/黑道十二神(青龙、明堂…勾陈),值日与时家共用。 */
|
|
94
|
+
export const TIAN_SHEN = ['青龙', '明堂', '天刑', '朱雀', '金匮', '天德', '白虎', '玉堂', '天牢', '玄武', '司命', '勾陈'];
|
|
95
|
+
/** 六黄道(吉)/ 六黑道(凶)。 */
|
|
96
|
+
export const TIAN_SHEN_TYPE = {
|
|
97
|
+
青龙: '黄道', 明堂: '黄道', 金匮: '黄道', 天德: '黄道', 玉堂: '黄道', 司命: '黄道',
|
|
98
|
+
天刑: '黑道', 朱雀: '黑道', 白虎: '黑道', 天牢: '黑道', 玄武: '黑道', 勾陈: '黑道',
|
|
99
|
+
};
|
|
100
|
+
/** 十二神起例:以月支(日家)或日支(时家)为锚的偏移。 */
|
|
101
|
+
const TIAN_SHEN_OFFSET = { 子: 4, 丑: 2, 寅: 0, 卯: 10, 辰: 8, 巳: 6, 午: 4, 未: 2, 申: 0, 酉: 10, 戌: 8, 亥: 6 };
|
|
102
|
+
|
|
103
|
+
/** 日家十二神:日支 + 月支偏移;时家十二神:时支 + 日支偏移。 */
|
|
104
|
+
export function tianShenOf(branch, anchorBranch) {
|
|
105
|
+
const b = BRANCHES.indexOf(branch);
|
|
106
|
+
const off = TIAN_SHEN_OFFSET[anchorBranch];
|
|
107
|
+
if (b < 0 || off == null) return null;
|
|
108
|
+
const name = TIAN_SHEN[(b + off) % 12];
|
|
109
|
+
const type = TIAN_SHEN_TYPE[name];
|
|
110
|
+
return { name, type, luck: type === '黄道' ? '吉' : '凶' };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** 二十八宿:值日宿按「日支 + 星期」轮转(四组各七宿)。 */
|
|
114
|
+
export const MANSIONS = {
|
|
115
|
+
角: { luck: '吉', zheng: '木', animal: '蛟', gong: '东' }, 亢: { luck: '凶', zheng: '金', animal: '龙', gong: '东' },
|
|
116
|
+
氐: { luck: '凶', zheng: '土', animal: '貉', gong: '东' }, 房: { luck: '吉', zheng: '日', animal: '兔', gong: '东' },
|
|
117
|
+
心: { luck: '凶', zheng: '月', animal: '狐', gong: '东' }, 尾: { luck: '吉', zheng: '火', animal: '虎', gong: '东' },
|
|
118
|
+
箕: { luck: '吉', zheng: '水', animal: '豹', gong: '东' }, 斗: { luck: '吉', zheng: '木', animal: '獬', gong: '北' },
|
|
119
|
+
牛: { luck: '凶', zheng: '金', animal: '牛', gong: '北' }, 女: { luck: '凶', zheng: '土', animal: '蝠', gong: '北' },
|
|
120
|
+
虚: { luck: '凶', zheng: '日', animal: '鼠', gong: '北' }, 危: { luck: '凶', zheng: '月', animal: '燕', gong: '北' },
|
|
121
|
+
室: { luck: '吉', zheng: '火', animal: '猪', gong: '北' }, 壁: { luck: '吉', zheng: '水', animal: '獝', gong: '北' },
|
|
122
|
+
奎: { luck: '凶', zheng: '木', animal: '狼', gong: '西' }, 娄: { luck: '吉', zheng: '金', animal: '狗', gong: '西' },
|
|
123
|
+
胃: { luck: '吉', zheng: '土', animal: '彘', gong: '西' }, 昴: { luck: '凶', zheng: '日', animal: '鸡', gong: '西' },
|
|
124
|
+
毕: { luck: '吉', zheng: '月', animal: '乌', gong: '西' }, 觜: { luck: '凶', zheng: '火', animal: '猴', gong: '西' },
|
|
125
|
+
参: { luck: '吉', zheng: '水', animal: '猿', gong: '西' }, 井: { luck: '吉', zheng: '木', animal: '犴', gong: '南' },
|
|
126
|
+
鬼: { luck: '凶', zheng: '金', animal: '羊', gong: '南' }, 柳: { luck: '凶', zheng: '土', animal: '獐', gong: '南' },
|
|
127
|
+
星: { luck: '凶', zheng: '日', animal: '马', gong: '南' }, 张: { luck: '吉', zheng: '月', animal: '鹿', gong: '南' },
|
|
128
|
+
翼: { luck: '凶', zheng: '火', animal: '蛇', gong: '南' }, 轸: { luck: '吉', zheng: '水', animal: '蚓', gong: '南' },
|
|
129
|
+
};
|
|
130
|
+
const XIU_GROUPS = {
|
|
131
|
+
A: ['虚', '毕', '翼', '箕', '奎', '鬼', '氐'],
|
|
132
|
+
B: ['房', '危', '觜', '轸', '斗', '娄', '柳'],
|
|
133
|
+
C: ['星', '心', '室', '参', '角', '牛', '胃'],
|
|
134
|
+
D: ['昴', '张', '尾', '壁', '井', '亢', '女'],
|
|
135
|
+
};
|
|
136
|
+
const XIU_GROUP_OF = { 子: 'A', 辰: 'A', 申: 'A', 丑: 'B', 巳: 'B', 酉: 'B', 寅: 'C', 午: 'C', 戌: 'C', 卯: 'D', 未: 'D', 亥: 'D' };
|
|
137
|
+
|
|
138
|
+
/** 值日宿:weekday 0=周日。 */
|
|
139
|
+
export function xiuOf(dayBranch, weekdayIndex) {
|
|
140
|
+
const g = XIU_GROUP_OF[dayBranch];
|
|
141
|
+
if (!g) return null;
|
|
142
|
+
const name = XIU_GROUPS[g][weekdayIndex];
|
|
143
|
+
const info = MANSIONS[name];
|
|
144
|
+
return info ? { name, ...info } : null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** 吉神方位(按日干;福神取通行一变,另一变注明差异)。 */
|
|
148
|
+
const DIR_OF = { 坎: '正北', 艮: '东北', 震: '正东', 巽: '东南', 离: '正南', 坤: '西南', 兑: '正西', 乾: '西北' };
|
|
149
|
+
const POS_XI = { 甲: '艮', 乙: '乾', 丙: '坤', 丁: '离', 戊: '巽', 己: '艮', 庚: '乾', 辛: '坤', 壬: '离', 癸: '巽' };
|
|
150
|
+
const POS_CAI = { 甲: '艮', 乙: '艮', 丙: '坤', 丁: '坤', 戊: '坎', 己: '坎', 庚: '震', 辛: '震', 壬: '离', 癸: '离' };
|
|
151
|
+
const POS_FU = { 甲: '坎', 乙: '坤', 丙: '乾', 丁: '巽', 戊: '艮', 己: '坎', 庚: '坤', 辛: '乾', 壬: '巽', 癸: '艮' };
|
|
152
|
+
const POS_YANG_GUI = { 甲: '坤', 乙: '坤', 丙: '兑', 丁: '乾', 戊: '艮', 己: '坎', 庚: '离', 辛: '艮', 壬: '震', 癸: '巽' };
|
|
153
|
+
const POS_YIN_GUI = { 甲: '艮', 乙: '坎', 丙: '乾', 丁: '兑', 戊: '坤', 己: '坤', 庚: '艮', 辛: '离', 壬: '巽', 癸: '震' };
|
|
154
|
+
const posOf = (map, stem) => (map[stem] ? { gua: map[stem], dir: DIR_OF[map[stem]] } : null);
|
|
155
|
+
|
|
156
|
+
/** 胎神(逐日干支,通行表)。 */
|
|
157
|
+
const TAI_SHEN = {
|
|
158
|
+
甲子: '占门碓 外东南', 乙丑: '碓磨厕 外东南', 丙寅: '厨灶炉 外正南', 丁卯: '仓库门 外正南', 戊辰: '房床栖 外正南',
|
|
159
|
+
己巳: '占门床 外正南', 庚午: '占碓磨 外正南', 辛未: '厨灶厕 外西南', 壬申: '仓库炉 外西南', 癸酉: '房床门 外西南',
|
|
160
|
+
甲戌: '占门栖 外西南', 乙亥: '碓磨床 外西南', 丙子: '厨灶碓 外西南', 丁丑: '仓库厕 外正西', 戊寅: '房床炉 外正西',
|
|
161
|
+
己卯: '占大门 外正西', 庚辰: '碓磨栖 外正西', 辛巳: '厨灶床 外正西', 壬午: '仓库碓 外西北', 癸未: '房床厕 外西北',
|
|
162
|
+
甲申: '占门炉 外西北', 乙酉: '碓磨门 外西北', 丙戌: '厨灶栖 外西北', 丁亥: '仓库床 外西北', 戊子: '房床碓 外正北',
|
|
163
|
+
己丑: '占门厕 外正北', 庚寅: '碓磨炉 外正北', 辛卯: '厨灶门 外正北', 壬辰: '仓库栖 外正北', 癸巳: '占房床 房内北',
|
|
164
|
+
甲午: '占门碓 房内北', 乙未: '碓磨厕 房内北', 丙申: '厨灶炉 房内北', 丁酉: '仓库门 房内北', 戊戌: '房床栖 房内中',
|
|
165
|
+
己亥: '占门床 房内中', 庚子: '占碓磨 房内南', 辛丑: '厨灶厕 房内南', 壬寅: '仓库炉 房内南', 癸卯: '房床门 房内西',
|
|
166
|
+
甲辰: '占门栖 房内东', 乙巳: '碓磨床 房内东', 丙午: '厨灶碓 房内东', 丁未: '仓库厕 房内东', 戊申: '房床炉 房内中',
|
|
167
|
+
己酉: '占大门 外东北', 庚戌: '碓磨栖 外东北', 辛亥: '厨灶床 外东北', 壬子: '仓库碓 外东北', 癸丑: '房床厕 外东北',
|
|
168
|
+
甲寅: '占门炉 外东北', 乙卯: '碓磨门 外正东', 丙辰: '厨灶栖 外正东', 丁巳: '仓库床 外正东', 戊午: '房床碓 外正东',
|
|
169
|
+
己未: '占门厕 外正东', 庚申: '碓磨炉 外东南', 辛酉: '厨灶门 外东南', 壬戌: '仓库栖 外东南', 癸亥: '占房床 外东南',
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/** 六合 / 三合(对日支取吉配生肖)。 */
|
|
173
|
+
const LIUHE = { 子: '丑', 丑: '子', 寅: '亥', 亥: '寅', 卯: '戌', 戌: '卯', 辰: '酉', 酉: '辰', 巳: '申', 申: '巳', 午: '未', 未: '午' };
|
|
174
|
+
const SANHE = { 申: '申子辰', 子: '申子辰', 辰: '申子辰', 亥: '亥卯未', 卯: '亥卯未', 未: '亥卯未', 寅: '寅午戌', 午: '寅午戌', 戌: '寅午戌', 巳: '巳酉丑', 酉: '巳酉丑', 丑: '巳酉丑' };
|
|
175
|
+
|
|
92
176
|
/** 每日一卦:日期哈希确定性映射到通行本 64 卦(同日同卦)。 */
|
|
93
177
|
export function dailyHexagram(year, month, day) {
|
|
94
178
|
const names = Object.keys(HEX64);
|
|
@@ -153,7 +237,42 @@ export function buildAlmanac(input) {
|
|
|
153
237
|
return `${p.year}-${String(p.month).padStart(2, '0')}-${String(p.day).padStart(2, '0')}`;
|
|
154
238
|
};
|
|
155
239
|
|
|
156
|
-
const
|
|
240
|
+
const weekdayIdx = (jdn + 1) % 7;
|
|
241
|
+
const weekday = ['日', '一', '二', '三', '四', '五', '六'][weekdayIdx];
|
|
242
|
+
// 值日十二神(黄道/黑道)、二十八宿、胎神、纳音、吉神方位、时辰吉凶
|
|
243
|
+
const dayGod = tianShenOf(dayBranch, BRANCHES[monthBranchIdx]);
|
|
244
|
+
const xiu = xiuOf(dayBranch, weekdayIdx);
|
|
245
|
+
const taiShen = TAI_SHEN[dayGz.name] || null;
|
|
246
|
+
const hourBase = (STEMS.indexOf(dayGz.stem) % 5) * 2;
|
|
247
|
+
const hours = BRANCHES.map((zhi, i) => {
|
|
248
|
+
const gan = STEMS[(hourBase + i) % 10];
|
|
249
|
+
const gz = ganzhiName(hourComposite((hourBase + i) % 10, i));
|
|
250
|
+
const shen = tianShenOf(zhi, dayBranch);
|
|
251
|
+
return {
|
|
252
|
+
zhi,
|
|
253
|
+
name: `${zhi}时`,
|
|
254
|
+
ganZhi: gz.name,
|
|
255
|
+
gan,
|
|
256
|
+
shen: shen ? shen.name : null,
|
|
257
|
+
type: shen ? shen.type : null,
|
|
258
|
+
luck: shen ? shen.luck : null,
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
const sanheGroup = SANHE[dayBranch] || '';
|
|
262
|
+
const liuheBranch = LIUHE[dayBranch] || null;
|
|
263
|
+
const lucky = {
|
|
264
|
+
liuhe: liuheBranch ? SHENGXIAO[BRANCHES.indexOf(liuheBranch)] : null,
|
|
265
|
+
sanhe: [...sanheGroup].filter((b) => b !== dayBranch).map((b) => SHENGXIAO[BRANCHES.indexOf(b)]),
|
|
266
|
+
};
|
|
267
|
+
const positions = {
|
|
268
|
+
caiShen: CAI_SHEN[dayGz.stem] || null,
|
|
269
|
+
xiShen: XI_SHEN[dayGz.stem] || null,
|
|
270
|
+
fuShen: posOf(POS_FU, dayGz.stem),
|
|
271
|
+
yangGui: posOf(POS_YANG_GUI, dayGz.stem),
|
|
272
|
+
yinGui: posOf(POS_YIN_GUI, dayGz.stem),
|
|
273
|
+
xiShenFull: posOf(POS_XI, dayGz.stem),
|
|
274
|
+
caiShenFull: posOf(POS_CAI, dayGz.stem),
|
|
275
|
+
};
|
|
157
276
|
const lunarText = `农历${springGz.name}年${lunarMonthText(lunar.month, lunar.isLeap)}${dayText(lunar.day)}`;
|
|
158
277
|
const boundaryNote = yearGz.name !== springGz.name
|
|
159
278
|
? `年界:本条按立春界作${yearGz.name}年·属${SHENGXIAO[BRANCHES.indexOf(yearGz.branch)]}(命理排盘用);春节界为${springGz.name}年·属${SHENGXIAO[BRANCHES.indexOf(springGz.branch)]},两种都对,取用场合不同`
|
|
@@ -165,7 +284,7 @@ export function buildAlmanac(input) {
|
|
|
165
284
|
date: `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
|
|
166
285
|
weekday: `星期${weekday}`,
|
|
167
286
|
...(boundaryNote ? { boundaryNote } : {}),
|
|
168
|
-
scope: '
|
|
287
|
+
scope: '通行口径:宜忌按建除十二神简表;已收录值日十二神(黄道/黑道)、时辰吉凶、二十八宿、胎神、吉神方位、纳音、六合三合吉配;逐日全量吉神凶煞与彭祖百忌未收录',
|
|
169
288
|
},
|
|
170
289
|
lunar: {
|
|
171
290
|
year: springYear,
|
|
@@ -186,7 +305,13 @@ export function buildAlmanac(input) {
|
|
|
186
305
|
prev: prevTerm ? { name: termName(prevTerm), date: fmtJdDate(prevTerm.jd) } : null,
|
|
187
306
|
next: nextTerm ? { name: termName(nextTerm), date: fmtJdDate(nextTerm.jd) } : null,
|
|
188
307
|
},
|
|
189
|
-
positions
|
|
308
|
+
positions,
|
|
309
|
+
dayGod,
|
|
310
|
+
xiu,
|
|
311
|
+
taiShen,
|
|
312
|
+
nayin: { day: nayinOf(dayGanzhiIndex(jdn)) },
|
|
313
|
+
lucky,
|
|
314
|
+
hours,
|
|
190
315
|
zhiXing,
|
|
191
316
|
yi: ZHIXING_YI[zhiXing].slice(),
|
|
192
317
|
ji: ZHIXING_JI[zhiXing].slice(),
|
|
@@ -199,6 +324,7 @@ export function buildAlmanac(input) {
|
|
|
199
324
|
sources: [
|
|
200
325
|
'农历与节气:本地天文历法(定朔 + 节气黄经)',
|
|
201
326
|
'建除十二神与冲煞:传统通行口径',
|
|
327
|
+
'值日/时家十二神(青龙…勾陈)、二十八宿、胎神、吉神方位:通行表',
|
|
202
328
|
'宜忌:建除十二神通行简表(非逐日全量黄历)',
|
|
203
329
|
'每日一卦:按公历日期确定性取卦(同日同卦)',
|
|
204
330
|
],
|
|
@@ -213,3 +339,11 @@ function monthComposite(stemIdx, branchIdx) {
|
|
|
213
339
|
}
|
|
214
340
|
return 0;
|
|
215
341
|
}
|
|
342
|
+
|
|
343
|
+
/** 由时干序与时支序求六十甲子序。 */
|
|
344
|
+
function hourComposite(stemIdx, branchIdx) {
|
|
345
|
+
for (let i = 0; i < 60; i++) {
|
|
346
|
+
if (i % 10 === stemIdx && i % 12 === branchIdx) return i;
|
|
347
|
+
}
|
|
348
|
+
return 0;
|
|
349
|
+
}
|
package/engine/chenggu.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// 袁天罡称骨:按农历年/月/日/时辰四柱骨重求和,查通行本《称骨歌》原文,附白话释义。
|
|
2
|
+
// 骨重表与歌诀均为通行本口径(各版本有异文,此处照录通行本);释义是白话自撰,不是原文。
|
|
3
3
|
import { solarToLunar } from './lunar.js';
|
|
4
4
|
import { ganzhiName, toJDN, dayGanzhiIndex } from './calendar.js';
|
|
5
5
|
import { assertCivil } from './validate.js';
|
|
@@ -58,6 +58,71 @@ export function lunarMonthText(month, isLeap = false) {
|
|
|
58
58
|
return `${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月`;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* 通行本《称骨歌》五十二首:键 = 骨重(钱),21 = 二两一钱 … 72 = 七两二钱。
|
|
63
|
+
* text 为歌诀原文照录(各版本有异文,此处取通行本,标点统一为「,;,。」);
|
|
64
|
+
* plain 为白话释义,是自撰,不是原文。
|
|
65
|
+
*/
|
|
66
|
+
export const CHENGGU_SONG = {
|
|
67
|
+
21: { text: '短命非业谓大空,平生灾难事重重;凶祸频临陷逆境,终世困苦事不成。', plain: '起点低、阻力大,凡事难一气呵成;宜守稳借力,不宜孤注一掷。' },
|
|
68
|
+
22: { text: '身寒骨冷苦伶仃,此命推来行乞人;劳劳碌碌无度日,终年打拱过平生。', plain: '早年资源薄、亲缘淡,靠勤苦与人缘翻身,最忌自弃。' },
|
|
69
|
+
23: { text: '此命推来骨格轻,求谋作事事难成;妻儿兄弟应难许,别处他乡作散人。', plain: '独自谋事难成,宜合伙或依附平台;离乡发展反有出路。' },
|
|
70
|
+
24: { text: '此命推来福禄无,门庭困苦总难荣;六亲骨肉皆无靠,流浪他乡作老翁。', plain: '六亲助力少,别指望祖业,早做打算、靠双手积累。' },
|
|
71
|
+
25: { text: '此命推来祖业微,门庭营度似稀奇;六亲骨肉如冰炭,一世勤劳自把持。', plain: '家底薄、亲缘冷,一生靠自己操持,勤俭则安。' },
|
|
72
|
+
26: { text: '平生衣禄苦中求,独自营谋事不休;离祖出门宜早计,晚来衣禄自无休。', plain: '白手起家之格:早离乡、晚渐稳,不必怕慢。' },
|
|
73
|
+
27: { text: '一生作事少商量,难靠祖宗作主张;独马单枪空做去,早年晚岁总无长。', plain: '主意要自己拿,靠人不如靠己;早定方向才不空忙。' },
|
|
74
|
+
28: { text: '一生行事似飘蓬,祖宗产业在梦中;若不过房改名姓,也当移徒二三通。', plain: '祖业难守,适合外出或改换环境,动中求安。' },
|
|
75
|
+
29: { text: '初年运限未曾亨,纵有功名在后成;须过四旬才可立,移居改姓始为良。', plain: '功名在后,四十前后才立得住,忌中途频繁换道。' },
|
|
76
|
+
30: { text: '劳劳碌碌苦中求,东奔西走何日休;若使终身勤与俭,老来稍可免忧愁。', plain: '东奔西走的劳碌格,靠勤俭积攒,晚年才得清闲。' },
|
|
77
|
+
31: { text: '忙忙碌碌苦中求,何日云开见日头;难得祖基家可立,中年衣食渐无忧。', plain: '先难后易:祖基难得,中年衣食转宽,守住本业即可。' },
|
|
78
|
+
32: { text: '初年运蹇事难谋,渐有财源如水流;到得中年衣食旺,那时名利一齐收。', plain: '幼年蹇滞,中年后财源渐旺,名利可期。' },
|
|
79
|
+
33: { text: '早年做事事难成,百年勤劳枉费心;半世自如流水去,后来运到始得金。', plain: '前半程多试错,后半程才见成果,急不得。' },
|
|
80
|
+
34: { text: '此命福气果如何,僧道门中衣禄多;离祖出家方为妙,朝晚拜佛念弥陀。', plain: '与清静行当、宗教或专门技艺有缘,离祖发展更顺。' },
|
|
81
|
+
35: { text: '生平福量不周全,祖业根基觉少传;营事生涯宜守旧,时来衣食胜从前。', plain: '福量不齐,宜守旧业、少折腾;时运到了自然宽裕。' },
|
|
82
|
+
36: { text: '不须劳碌过平生,独自成家福不轻;早有福星常照命,任君行去百般成。', plain: '不必太劳碌,福气随身,行事多能成。' },
|
|
83
|
+
37: { text: '此命般般事不成,弟兄少力自孤行;虽然祖业须微有,来得明时去不明。', plain: '单打独斗吃力、兄弟少力;宜合作,钱财要明算账。' },
|
|
84
|
+
38: { text: '一身骨肉最清高,早入簧门姓氏标;待到年将三十六,蓝衫脱去换红袍。', plain: '读书与专业路线见长,三十六前后有转机与体面。' },
|
|
85
|
+
39: { text: '此命终身运不通,劳劳作事尽皆空;苦心竭力成家计,到得那时在梦中。', plain: '早年空忙,成家立业偏晚;重在坚持,不宜频繁改行。' },
|
|
86
|
+
40: { text: '平生衣禄是绵长,件件心中自主张;前面风霜多受过,后来必定享安康。', plain: '先苦后甜:衣食渐稳,事在自主,晚景安康。' },
|
|
87
|
+
41: { text: '此命推来自不同,为人能干异凡庸;中年还有逍遥福,不比前时运来通。', plain: '能干出众,早年只是运会未到;中年有逍遥之福。' },
|
|
88
|
+
42: { text: '得宽怀处且宽怀,何用双眉皱不开;若使中年命运济,那时名利一起来。', plain: '心宽则顺;中年运济,名利自来,不必过虑。' },
|
|
89
|
+
43: { text: '为人心性最聪明,作事轩昂近贵人;衣禄一生天注定,不须劳碌是丰亨。', plain: '聪明近贵,易得贵人提携,衣禄有天定之说。' },
|
|
90
|
+
44: { text: '万事由天莫苦求,须知福碌赖人修;当年财帛难如意,晚景欣然便不优。', plain: '少壮难如意,晚景反安;福禄也靠人修,不必强求。' },
|
|
91
|
+
45: { text: '名利推求竟若何,前番辛苦后奔波;命中难养男和女,骨肉扶持也不多。', plain: '中年前后仍奔波,子女缘与骨肉助力偏薄,凡事多自扛。' },
|
|
92
|
+
46: { text: '东西南北尽皆通,出姓移居更觉隆;衣禄无穷无数定,中年晚景一般同。', plain: '外出、迁居更旺;衣禄不愁,中晚年境况相近。' },
|
|
93
|
+
47: { text: '此命推求旺末年,妻荣子贵自怡然;平生原有滔滔福,可卜财源若水泉。', plain: '晚运佳:妻荣子贵,福厚财源长。' },
|
|
94
|
+
48: { text: '初年运道未曾通,几许蹉跎命亦穷;兄弟六亲无依靠,一生事业晚来整。', plain: '早年蹉跎、六亲少靠,事业晚成,忌半途而废。' },
|
|
95
|
+
49: { text: '此命推来福不轻,自成自立显门庭;从来富贵人钦敬,使婢差奴过一生。', plain: '自立门户、显耀门庭,中年后受人敬重。' },
|
|
96
|
+
50: { text: '为利为名终日劳,中年福禄也多遭;老来自有财星照,不比前番目下高。', plain: '为名利终日奔忙,中年多波折;老来财星照,压力渐轻。' },
|
|
97
|
+
51: { text: '一世荣华事事通,不须劳碌自亨通;兄弟叔侄皆如意,家业成时福禄宏。', plain: '事多顺遂,兄弟叔侄得力,家业易成。' },
|
|
98
|
+
52: { text: '一世亨通事事能,不须劳苦自然宁;宗族有光欣喜甚,家产丰盈自称心。', plain: '诸事能干、少劳而宁;宗族有光,家产丰盈。' },
|
|
99
|
+
53: { text: '此格推来福泽宏,兴家立业在其中;一生衣食安排定,却是人间一福翁。', plain: '兴家立业之格,衣食安稳,是人间有福之人。' },
|
|
100
|
+
54: { text: '此格详采福泽宏,诗书满腹看功成;丰衣足食多安稳,正是人间有福人。', plain: '读书人格局:功名可期,衣食安稳。' },
|
|
101
|
+
55: { text: '策马扬鞭争名利,少年作事费筹论;一朝福禄源源至,富贵荣华显六亲。', plain: '少年费筹谋,一朝福至;富贵显亲,属于厚积薄发。' },
|
|
102
|
+
56: { text: '此格推来礼义通,一身福禄用无穷;甜酸苦辣皆尝过,滚滚财源盈而丰。', plain: '福禄厚:人生百味都经过,之后财源稳而丰。' },
|
|
103
|
+
57: { text: '福禄丰盈万事全,一身荣耀乐天年;名扬威震人争羡,此世逍遥宛似仙。', plain: '万事较全,名望与荣耀随行,晚运逍遥。' },
|
|
104
|
+
58: { text: '平生衣食自然来,名利双全富贵偕;金榜题名登甲第,紫袍玉带走金阶。', plain: '衣食自来、名利双全;有科第与体面之象。' },
|
|
105
|
+
59: { text: '细推此格秀而清,必定才高学业成;甲第之中应有分,扬鞭走马显威荣。', plain: '才高学业成,有科第之份,前程显达。' },
|
|
106
|
+
60: { text: '一朝金榜快题名,显祖荣宗大器成;衣禄定然无欠缺,田园财帛更丰盈。', plain: '金榜题名、显祖荣宗;衣禄丰足,田园财帛皆旺。' },
|
|
107
|
+
61: { text: '不作朝中金榜客,定为世上大财翁;聪明天付经书熟,名显高褂自是荣。', plain: '不入仕途也能成富;聪明博学,自有显名之荣。' },
|
|
108
|
+
62: { text: '此命生来福不穷,读书必定显亲宗;紫衣玉带为卿相,富贵荣华孰与同。', plain: '福泽不穷;读书可显亲,有卿相之象。' },
|
|
109
|
+
63: { text: '命主为官福禄长,得来富贵实非常;名题雁塔传金榜,大显门庭天下扬。', plain: '仕途顺、福禄长;富贵非常,门庭显扬。' },
|
|
110
|
+
64: { text: '此格威权不可当,紫袍金带尘高堂;荣华富贵谁能及,万古留名姓氏扬。', plain: '掌权之格:富贵与声名俱隆,留名后世。' },
|
|
111
|
+
65: { text: '细推此命福非轻,富贵荣华孰与争;定国安邦人极品,威声显赫震寰瀛。', plain: '贵重之命;有定国安邦之器,声威远震。' },
|
|
112
|
+
66: { text: '此格人间一福人,堆金积玉满堂春;从来富贵有天定,金榜题名更显亲。', plain: '堆金积玉、富贵天定;又有金榜显亲之象。' },
|
|
113
|
+
67: { text: '此命生来福自宏,田园家业最高隆;平生衣禄盈丰足,一路荣华万事通。', plain: '福厚家隆:田园家业兴旺,衣禄丰足,一路荣华。' },
|
|
114
|
+
68: { text: '富贵由天莫苦求,万事家计不须谋;十年不比前番事,祖业根基千古留。', plain: '家计不必苦谋;祖业根基可留,运势比前十年更好。' },
|
|
115
|
+
69: { text: '君是人间福禄星,一生富贵众人钦;总然衣禄由天定,安享荣华过一生。', plain: '人间福禄星:富贵受人钦敬,安享荣华。' },
|
|
116
|
+
70: { text: '此命推来福不轻,何须愁虑苦劳心;荣华富贵已天定,正笏垂绅拜紫宸。', plain: '不必愁虑劳心;荣华富贵已定,有朝堂之象。' },
|
|
117
|
+
71: { text: '此命生成大不同,公侯卿相在其中;一生自有逍遥福,富贵荣华极品隆。', plain: '公侯卿相之格:福厚逍遥,富贵极品。' },
|
|
118
|
+
72: { text: '此命推来天下隆,必定人间一主公;富贵荣华数不尽,定为乾坤一蛟龙。', plain: '极贵之格;但四表上限为七两一钱,此档基本不可达,仅备档。' },
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/** 按骨重取歌诀(超出 21–72 钱返回 null)。 */
|
|
122
|
+
export function songOf(qian) {
|
|
123
|
+
return CHENGGU_SONG[qian] || null;
|
|
124
|
+
}
|
|
125
|
+
|
|
61
126
|
/** 骨重分档(白话自撰)。 */
|
|
62
127
|
function bandVerdict(qian) {
|
|
63
128
|
if (qian >= 55) return { band: '上上', text: '骨重沉实,根基深厚,一生多逢贵人,谋事易成;守正持重,福泽可久。' };
|
|
@@ -95,6 +160,7 @@ export function buildChenggu(input) {
|
|
|
95
160
|
}
|
|
96
161
|
const total = wYear + wMonth + wDay + wHour;
|
|
97
162
|
const verdict = bandVerdict(total);
|
|
163
|
+
const song = songOf(total);
|
|
98
164
|
const jdn = toJDN(year, month, day);
|
|
99
165
|
|
|
100
166
|
return {
|
|
@@ -117,10 +183,14 @@ export function buildChenggu(input) {
|
|
|
117
183
|
},
|
|
118
184
|
total: { qian: total, label: formatWeight(total) },
|
|
119
185
|
verdict,
|
|
186
|
+
song: song
|
|
187
|
+
? { qian: total, label: formatWeight(total), title: `称骨歌·${formatWeight(total)}`, text: song.text, plain: song.plain, source: '通行本《称骨歌》' }
|
|
188
|
+
: { qian: total, label: formatWeight(total), title: `称骨歌·${formatWeight(total)}`, text: '', plain: '该骨重未见通行本歌诀(表内应落在二两一钱至七两二钱之间)。', source: '通行本《称骨歌》' },
|
|
120
189
|
sources: [
|
|
121
190
|
'骨重表:通行本袁天罡称骨(六十甲子年 / 十二月 / 三十日 / 十二时辰)',
|
|
122
|
-
'
|
|
191
|
+
'歌诀:通行本《称骨歌》原文照录(各版本有异文,断句标点已统一)',
|
|
192
|
+
'释义:白话自撰,非歌诀原文,只作字面直解',
|
|
123
193
|
],
|
|
124
|
-
disclaimer: '
|
|
194
|
+
disclaimer: '骨重与歌诀均为通行本口径,属民俗娱乐参考;释义为白话解释,不构成命运断言。',
|
|
125
195
|
};
|
|
126
196
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// 公农历互转(本地确定性,不依赖外部历法库)
|
|
2
|
+
//
|
|
3
|
+
// 两种方向:
|
|
4
|
+
// · 公历 → 农历:直接查本地定朔历(engine/lunar.js),给出农历年月日、闰月标记、干支、生肖。
|
|
5
|
+
// · 农历 → 公历:按目标农历年的「月首」序列反查(每月 29/30 天,闰月单独一轮),
|
|
6
|
+
// 逐月定位后再加日偏移;不做「节气月」换算,农历就是朔望月口径。
|
|
7
|
+
//
|
|
8
|
+
// 诚实边界:只处理 1900–2100 的本地历法覆盖范围(与 lunar.js 一致);闰月必须显式给出,
|
|
9
|
+
// 不猜「第一个同名月」;农历日期越界(如小月三十)如实报错,不静默回退。
|
|
10
|
+
import { solarToLunar } from './lunar.js';
|
|
11
|
+
import { fromJDN, toJDN } from './calendar.js';
|
|
12
|
+
import { buildAlmanac } from './almanac.js';
|
|
13
|
+
import { assertCivil, daysInMonth } from './validate.js';
|
|
14
|
+
|
|
15
|
+
const WEEK = ['日', '一', '二', '三', '四', '五', '六'];
|
|
16
|
+
const MONTH_TEXT = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊'];
|
|
17
|
+
const DAY_TENS = ['初', '十', '廿'];
|
|
18
|
+
const DAY_UNITS = ['十', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
|
|
19
|
+
|
|
20
|
+
function dayText(day) {
|
|
21
|
+
if (day === 10) return '初十';
|
|
22
|
+
if (day === 20) return '二十';
|
|
23
|
+
if (day === 30) return '三十';
|
|
24
|
+
return `${DAY_TENS[Math.floor(day / 10)]}${DAY_UNITS[day % 10]}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function lunarText(year, month, day, isLeap) {
|
|
28
|
+
return `农历${year}年${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月${dayText(day)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 找某个农历年的正月初一(公历 1/20–2/25 之间)。 */
|
|
32
|
+
function lunarNewYearJdn(lunarYear) {
|
|
33
|
+
const from = toJDN(lunarYear, 1, 20);
|
|
34
|
+
const to = toJDN(lunarYear, 2, 25);
|
|
35
|
+
for (let jdn = from; jdn <= to; jdn++) {
|
|
36
|
+
const p = fromJDN(jdn);
|
|
37
|
+
const l = solarToLunar(p.year, p.month, p.day);
|
|
38
|
+
if (l.lunarYear === lunarYear && l.month === 1 && l.day === 1) return jdn;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** 某农历年的月首序列(含闰月)。 */
|
|
44
|
+
function lunarMonths(lunarYear) {
|
|
45
|
+
const first = lunarNewYearJdn(lunarYear);
|
|
46
|
+
if (first == null) return [];
|
|
47
|
+
const out = [];
|
|
48
|
+
let cur = first;
|
|
49
|
+
for (let i = 0; i < 14; i++) {
|
|
50
|
+
const p = fromJDN(cur);
|
|
51
|
+
const l = solarToLunar(p.year, p.month, p.day);
|
|
52
|
+
if (i > 0 && l.month === 1 && !l.isLeap) break;
|
|
53
|
+
let next = null;
|
|
54
|
+
for (let k = 29; k <= 31; k++) {
|
|
55
|
+
const d = fromJDN(cur + k);
|
|
56
|
+
const l2 = solarToLunar(d.year, d.month, d.day);
|
|
57
|
+
if (l2.day === 1) { next = cur + k; break; }
|
|
58
|
+
}
|
|
59
|
+
if (next == null) break;
|
|
60
|
+
out.push({ month: l.month, isLeap: l.isLeap, startJdn: cur, length: next - cur });
|
|
61
|
+
cur = next;
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 公农历互转。
|
|
68
|
+
* @param {{mode?:'solar2lunar'|'lunar2solar', year?:number, month?:number, day?:number,
|
|
69
|
+
* lunarYear?:number, lunarMonth?:number, lunarDay?:number, isLeapMonth?:boolean}} input
|
|
70
|
+
*/
|
|
71
|
+
export function buildConvert(input) {
|
|
72
|
+
const mode = input.mode === 'lunar2solar' ? 'lunar2solar' : 'solar2lunar';
|
|
73
|
+
let solar;
|
|
74
|
+
let lunar;
|
|
75
|
+
let note = null;
|
|
76
|
+
if (mode === 'solar2lunar') {
|
|
77
|
+
solar = { year: input.year, month: input.month, day: input.day };
|
|
78
|
+
assertCivil(solar, '公农历转换');
|
|
79
|
+
if (solar.day > daysInMonth(solar.year, solar.month)) {
|
|
80
|
+
throw new Error(`非法日期:${solar.year} 年 ${solar.month} 月没有 ${solar.day} 日`);
|
|
81
|
+
}
|
|
82
|
+
lunar = solarToLunar(solar.year, solar.month, solar.day);
|
|
83
|
+
} else {
|
|
84
|
+
const y = Number(input.lunarYear);
|
|
85
|
+
const m = Number(input.lunarMonth);
|
|
86
|
+
const d = Number(input.lunarDay);
|
|
87
|
+
if (![y, m, d].every(Number.isInteger)) throw new Error('农历转换需要 lunarYear / lunarMonth / lunarDay');
|
|
88
|
+
if (m < 1 || m > 12) throw new Error('农历月份须在 1–12');
|
|
89
|
+
const months = lunarMonths(y);
|
|
90
|
+
if (!months.length) throw new Error(`农历 ${y} 年超出本地历法覆盖范围(1900–2100)`);
|
|
91
|
+
const isLeap = input.isLeapMonth === true;
|
|
92
|
+
const hit = months.find((x) => x.month === m && x.isLeap === isLeap);
|
|
93
|
+
if (!hit) {
|
|
94
|
+
const leapMonths = months.filter((x) => x.isLeap).map((x) => `闰${MONTH_TEXT[x.month - 1]}月`);
|
|
95
|
+
throw new Error(`农历 ${y} 年没有${leapMonths.length ? `该月(该年闰月为 ${leapMonths.join('、')})` : '闰月'}:${isLeap ? '请确认闰月标记' : '请确认月份'}`);
|
|
96
|
+
}
|
|
97
|
+
if (d < 1 || d > hit.length) throw new Error(`农历 ${y} 年${isLeap ? '闰' : ''}${MONTH_TEXT[m - 1]}月只有 ${hit.length} 天,没有 ${d} 日`);
|
|
98
|
+
const p = fromJDN(hit.startJdn + d - 1);
|
|
99
|
+
solar = { year: p.year, month: p.month, day: p.day };
|
|
100
|
+
const check = solarToLunar(p.year, p.month, p.day);
|
|
101
|
+
if (check.month !== m || check.day !== d || check.isLeap !== isLeap) {
|
|
102
|
+
note = '反查结果与目标农历日不完全一致,已按本地历法实际月首回推';
|
|
103
|
+
}
|
|
104
|
+
lunar = check;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const a = buildAlmanac(solar);
|
|
108
|
+
const jdn = toJDN(solar.year, solar.month, solar.day);
|
|
109
|
+
const solarText = `${solar.year}-${String(solar.month).padStart(2, '0')}-${String(solar.day).padStart(2, '0')}`;
|
|
110
|
+
return {
|
|
111
|
+
system: 'convert',
|
|
112
|
+
meta: {
|
|
113
|
+
mode,
|
|
114
|
+
solarDate: solarText,
|
|
115
|
+
weekday: `星期${WEEK[(jdn + 1) % 7]}`,
|
|
116
|
+
...(note ? { note } : {}),
|
|
117
|
+
scope: '公农历互转按本地定朔历(1900–2100);农历闰月须显式指定,不自动猜同名月',
|
|
118
|
+
},
|
|
119
|
+
solar: { year: solar.year, month: solar.month, day: solar.day, text: solarText },
|
|
120
|
+
lunar: {
|
|
121
|
+
year: lunar.lunarYear,
|
|
122
|
+
month: lunar.month,
|
|
123
|
+
day: lunar.day,
|
|
124
|
+
isLeap: lunar.isLeap,
|
|
125
|
+
text: lunarText(lunar.lunarYear, lunar.month, lunar.day, lunar.isLeap),
|
|
126
|
+
},
|
|
127
|
+
ganzhi: {
|
|
128
|
+
year: a.ganzhi.year,
|
|
129
|
+
month: a.ganzhi.month,
|
|
130
|
+
day: a.ganzhi.day,
|
|
131
|
+
shengXiao: a.ganzhi.shengXiao,
|
|
132
|
+
springYear: a.ganzhi.springYear,
|
|
133
|
+
},
|
|
134
|
+
sources: ['农历:本地定朔 + 节气黄经历法(engine/lunar.js)', '干支与生肖:与黄历同口径(年按立春界,另列春节界)'],
|
|
135
|
+
disclaimer: '历法换算为确定性计算;民俗历法各版本在极少数日期(交节当日、闰月边界)存在日界差异,已注明口径。',
|
|
136
|
+
};
|
|
137
|
+
}
|
package/engine/geo.js
CHANGED
|
@@ -143,7 +143,7 @@ const DETAIL = /(区|县|镇|乡|村|小区|街道|路|号|巷|弄|组|队)/;
|
|
|
143
143
|
|
|
144
144
|
/** OpenStreetMap Nominatim:免密钥、支持中文。失败返回 null。
|
|
145
145
|
* UA 按 OSM 使用政策要求写明应用与联系方式(改版本时同步这里)。 */
|
|
146
|
-
const USER_AGENT = 'dsh-metaphysics/0.
|
|
146
|
+
const USER_AGENT = 'dsh-metaphysics/0.19.0 (+https://github.com/xuanfu-web/dsh-metaphysics)';
|
|
147
147
|
|
|
148
148
|
async function onlineLookup(text, { timeoutMs = 2500 } = {}) {
|
|
149
149
|
if (typeof fetch !== 'function') return null;
|
package/engine/index.js
CHANGED
|
@@ -21,7 +21,8 @@ import { buildZeri } from './zeri.js';
|
|
|
21
21
|
import { buildChenggu } from './chenggu.js';
|
|
22
22
|
import { buildXiaoliuren } from './xiaoliuren.js';
|
|
23
23
|
import { buildStar } from './star.js';
|
|
24
|
-
import { buildNumerology } from './numerology.js';
|
|
24
|
+
import { buildNumerology } from './numerology.js';
|
|
25
|
+
import { buildConvert } from './convert.js';
|
|
25
26
|
import { buildTrend } from './trend.js';
|
|
26
27
|
import { buildFengshui } from './fengshui.js';
|
|
27
28
|
import { buildName } from './name.js';
|
|
@@ -617,6 +618,26 @@ function computeRaw(args = {}) {
|
|
|
617
618
|
const result = buildChenggu({ year: dt.year, month: dt.month, day: dt.day, hour, minute: hasTime ? dt.minute : 0 });
|
|
618
619
|
return { ...result, summary: chengguText(result) };
|
|
619
620
|
}
|
|
621
|
+
if (system === 'convert') {
|
|
622
|
+
const mode = args.mode === 'lunar2solar' ? 'lunar2solar' : 'solar2lunar';
|
|
623
|
+
let result;
|
|
624
|
+
if (mode === 'lunar2solar') {
|
|
625
|
+
if (args.lunarYear == null || args.lunarMonth == null || args.lunarDay == null) {
|
|
626
|
+
throw fail('E_INPUT', '农历转公历需要 lunarYear / lunarMonth / lunarDay(闰月另加 isLeapMonth: true)');
|
|
627
|
+
}
|
|
628
|
+
result = buildConvert({
|
|
629
|
+
mode,
|
|
630
|
+
lunarYear: Number(args.lunarYear),
|
|
631
|
+
lunarMonth: Number(args.lunarMonth),
|
|
632
|
+
lunarDay: Number(args.lunarDay),
|
|
633
|
+
isLeapMonth: args.isLeapMonth === true,
|
|
634
|
+
});
|
|
635
|
+
} else {
|
|
636
|
+
const dt = parseDateTime(args.datetime);
|
|
637
|
+
result = buildConvert({ mode, year: dt.year, month: dt.month, day: dt.day });
|
|
638
|
+
}
|
|
639
|
+
return { ...result, summary: convertText(result) };
|
|
640
|
+
}
|
|
620
641
|
if (system === 'xiaoliuren') {
|
|
621
642
|
const dt = args.datetime ? parseDateTime(args.datetime) : null;
|
|
622
643
|
const result = buildXiaoliuren({
|
|
@@ -700,22 +721,35 @@ function computeRaw(args = {}) {
|
|
|
700
721
|
return { ...result, summary: nameText(result) };
|
|
701
722
|
}
|
|
702
723
|
if (!system) {
|
|
703
|
-
throw fail('E_INPUT', '缺少 system,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name
|
|
724
|
+
throw fail('E_INPUT', '缺少 system,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name(起名)、convert(公农历互转)。');
|
|
704
725
|
}
|
|
705
|
-
throw fail('E_SYSTEM', `未知体系「${system}」,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name
|
|
726
|
+
throw fail('E_SYSTEM', `未知体系「${system}」,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name(起名)、convert(公农历互转)。`);
|
|
706
727
|
}
|
|
707
728
|
|
|
708
729
|
/** 黄历文本 */
|
|
709
730
|
function almanacText(r) {
|
|
710
731
|
const g = r.ganzhi;
|
|
711
732
|
const jq = r.jieQi && r.jieQi.next ? ` 下一节:${r.jieQi.next.name} ${r.jieQi.next.date}` : '';
|
|
733
|
+
const god = r.dayGod ? `值日:${r.dayGod.name}(${r.dayGod.type}·${r.dayGod.luck})` : '';
|
|
734
|
+
const xiu = r.xiu ? `二十八宿:${r.xiu.name}宿(${r.xiu.luck}·${r.xiu.zheng}·${r.xiu.animal})` : '';
|
|
735
|
+
const tai = r.taiShen ? `胎神:${r.taiShen}` : '';
|
|
736
|
+
const pos = r.positions
|
|
737
|
+
? `吉神方位:喜神${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 : '—'}`
|
|
738
|
+
: '';
|
|
739
|
+
const lucky = r.lucky ? `吉配生肖:六合${r.lucky.liuhe || '—'} 三合${(r.lucky.sanhe || []).join('、') || '—'}` : '';
|
|
740
|
+
const nayin = r.nayin && r.nayin.day ? `日柱纳音:${r.nayin.day.name}` : '';
|
|
741
|
+
const hours = (r.hours || []).map((h) => `${h.zhi}${h.ganZhi.slice(0, 1)}·${h.shen}${h.luck === '吉' ? '吉' : '凶'}`).join(' ');
|
|
712
742
|
return [
|
|
713
743
|
`【黄历】${r.meta.date} ${r.meta.weekday} ${r.lunar.text}`,
|
|
714
744
|
`干支:${g.year}年 ${g.month}月 ${g.day}日 属${g.shengXiao}`,
|
|
715
745
|
...(r.meta.boundaryNote ? [` ${r.meta.boundaryNote}`] : []),
|
|
716
|
-
`建除:${r.zhiXing}日 冲:${r.chong.text}${r.chong.sha ? `(${r.chong.sha})` : ''}
|
|
746
|
+
`建除:${r.zhiXing}日 冲:${r.chong.text}${r.chong.sha ? `(${r.chong.sha})` : ''} ${god}`,
|
|
747
|
+
[xiu, nayin, tai].filter(Boolean).join(' '),
|
|
717
748
|
`宜:${r.yi.join('、')}`,
|
|
718
749
|
`忌:${r.ji.join('、')}`,
|
|
750
|
+
pos,
|
|
751
|
+
lucky,
|
|
752
|
+
hours ? `时辰吉凶:${hours}` : '',
|
|
719
753
|
`节气:上一节 ${r.jieQi.prev ? `${r.jieQi.prev.name} ${r.jieQi.prev.date}` : '—'}${jq}`,
|
|
720
754
|
r.dailyHexagram ? `每日一卦:${r.dailyHexagram.name} ${r.dailyHexagram.meaning || ''}` : '',
|
|
721
755
|
`口径:${r.meta.scope}`,
|
|
@@ -740,13 +774,17 @@ function zeriText(r) {
|
|
|
740
774
|
|
|
741
775
|
/** 称骨文本 */
|
|
742
776
|
function chengguText(r) {
|
|
743
|
-
|
|
777
|
+
const s = r.song || {};
|
|
778
|
+
const lines = [
|
|
744
779
|
`【称骨】${r.input.solar} ${r.lunar.text}`,
|
|
745
780
|
`四项:${r.weights.year.label} ${r.weights.month.label} ${r.weights.day.label} ${r.weights.hour.label}`,
|
|
746
781
|
`合计:${r.total.label}(${r.verdict.band})`,
|
|
747
|
-
|
|
748
|
-
'
|
|
749
|
-
|
|
782
|
+
`歌诀(${r.total.label}):${s.text || '—'}`,
|
|
783
|
+
`释义:${s.plain || '—'}`,
|
|
784
|
+
`分档白话:${r.verdict.text}`,
|
|
785
|
+
'口径:骨重与歌诀为通行本口径(各版本歌诀有异文),释义为白话自撰,属民俗娱乐参考。',
|
|
786
|
+
];
|
|
787
|
+
return lines.join('\n');
|
|
750
788
|
}
|
|
751
789
|
|
|
752
790
|
/** 小六壬文本 */
|
|
@@ -771,6 +809,18 @@ function starText(r) {
|
|
|
771
809
|
].join('\n');
|
|
772
810
|
}
|
|
773
811
|
|
|
812
|
+
/** 公农历互转文本 */
|
|
813
|
+
function convertText(r) {
|
|
814
|
+
const g = r.ganzhi;
|
|
815
|
+
const dir = r.meta.mode === 'lunar2solar' ? '农历 → 公历' : '公历 → 农历';
|
|
816
|
+
return [
|
|
817
|
+
`【公农历转换·${dir}】${r.lunar.text} ⇄ ${r.solar.text} ${r.meta.weekday}`,
|
|
818
|
+
`干支:${g.year}年 ${g.month}月 ${g.day}日 属${g.shengXiao}${g.springYear && g.springYear !== g.year ? `(春节界为${g.springYear}年)` : ''}`,
|
|
819
|
+
...(r.meta.note ? [`注:${r.meta.note}`] : []),
|
|
820
|
+
`口径:${r.meta.scope}`,
|
|
821
|
+
].join('\n');
|
|
822
|
+
}
|
|
823
|
+
|
|
774
824
|
/** 生命数字文本 */
|
|
775
825
|
function numerologyText(r) {
|
|
776
826
|
return [
|
|
@@ -879,7 +929,7 @@ export { buildBazi, buildLiuyao, tossLines };
|
|
|
879
929
|
export { followup };
|
|
880
930
|
export { pastSignals, verifyFit, rectifyBirth };
|
|
881
931
|
export { crossCheck, crossText };
|
|
882
|
-
export { buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buildNumerology };
|
|
932
|
+
export { buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buildNumerology, buildConvert };
|
|
883
933
|
export { buildTrend, buildFengshui, buildName };
|
|
884
934
|
|
|
885
935
|
|
package/engine/zeri.js
CHANGED
|
@@ -7,27 +7,54 @@ import { buildAlmanac, SHENGXIAO } from './almanac.js';
|
|
|
7
7
|
export const TASKS = {
|
|
8
8
|
嫁娶: { yi: ['嫁娶', '结亲', '订盟', '纳采'], related: ['会亲友', '裁衣'], category: 'marriage' },
|
|
9
9
|
订婚: { yi: ['订盟', '纳采'], related: ['嫁娶', '会亲友'], category: 'marriage' },
|
|
10
|
+
领证: { yi: ['嫁娶', '纳采'], related: ['订盟', '会亲友'], category: 'marriage' },
|
|
11
|
+
提亲: { yi: ['纳采', '订盟'], related: ['会亲友'], category: 'marriage' },
|
|
12
|
+
收送聘金: { yi: ['纳采', '订盟'], related: ['嫁娶'], category: 'marriage' },
|
|
13
|
+
满月酒: { yi: ['祭祀', '祈福'], related: ['会亲友'], category: 'celebration' },
|
|
10
14
|
开业: { yi: ['开市', '立券', '交易'], related: ['纳财', '挂匾'], category: 'business' },
|
|
15
|
+
交易: { yi: ['交易', '立券'], related: ['开市', '纳财'], category: 'business' },
|
|
16
|
+
投资: { yi: ['纳财', '交易'], related: ['立券'], category: 'business' },
|
|
17
|
+
签订合同: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
18
|
+
签约: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
19
|
+
纳财: { yi: ['纳财', '收账'], related: ['开市', '立券'], category: 'contract' },
|
|
11
20
|
入宅: { yi: ['入宅', '移徙'], related: ['安床', '修造', '扫舍'], category: 'move' },
|
|
12
21
|
搬家: { yi: ['移徙', '入宅'], related: ['安床', '修造'], category: 'move' },
|
|
22
|
+
搬家入宅: { yi: ['入宅', '移徙'], related: ['安床', '扫舍'], category: 'move' },
|
|
13
23
|
动土: { yi: ['动土', '修造'], related: ['竖柱', '上梁'], category: 'construction' },
|
|
14
24
|
装修: { yi: ['修造', '修饰垣墙'], related: ['动土'], category: 'construction' },
|
|
25
|
+
装修建造: { yi: ['修造', '动土'], related: ['竖柱', '上梁'], category: 'construction' },
|
|
26
|
+
试车买车: { yi: ['交易', '纳财'], related: ['出行'], category: 'purchase' },
|
|
15
27
|
安葬: { yi: ['安葬', '破土'], related: ['立碑', '埋穴'], category: 'burial' },
|
|
16
28
|
出行: { yi: ['出行'], related: ['上任', '赴任'], category: 'travel' },
|
|
29
|
+
旅行: { yi: ['出行'], related: ['上任', '赴任'], category: 'travel' },
|
|
30
|
+
赴任: { yi: ['上任', '赴任'], related: ['出行'], category: 'travel' },
|
|
31
|
+
访亲友: { yi: ['会亲友'], related: ['出行'], category: 'visit' },
|
|
32
|
+
入学: { yi: ['入学'], related: ['开市', '修造'], category: 'study' },
|
|
17
33
|
祭祀: { yi: ['祭祀'], related: ['祈福', '求嗣'], category: 'worship' },
|
|
18
|
-
签约: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
19
34
|
求医: { yi: ['求医', '疗病'], related: ['针灸'], category: 'medical' },
|
|
20
|
-
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** 事项分组(界面按组呈现;与商用黄历的「常用/婚嫁/生活/建造/工商」对应)。 */
|
|
38
|
+
export const TASK_GROUPS = {
|
|
39
|
+
常用: ['嫁娶', '搬家入宅', '出行', '开业', '签订合同', '祭祀'],
|
|
40
|
+
婚嫁: ['嫁娶', '订婚', '领证', '提亲', '收送聘金', '满月酒'],
|
|
41
|
+
生活: ['搬家', '入宅', '旅行', '访亲友', '入学', '求医', '祭祀'],
|
|
42
|
+
建造: ['动土', '装修', '装修建造', '安葬', '试车买车'],
|
|
43
|
+
工商: ['开业', '交易', '投资', '签订合同', '签约', '纳财', '赴任'],
|
|
21
44
|
};
|
|
22
45
|
|
|
23
46
|
/** 建除十二神按事项大类的通行适配(简化口径)。 */
|
|
24
47
|
const ZHIXING_FAVOR = {
|
|
25
48
|
marriage: ['满', '定', '成', '开'],
|
|
49
|
+
celebration: ['满', '成', '开', '平'],
|
|
26
50
|
business: ['开', '成', '满', '收'],
|
|
27
51
|
move: ['定', '成', '开', '除'],
|
|
28
52
|
construction: ['建', '除', '成', '开'],
|
|
53
|
+
purchase: ['成', '开', '满'],
|
|
29
54
|
burial: ['除', '定', '闭', '破'],
|
|
30
55
|
travel: ['建', '成', '开', '除'],
|
|
56
|
+
visit: ['满', '平', '定', '成'],
|
|
57
|
+
study: ['成', '开', '建'],
|
|
31
58
|
worship: ['除', '满', '平', '定', '执', '成', '开'],
|
|
32
59
|
contract: ['定', '成', '收', '开'],
|
|
33
60
|
medical: ['除', '开'],
|