ziwei-cli 1.1.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.
@@ -0,0 +1,156 @@
1
+ /**
2
+ * 宫位查询命令
3
+ * 支持本命/大限/流年/流月/流日各层级的三方四正查询
4
+ */
5
+
6
+ import { generateAstrolabe, formatPalace, formatSurroundedPalaces, getAstrolabeBasicInfo, getScopePalaces } from '../engine/astrolabe.js';
7
+ import { detectPatterns } from '../engine/patterns.js';
8
+
9
+ /**
10
+ * 构建查询日期字符串
11
+ */
12
+ function buildQueryDate(year, month = 1, day = 1) {
13
+ const m = String(month).padStart(2, '0');
14
+ const d = String(day).padStart(2, '0');
15
+ return `${year}-${m}-${d}`;
16
+ }
17
+
18
+ /**
19
+ * 获取指定层级的宫位及三方四正
20
+ */
21
+ function getScopedPalaceAndSurrounded(astrolabe, palaceName, scope, queryDate) {
22
+ if (scope === 'origin') {
23
+ // 本命层直接从 astrolabe 获取
24
+ const targetPalace = astrolabe.palace(palaceName);
25
+ const surroundedPalaces = astrolabe.surroundedPalaces(palaceName);
26
+ return { targetPalace, surroundedPalaces, scopeData: {} };
27
+ } else {
28
+ // 运限层从 horoscope 获取
29
+ const horoscope = astrolabe.horoscope(queryDate);
30
+ const scopeData = horoscope[scope];
31
+
32
+ if (!scopeData) {
33
+ throw new Error(`无效的运限范围: ${scope}`);
34
+ }
35
+
36
+ const targetPalace = horoscope.palace(palaceName, scope);
37
+ const surroundedPalaces = horoscope.surroundPalaces(palaceName, scope);
38
+
39
+ return { targetPalace, surroundedPalaces, scopeData };
40
+ }
41
+ }
42
+
43
+ /**
44
+ * 执行宫位查询
45
+ * @param {Object} options - 命令选项
46
+ * @returns {Object} 查询结果 (JSON)
47
+ */
48
+ export async function executePalace(options) {
49
+ const { date, time, gender, city, palace, lunar, leap, scope = 'origin', year, month, day } = options;
50
+
51
+ try {
52
+ // 验证必需参数
53
+ if (!date || !time || !gender || !city || !palace) {
54
+ return {
55
+ success: false,
56
+ error: '缺少必需参数: date, time, gender, city, palace'
57
+ };
58
+ }
59
+
60
+ // 验证运限层级所需的额外参数
61
+ if (scope !== 'origin' && !year) {
62
+ return {
63
+ success: false,
64
+ error: `${scope} 层级需要指定 year 参数`
65
+ };
66
+ }
67
+ if ((scope === 'monthly' || scope === 'daily') && !month) {
68
+ return {
69
+ success: false,
70
+ error: `${scope} 层级需要指定 month 参数`
71
+ };
72
+ }
73
+ if (scope === 'daily' && !day) {
74
+ return {
75
+ success: false,
76
+ error: 'daily 层级需要指定 day 参数'
77
+ };
78
+ }
79
+
80
+ // 生成星盘
81
+ const astrolabe = await generateAstrolabe({
82
+ birth_date: date,
83
+ time: time,
84
+ gender: gender,
85
+ city: city,
86
+ is_lunar: lunar || false,
87
+ is_leap: leap || false
88
+ });
89
+
90
+ // 获取目标宫位名称
91
+ // origin 模式需要带"宫"字,horoscope 模式不需要
92
+ const palaceNameWithSuffix = palace.replace(/宫$/, '') + '宫';
93
+ const palaceNameWithoutSuffix = palace.replace(/宫$/, '');
94
+ const targetPalaceName = scope === 'origin' ? palaceNameWithSuffix : palaceNameWithoutSuffix;
95
+
96
+ // 构建查询日期
97
+ const queryDate = scope !== 'origin' ? buildQueryDate(year, month || 1, day || 1) : null;
98
+
99
+ // 获取目标宫位和三方四正
100
+ const { targetPalace, surroundedPalaces, scopeData } = getScopedPalaceAndSurrounded(
101
+ astrolabe, targetPalaceName, scope, queryDate
102
+ );
103
+
104
+ if (!targetPalace) {
105
+ return {
106
+ success: false,
107
+ error: `未找到宫位: ${palace}`
108
+ };
109
+ }
110
+
111
+ // 检测格局
112
+ let patterns;
113
+ if (scope === 'origin') {
114
+ patterns = detectPatterns(astrolabe);
115
+ } else {
116
+ const horoscope = astrolabe.horoscope(queryDate);
117
+ patterns = detectPatterns(horoscope, scope);
118
+ }
119
+
120
+ // 构建结果
121
+ const result = {
122
+ success: true,
123
+ data: {
124
+ basic_info: getAstrolabeBasicInfo(astrolabe),
125
+ scope: scope,
126
+ target_palace: formatPalace(targetPalace, scopeData, scope),
127
+ surrounded_palaces: formatSurroundedPalaces(surroundedPalaces, scopeData, scope),
128
+ patterns: patterns.map(p => ({
129
+ title: p.title,
130
+ blurb: p.blurb,
131
+ reason: p.reason
132
+ }))
133
+ }
134
+ };
135
+
136
+ // 添加查询时间信息
137
+ if (scope !== 'origin') {
138
+ result.data.query_year = year;
139
+ if (month) result.data.query_month = month;
140
+ if (day) result.data.query_day = day;
141
+
142
+ // 添加该层级的四化信息
143
+ if (scopeData.mutagen) {
144
+ result.data.mutagen = scopeData.mutagen;
145
+ }
146
+ }
147
+
148
+ return result;
149
+
150
+ } catch (error) {
151
+ return {
152
+ success: false,
153
+ error: error.message
154
+ };
155
+ }
156
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * 合盘分析命令
3
+ */
4
+
5
+ import { analyzeSynastryByUserInfo } from '../engine/synastry.js';
6
+
7
+ /**
8
+ * 执行本命合盘分析
9
+ */
10
+ export async function executeSynastry(options) {
11
+ const {
12
+ aDate, aTime, aGender, aCity, aName,
13
+ bDate, bTime, bGender, bCity, bName,
14
+ aLunar, aLeap, bLunar, bLeap
15
+ } = options;
16
+
17
+ try {
18
+ // 验证必需参数
19
+ if (!aDate || !aTime || !aGender || !aCity) {
20
+ return {
21
+ success: false,
22
+ error: '缺少A方必需参数: a-date, a-time, a-gender, a-city'
23
+ };
24
+ }
25
+ if (!bDate || !bTime || !bGender || !bCity) {
26
+ return {
27
+ success: false,
28
+ error: '缺少B方必需参数: b-date, b-time, b-gender, b-city'
29
+ };
30
+ }
31
+
32
+ const result = await analyzeSynastryByUserInfo({
33
+ birth_date_a: aDate,
34
+ birth_time_a: aTime,
35
+ gender_a: aGender,
36
+ city_a: aCity,
37
+ name_a: aName || 'A',
38
+ birth_date_b: bDate,
39
+ birth_time_b: bTime,
40
+ gender_b: bGender,
41
+ city_b: bCity,
42
+ name_b: bName || 'B',
43
+ is_lunar_a: aLunar || false,
44
+ is_leap_a: aLeap || false,
45
+ is_lunar_b: bLunar || false,
46
+ is_leap_b: bLeap || false,
47
+ scope: 'origin'
48
+ });
49
+
50
+ return result;
51
+
52
+ } catch (error) {
53
+ return {
54
+ success: false,
55
+ error: error.message
56
+ };
57
+ }
58
+ }
59
+
60
+ /**
61
+ * 执行流年合盘分析
62
+ */
63
+ export async function executeSynastryYearly(options) {
64
+ const {
65
+ aDate, aTime, aGender, aCity, aName,
66
+ bDate, bTime, bGender, bCity, bName,
67
+ aLunar, aLeap, bLunar, bLeap,
68
+ year
69
+ } = options;
70
+
71
+ try {
72
+ if (!aDate || !aTime || !aGender || !aCity) {
73
+ return {
74
+ success: false,
75
+ error: '缺少A方必需参数: a-date, a-time, a-gender, a-city'
76
+ };
77
+ }
78
+ if (!bDate || !bTime || !bGender || !bCity) {
79
+ return {
80
+ success: false,
81
+ error: '缺少B方必需参数: b-date, b-time, b-gender, b-city'
82
+ };
83
+ }
84
+ if (!year) {
85
+ return {
86
+ success: false,
87
+ error: '缺少年份参数: year'
88
+ };
89
+ }
90
+
91
+ const queryDate = `${year}-01-01`;
92
+
93
+ const result = await analyzeSynastryByUserInfo({
94
+ birth_date_a: aDate,
95
+ birth_time_a: aTime,
96
+ gender_a: aGender,
97
+ city_a: aCity,
98
+ name_a: aName || 'A',
99
+ birth_date_b: bDate,
100
+ birth_time_b: bTime,
101
+ gender_b: bGender,
102
+ city_b: bCity,
103
+ name_b: bName || 'B',
104
+ is_lunar_a: aLunar || false,
105
+ is_leap_a: aLeap || false,
106
+ is_lunar_b: bLunar || false,
107
+ is_leap_b: bLeap || false,
108
+ scope: 'yearly',
109
+ query_date: queryDate
110
+ });
111
+
112
+ if (result.success) {
113
+ result.data.query_year = year;
114
+ }
115
+
116
+ return result;
117
+
118
+ } catch (error) {
119
+ return {
120
+ success: false,
121
+ error: error.message
122
+ };
123
+ }
124
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * 星盘生成模块
3
+ * 封装 iztro 库,提供命盘生成和格式化功能
4
+ */
5
+
6
+ import { lookupCity } from './geo.js';
7
+ import { getSolarTime, getTimeIndex } from './solar.js';
8
+ import { starsTypeMapping, scopeMapping, MUTAGENS_MAPPING, PALACE_NAMES } from './config.js';
9
+
10
+ let astroClient;
11
+
12
+ /**
13
+ * 获取 iztro 客户端
14
+ */
15
+ async function getAstroClient() {
16
+ if (!astroClient) {
17
+ const { astro } = await import('iztro');
18
+ astro.config({ yearDivide: 'normal' });
19
+ astroClient = astro;
20
+ }
21
+ return astroClient;
22
+ }
23
+
24
+ /**
25
+ * 生成星盘
26
+ * @param {Object} params - 参数对象
27
+ * @param {string} params.birth_date - 出生日期 (YYYY-MM-DD)
28
+ * @param {string} params.time - 出生时间 (HH:mm)
29
+ * @param {string} params.gender - 性别 ("男"/"女")
30
+ * @param {string} params.city - 出生城市
31
+ * @param {boolean} params.is_lunar - 是否农历 (默认false)
32
+ * @param {boolean} params.is_leap - 是否闰月 (默认false)
33
+ * @returns {Object} iztro 星盘对象
34
+ */
35
+ export async function generateAstrolabe({ birth_date, time, gender, city, is_lunar = false, is_leap = false }) {
36
+ try {
37
+ const astro = await getAstroClient();
38
+ const [hour, minute] = time.split(':').map(Number);
39
+
40
+ // 获取城市坐标
41
+ const locationResult = lookupCity(city);
42
+ if (!locationResult.success) {
43
+ throw new Error(`城市查询失败: ${locationResult.error}`);
44
+ }
45
+ const coordinates = {
46
+ lat: locationResult.data.latitude,
47
+ lng: locationResult.data.longitude
48
+ };
49
+
50
+ // 解析日期
51
+ let dateParts;
52
+ if (is_lunar) {
53
+ const tempAstrolabe = astro.byLunar(birth_date, 0, gender, is_leap, true, 'zh-CN');
54
+ const [year, month, day] = tempAstrolabe.solarDate.split('-').map(Number);
55
+ dateParts = { year, month, day };
56
+ } else {
57
+ const [year, month, day] = birth_date.split('-').map(Number);
58
+ dateParts = { year, month, day };
59
+ }
60
+
61
+ // 计算真太阳时
62
+ const solarTimeResult = getSolarTime({
63
+ dateTime: { ...dateParts, hour, minute, second: 0 },
64
+ longitude: coordinates.lng,
65
+ latitude: coordinates.lat
66
+ });
67
+
68
+ let timeIndex;
69
+ if (solarTimeResult.success) {
70
+ const trueSolarTime = solarTimeResult.data.trueSolarTime;
71
+ timeIndex = getTimeIndex(trueSolarTime.hour, trueSolarTime.minute);
72
+ } else {
73
+ timeIndex = getTimeIndex(hour, minute);
74
+ }
75
+
76
+ // 生成星盘
77
+ const astrolabe = is_lunar
78
+ ? astro.byLunar(birth_date, timeIndex, gender, is_leap, true, 'zh-CN')
79
+ : astro.bySolar(birth_date, timeIndex, gender, is_leap, 'zh-CN');
80
+
81
+ return astrolabe;
82
+ } catch (error) {
83
+ throw new Error(`星盘生成失败: ${error.message}`);
84
+ }
85
+ }
86
+
87
+ /**
88
+ * 格式化宫位信息
89
+ */
90
+ export function formatPalace(palace, horoscope = {}, scope = 'origin') {
91
+ const ret = {
92
+ "宫位索引": palace.index,
93
+ "宫位名称": horoscope?.palaceNames?.[palace.index] || palace.name,
94
+ "是否身宫": palace.isBodyPalace,
95
+ "是否本宫": palace.isOriginalPalace,
96
+ "天干": palace.heavenlyStem,
97
+ "地支": palace.earthlyBranch,
98
+ "主星": palace.majorStars?.map(star => ({
99
+ "星曜名称": star.name,
100
+ "星曜类型": starsTypeMapping(star.type),
101
+ "作用范围": scopeMapping(star.scope),
102
+ "亮度": star.brightness || "无",
103
+ "本命盘四化": star.mutagen ? star.name + '化' + star.mutagen : "无"
104
+ })) || [],
105
+ "辅星": palace.minorStars?.map(star => ({
106
+ "星曜名称": star.name,
107
+ "星曜类型": starsTypeMapping(star.type),
108
+ "作用范围": scopeMapping(star.scope),
109
+ "亮度": star.brightness || "无"
110
+ })) || [],
111
+ "杂曜": palace.adjectiveStars?.map(star => ({
112
+ "星曜名称": star.name,
113
+ "星曜类型": starsTypeMapping(star.type),
114
+ "作用范围": scopeMapping(star.scope)
115
+ })) || [],
116
+ };
117
+
118
+ if (scope === 'origin') {
119
+ ret["长生十二神"] = palace.changsheng12 || "无";
120
+ ret["博士十二神"] = palace.boshi12 || "无";
121
+ } else {
122
+ ret["将前十二神"] = palace.jiangqian12 || "无";
123
+ ret["岁前十二神"] = palace.suiqian12 || "无";
124
+ }
125
+
126
+ if (scope === 'decadal') {
127
+ ret["运耀"] = horoscope.stars?.[palace.index]?.map(star => ({
128
+ "星曜名称": star.name,
129
+ "星曜类型": starsTypeMapping(star.type),
130
+ "作用范围": scopeMapping(star.scope),
131
+ "亮度": star.brightness || "无",
132
+ "运耀四化": star.mutagen ? star.name + '化' + star.mutagen : "无"
133
+ })) || [];
134
+
135
+ ret["大限飞星四化"] = horoscope.mutagen?.reduce((acc, mutagen, i) => {
136
+ if (palace.majorStars?.some(star => star.name === mutagen)) {
137
+ acc.push(mutagen + '化' + MUTAGENS_MAPPING[i]);
138
+ }
139
+ return acc;
140
+ }, []) || [];
141
+
142
+ if (palace.index === horoscope.index) {
143
+ ret["大限年龄范围"] = palace.decadal?.range || [];
144
+ }
145
+ }
146
+
147
+ if (scope === 'yearly') {
148
+ ret["流曜"] = horoscope.stars?.[palace.index]?.map(star => ({
149
+ "星曜名称": star.name,
150
+ "星曜类型": starsTypeMapping(star.type),
151
+ "作用范围": scopeMapping(star.scope),
152
+ "亮度": star.brightness || "无",
153
+ "流曜四化": star.mutagen ? star.name + '化' + star.mutagen : "无"
154
+ })) || [];
155
+
156
+ ret["流年飞星四化"] = horoscope.mutagen?.reduce((acc, mutagen, i) => {
157
+ if (palace.majorStars?.some(star => star.name === mutagen)) {
158
+ acc.push(mutagen + '化' + MUTAGENS_MAPPING[i]);
159
+ }
160
+ return acc;
161
+ }, []) || [];
162
+ }
163
+
164
+ return ret;
165
+ }
166
+
167
+ /**
168
+ * 获取指定运限范围内的十二宫信息数组
169
+ */
170
+ export function getScopePalaces(horoscope, scope) {
171
+ if (!horoscope || typeof horoscope.palace !== 'function') {
172
+ throw new Error('无效的运限对象:缺少宫位查询能力');
173
+ }
174
+
175
+ return horoscope[scope].palaceNames.map(name => {
176
+ const palace = horoscope.palace(name, scope);
177
+ if (!palace) {
178
+ throw new Error(`未能获取「${name}」的运限宫位信息`);
179
+ }
180
+ palace.name = horoscope[scope].palaceNames[palace.index];
181
+ return palace;
182
+ });
183
+ }
184
+
185
+ /**
186
+ * 格式化三方四正宫位信息
187
+ */
188
+ export function formatSurroundedPalaces(surroundedPalaces, horoscope = {}, scope = 'origin') {
189
+ return {
190
+ "对宫": formatPalace(surroundedPalaces.opposite, horoscope, scope),
191
+ "三方": {
192
+ "三合宫之一": formatPalace(surroundedPalaces.wealth, horoscope, scope),
193
+ "三合宫之二": formatPalace(surroundedPalaces.career, horoscope, scope),
194
+ },
195
+ };
196
+ }
197
+
198
+ /**
199
+ * 获取星盘基本信息
200
+ */
201
+ export function getAstrolabeBasicInfo(astrolabe) {
202
+ return {
203
+ "阳历日期": astrolabe.solarDate,
204
+ "农历日期": astrolabe.lunarDate,
205
+ "四柱": astrolabe.chineseDate,
206
+ "时辰": astrolabe.time,
207
+ "时辰对应时间段": astrolabe.timeRange,
208
+ "星座": astrolabe.sign,
209
+ "生肖": astrolabe.zodiac,
210
+ "命宫地支": astrolabe.earthlyBranchOfSoulPalace,
211
+ "身宫地支": astrolabe.earthlyBranchOfBodyPalace,
212
+ "命主": astrolabe.soul,
213
+ "身主": astrolabe.body,
214
+ "五行局": astrolabe.fiveElementsClass
215
+ };
216
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * 八字计算引擎
3
+ * 基于 tyme4ts 和 cantian-tymext 库
4
+ */
5
+
6
+ import { calculateRelation, getShen } from 'cantian-tymext';
7
+ import {
8
+ ChildLimit,
9
+ DefaultEightCharProvider,
10
+ LunarHour,
11
+ LunarSect2EightCharProvider,
12
+ SolarTime,
13
+ } from 'tyme4ts';
14
+
15
+ const eightCharProvider1 = new DefaultEightCharProvider();
16
+ const eightCharProvider2 = new LunarSect2EightCharProvider();
17
+
18
+ /**
19
+ * 构建藏干对象
20
+ */
21
+ function buildHideHeavenObject(heavenStem, me) {
22
+ if (!heavenStem) return undefined;
23
+ return {
24
+ 天干: heavenStem.toString(),
25
+ 十神: me.getTenStar(heavenStem).toString(),
26
+ };
27
+ }
28
+
29
+ /**
30
+ * 构建六十甲子柱对象(年柱/月柱/日柱/时柱)
31
+ */
32
+ function buildSixtyCycleObject(sixtyCycle, me) {
33
+ const heavenStem = sixtyCycle.getHeavenStem();
34
+ const earthBranch = sixtyCycle.getEarthBranch();
35
+ if (!me) me = heavenStem;
36
+
37
+ return {
38
+ 天干: {
39
+ 天干: heavenStem.toString(),
40
+ 五行: heavenStem.getElement().toString(),
41
+ 阴阳: heavenStem.getYinYang() === 1 ? '阳' : '阴',
42
+ 十神: me === heavenStem ? undefined : me.getTenStar(heavenStem).toString(),
43
+ },
44
+ 地支: {
45
+ 地支: earthBranch.toString(),
46
+ 五行: earthBranch.getElement().toString(),
47
+ 阴阳: earthBranch.getYinYang() === 1 ? '阳' : '阴',
48
+ 藏干: {
49
+ 主气: buildHideHeavenObject(earthBranch.getHideHeavenStemMain(), me),
50
+ 中气: buildHideHeavenObject(earthBranch.getHideHeavenStemMiddle(), me),
51
+ 余气: buildHideHeavenObject(earthBranch.getHideHeavenStemResidual(), me),
52
+ },
53
+ },
54
+ 纳音: sixtyCycle.getSound().toString(),
55
+ 旬: sixtyCycle.getTen().toString(),
56
+ 空亡: sixtyCycle.getExtraEarthBranches().join(''),
57
+ 星运: me.getTerrain(earthBranch).toString(),
58
+ 自坐: heavenStem.getTerrain(earthBranch).toString(),
59
+ };
60
+ }
61
+
62
+ /**
63
+ * 构建神煞对象
64
+ */
65
+ function buildGodsObject(eightChar, gender) {
66
+ const gods = getShen(eightChar.toString(), gender);
67
+ return {
68
+ 年柱: gods[0],
69
+ 月柱: gods[1],
70
+ 日柱: gods[2],
71
+ 时柱: gods[3],
72
+ };
73
+ }
74
+
75
+ /**
76
+ * 构建大运排盘
77
+ */
78
+ function buildDecadeFortuneObject(solarTime, gender, me) {
79
+ const childLimit = ChildLimit.fromSolarTime(solarTime, gender);
80
+ let decadeFortune = childLimit.getStartDecadeFortune();
81
+ const firstStartAge = decadeFortune.getStartAge();
82
+ const startDate = childLimit.getEndTime();
83
+ const decadeFortuneObjects = [];
84
+
85
+ for (let i = 0; i < 10; i++) {
86
+ const sixtyCycle = decadeFortune.getSixtyCycle();
87
+ const heavenStem = sixtyCycle.getHeavenStem();
88
+ const earthBranch = sixtyCycle.getEarthBranch();
89
+ decadeFortuneObjects.push({
90
+ 干支: sixtyCycle.toString(),
91
+ 开始年份: decadeFortune.getStartSixtyCycleYear().getYear(),
92
+ 结束年份: decadeFortune.getEndSixtyCycleYear().getYear(),
93
+ 天干十神: me.getTenStar(heavenStem).getName(),
94
+ 地支十神: earthBranch.getHideHeavenStems().map((hs) => me.getTenStar(hs.getHeavenStem()).getName()),
95
+ 地支藏干: earthBranch.getHideHeavenStems().map((hs) => hs.toString()),
96
+ 开始年龄: decadeFortune.getStartAge(),
97
+ 结束年龄: decadeFortune.getEndAge(),
98
+ });
99
+ decadeFortune = decadeFortune.next(1);
100
+ }
101
+
102
+ return {
103
+ 起运日期: `${startDate.getYear()}-${startDate.getMonth()}-${startDate.getDay()}`,
104
+ 起运年龄: firstStartAge,
105
+ 大运: decadeFortuneObjects,
106
+ };
107
+ }
108
+
109
+ /**
110
+ * 生成完整八字排盘
111
+ * @param {Object} options
112
+ * @param {string} options.date - 出生日期 YYYY-MM-DD
113
+ * @param {string} options.time - 出生时间 HH:MM
114
+ * @param {string} options.gender - 性别 "男"/"女"
115
+ * @param {boolean} [options.lunar] - 是否农历
116
+ * @param {number} [options.sect] - 早晚子时配置 1或2,默认2
117
+ */
118
+ export function generateBazi({ date, time, gender, lunar = false, sect = 2 }) {
119
+ const [hour, minute] = time.split(':').map(Number);
120
+ const genderNum = gender === '男' ? 1 : 0;
121
+
122
+ let lunarHour;
123
+
124
+ if (lunar) {
125
+ // 农历输入
126
+ const [year, month, day] = date.split('-').map(Number);
127
+ lunarHour = LunarHour.fromYmdHms(year, month, day, hour, minute, 0);
128
+ } else {
129
+ // 阳历输入
130
+ const [year, month, day] = date.split('-').map(Number);
131
+ const solarTime = SolarTime.fromYmdHms(year, month, day, hour, minute, 0);
132
+ lunarHour = solarTime.getLunarHour();
133
+ }
134
+
135
+ // 设置子时配置
136
+ if (sect === 2) {
137
+ LunarHour.provider = eightCharProvider2;
138
+ } else {
139
+ LunarHour.provider = eightCharProvider1;
140
+ }
141
+
142
+ const eightChar = lunarHour.getEightChar();
143
+ const me = eightChar.getDay().getHeavenStem();
144
+ const solarTime = lunarHour.getSolarTime();
145
+
146
+ return {
147
+ 性别: gender,
148
+ 阳历: solarTime.toString(),
149
+ 农历: lunarHour.toString(),
150
+ 八字: eightChar.toString(),
151
+ 生肖: eightChar.getYear().getEarthBranch().getZodiac().toString(),
152
+ 日主: me.toString(),
153
+ 年柱: buildSixtyCycleObject(eightChar.getYear(), me),
154
+ 月柱: buildSixtyCycleObject(eightChar.getMonth(), me),
155
+ 日柱: buildSixtyCycleObject(eightChar.getDay()),
156
+ 时柱: buildSixtyCycleObject(eightChar.getHour(), me),
157
+ 胎元: eightChar.getFetalOrigin().toString(),
158
+ 胎息: eightChar.getFetalBreath().toString(),
159
+ 命宫: eightChar.getOwnSign().toString(),
160
+ 身宫: eightChar.getBodySign().toString(),
161
+ 神煞: buildGodsObject(eightChar, genderNum),
162
+ 大运: buildDecadeFortuneObject(solarTime, genderNum, me),
163
+ 刑冲合会: calculateRelation({
164
+ 年: { 天干: eightChar.getYear().getHeavenStem().toString(), 地支: eightChar.getYear().getEarthBranch().toString() },
165
+ 月: { 天干: eightChar.getMonth().getHeavenStem().toString(), 地支: eightChar.getMonth().getEarthBranch().toString() },
166
+ 日: { 天干: eightChar.getDay().getHeavenStem().toString(), 地支: eightChar.getDay().getEarthBranch().toString() },
167
+ 时: { 天干: eightChar.getHour().getHeavenStem().toString(), 地支: eightChar.getHour().getEarthBranch().toString() },
168
+ }),
169
+ };
170
+ }
171
+
172
+ /**
173
+ * 获取黄历信息
174
+ * @param {string} [date] - 阳历日期 YYYY-MM-DD,不传则为当天
175
+ */
176
+ export function getCalendar(date) {
177
+ let solarTime;
178
+ if (date) {
179
+ const [year, month, day] = date.split('-').map(Number);
180
+ solarTime = SolarTime.fromYmdHms(year, month, day, 12, 0, 0);
181
+ } else {
182
+ const now = new Date();
183
+ solarTime = SolarTime.fromYmdHms(
184
+ now.getFullYear(), now.getMonth() + 1, now.getDate(),
185
+ now.getHours(), now.getMinutes(), now.getSeconds()
186
+ );
187
+ }
188
+
189
+ const lunarHour = solarTime.getLunarHour();
190
+ const lunarDay = lunarHour.getLunarDay();
191
+ const eightChar = lunarHour.getEightChar();
192
+ const solarDay = solarTime.getSolarDay();
193
+
194
+ return {
195
+ 公历: solarTime.toString().split(' ')[0],
196
+ 农历: lunarDay.toString(),
197
+ 干支: eightChar.toString().split(' ').slice(0, 3).join(' '),
198
+ 年干支: eightChar.getYear().toString(),
199
+ 月干支: eightChar.getMonth().toString(),
200
+ 日干支: eightChar.getDay().toString(),
201
+ 生肖: eightChar.getYear().getEarthBranch().getZodiac().toString(),
202
+ 纳音: eightChar.getDay().getSound().toString(),
203
+ 节气: solarDay.getTerm()?.toString() || '无节气',
204
+ 农历节日: lunarDay.getFestival()?.toString() || undefined,
205
+ 公历节日: solarDay.getFestival()?.toString() || undefined,
206
+ };
207
+ }