dsh-metaphysics 0.57.0 → 0.58.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 +1204 -1115
- package/README.md +20 -8
- package/client.almanac.js +59 -58
- package/client.bazi.js +102 -101
- package/client.chenggu.js +59 -58
- package/client.convert.js +59 -58
- package/client.daliuren.js +94 -93
- package/client.fengshui.js +58 -57
- package/client.hepan.js +103 -102
- package/client.js +353 -277
- package/client.liuyao.js +96 -95
- package/client.mbti.js +59 -58
- package/client.name.js +56 -55
- package/client.numerology.js +59 -58
- package/client.qimen.js +94 -93
- package/client.star.js +59 -58
- package/client.tarot.js +93 -92
- package/client.trend.js +96 -95
- package/client.xiaoliuren.js +59 -58
- package/client.zeri.js +59 -58
- package/client.ziwei.js +102 -101
- package/engine/bridge.js +211 -0
- package/engine/citations.js +57 -3
- package/engine/diff.js +54 -0
- package/engine/hepan.js +43 -0
- package/engine/index.js +111 -43
- package/engine/interpret-knowledge.js +3 -2
- package/engine/trace.js +18 -18
- package/engine/zeri.js +89 -13
- package/index.js +18 -2
- package/package.json +116 -115
- package//345/221/275/347/220/206/346/216/222/347/233/230.html +872 -95
package/engine/index.js
CHANGED
|
@@ -5,13 +5,14 @@ import { buildZiwei, BRIGHTNESS, flowOf, asOfParts, ZIWEI_SCHOOL_DEFAULTS } from
|
|
|
5
5
|
import { drawTarot } from './tarot.js';
|
|
6
6
|
import { buildMeihua } from './meihua.js';
|
|
7
7
|
import { buildDaliuren } from './daliuren.js';
|
|
8
|
-
import { buildHepan } from './hepan.js';
|
|
8
|
+
import { buildHepan, tripleOf } from './hepan.js';
|
|
9
9
|
import { buildZiweiHepan } from './ziwei-hepan.js';
|
|
10
10
|
import { buildQimen, buildSnapshot } from './qimen.js';
|
|
11
11
|
import { geocodeAddress, resolveAddress } from './geo.js';
|
|
12
12
|
import { toJDN, ganzhiName, dayGanzhiIndex } from './calendar.js';
|
|
13
13
|
import { randomOf, isSeed } from './random.js';
|
|
14
14
|
import { encodeHandle, decodeHandle, resolveHandle } from './handle.js';
|
|
15
|
+
import { askLink, parseAskLink, formOf, restNote, askPackages } from './bridge.js';
|
|
15
16
|
import { parseRevision, displayValue } from './revise.js';
|
|
16
17
|
import { interpret, DIRECTIONS, DIRECTION_DEFAULT } from './interpret.js';
|
|
17
18
|
import { followup, askPrompt } from './followup.js';
|
|
@@ -27,7 +28,7 @@ import { buildNumerology } from './numerology.js';
|
|
|
27
28
|
import { buildMbti, mbtiPaper } from './mbti.js';
|
|
28
29
|
import { buildConvert } from './convert.js';
|
|
29
30
|
import { classicsFor, classicsText, suiyunClassicOf, classicOf, CLASSIC_BOOKS } from './classics.js';
|
|
30
|
-
import { diffObjects, summarize, sortDiffs, labelOf, rootOf, categoryOf, formatValue, CALIBER_SWITCHES } from './diff.js';
|
|
31
|
+
import { diffObjects, summarize, sortDiffs, labelOf, rootOf, categoryOf, formatValue, CALIBER_SWITCHES, viewRows } from './diff.js';
|
|
31
32
|
import { canonicalJson, fingerprintOf } from './fingerprint.js';
|
|
32
33
|
import { buildTrend } from './trend.js';
|
|
33
34
|
import { buildFengshui } from './fengshui.js';
|
|
@@ -297,6 +298,26 @@ function qimenText(r) {
|
|
|
297
298
|
].join('\n');
|
|
298
299
|
}
|
|
299
300
|
|
|
301
|
+
function tripleText(t) {
|
|
302
|
+
if (!t || !Array.isArray(t.pairs) || !t.pairs.length) return [];
|
|
303
|
+
const lines = [
|
|
304
|
+
'【三方合盘】三对两两并列,不合成「三人总分」',
|
|
305
|
+
...t.pairs.map((p) => `· ${p.a}–${p.b}:${p.level || '—'}(${p.total == null ? '—' : `${p.total}/100`})`),
|
|
306
|
+
];
|
|
307
|
+
if (t.best) {
|
|
308
|
+
// 差 1–2 分时点名「最顺/最需磨合」是假精确:三对分数接近就直说接近,不排名
|
|
309
|
+
if (t.spread >= 3) {
|
|
310
|
+
lines.push(` 最顺:${t.best.a}–${t.best.b}(${t.best.total}/100)`
|
|
311
|
+
+ (t.hardest ? `;最需磨合:${t.hardest.a}–${t.hardest.b}(${t.hardest.total}/100)` : ''));
|
|
312
|
+
} else {
|
|
313
|
+
lines.push(` 三对分数接近(最高与最低相差 ${t.spread} 分),不排名`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (t.focus && t.focus.spread >= 3) lines.push(` 差异最大的一维:${t.focus.label}(三对相差 ${t.focus.spread} 分)`);
|
|
317
|
+
if (t.note) lines.push(`※ ${t.note}`);
|
|
318
|
+
return lines;
|
|
319
|
+
}
|
|
320
|
+
|
|
300
321
|
function hepanText(r) {
|
|
301
322
|
if (r.chart === 'ziwei') {
|
|
302
323
|
const d = (x) => `${x.label}:${x.score >= 0 ? '+' : ''}${x.score} ${x.text}`;
|
|
@@ -306,6 +327,7 @@ function hepanText(r) {
|
|
|
306
327
|
`对方 命宫 ${r.b.soul.branch}(${r.b.soulStars.join('、') || '无主星'}) 夫妻 ${r.b.spouseStars.join('、') || '无主星'} ${r.b.bureau}`,
|
|
307
328
|
...r.dimensions.map(d),
|
|
308
329
|
...r.interactions.map((h) => ` · ${h.text}`),
|
|
330
|
+
...tripleText(r.triple),
|
|
309
331
|
...r.notes.map((n) => `※ ${n}`),
|
|
310
332
|
].join('\n');
|
|
311
333
|
}
|
|
@@ -329,6 +351,7 @@ function hepanText(r) {
|
|
|
329
351
|
`年命纳音:${r.detail.nayin.a} / ${r.detail.nayin.b}(${r.detail.nayin.label})——${r.detail.nayin.text}`,
|
|
330
352
|
`吉凶象:吉 ${r.detail.tally.good} / 凶 ${r.detail.tally.bad}(${r.detail.tally.lean};分档只数象,总分以上面三维度为准)`,
|
|
331
353
|
] : []),
|
|
354
|
+
...tripleText(r.triple),
|
|
332
355
|
...r.notes.map((n) => `※ ${n}`),
|
|
333
356
|
].join('\n');
|
|
334
357
|
}
|
|
@@ -559,11 +582,14 @@ function shadowParams(args, result) {
|
|
|
559
582
|
};
|
|
560
583
|
}
|
|
561
584
|
if (system === 'hepan') {
|
|
562
|
-
|
|
585
|
+
const params = {
|
|
563
586
|
chart: args.chart === 'ziwei' ? 'ziwei' : 'bazi',
|
|
564
587
|
a: shadowPerson({ ...args, datetime: args.datetime }),
|
|
565
588
|
b: shadowPerson(args.partner || {}),
|
|
566
589
|
};
|
|
590
|
+
// 第三方进指纹:同一对加上不同的第三人,是另一组盘
|
|
591
|
+
if (args.partner2) params.c = shadowPerson(args.partner2);
|
|
592
|
+
return params;
|
|
567
593
|
}
|
|
568
594
|
|
|
569
595
|
// 其余体系:只剔除解析/附加模块参数,其余原样归一化
|
|
@@ -720,6 +746,11 @@ export function compute(input = {}) {
|
|
|
720
746
|
ignored: rev.ignored,
|
|
721
747
|
};
|
|
722
748
|
}
|
|
749
|
+
// partner2: null 视同未传:先归一化再排盘,否则同一对盘会因为显式 null 多出一个句柄
|
|
750
|
+
if (args.partner2 === null) {
|
|
751
|
+
args = { ...args };
|
|
752
|
+
delete args.partner2;
|
|
753
|
+
}
|
|
723
754
|
const r = jsonSafe(computeRaw(args));
|
|
724
755
|
if (revision) r.revision = revision;
|
|
725
756
|
if (r && r.system === 'bazi') {
|
|
@@ -901,11 +932,12 @@ export function caliberCompare(args = {}, opts = {}) {
|
|
|
901
932
|
const alt = sw.alt(current);
|
|
902
933
|
let diffs = [];
|
|
903
934
|
let error = '';
|
|
935
|
+
let cur = null;
|
|
936
|
+
let altRes = null;
|
|
904
937
|
try {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
);
|
|
938
|
+
cur = compute({ ...base, [sw.key]: current });
|
|
939
|
+
altRes = compute({ ...base, [sw.key]: alt });
|
|
940
|
+
diffs = diffObjects(cur, altRes);
|
|
909
941
|
} catch (e) {
|
|
910
942
|
error = (e && e.message) || String(e);
|
|
911
943
|
}
|
|
@@ -933,6 +965,7 @@ export function caliberCompare(args = {}, opts = {}) {
|
|
|
933
965
|
altLabel: sw.label(alt),
|
|
934
966
|
total: diffs.length,
|
|
935
967
|
summary: error ? '' : summarize(diffs),
|
|
968
|
+
views: error ? [] : viewRows(system, cur, altRes),
|
|
936
969
|
roots,
|
|
937
970
|
categories,
|
|
938
971
|
error,
|
|
@@ -1045,31 +1078,42 @@ function computeRaw(args = {}) {
|
|
|
1045
1078
|
if (!partner.datetime) {
|
|
1046
1079
|
throw fail('E_PARTNER', '缺少 partner.datetime(对方的公历出生时间),例如 partner: {"datetime":"1992-03-03T10:00","gender":"female"}');
|
|
1047
1080
|
}
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1081
|
+
const partner2 = args.partner2;
|
|
1082
|
+
if (partner2 !== undefined && partner2 !== null) {
|
|
1083
|
+
if (typeof partner2 !== 'object' || Array.isArray(partner2)) {
|
|
1084
|
+
throw fail('E_PARTNER', 'partner2 需要 { datetime, gender, address? };不想看三方就整段省略(null 视同未传)');
|
|
1085
|
+
}
|
|
1086
|
+
if (!partner2.datetime) {
|
|
1087
|
+
throw fail('E_PARTNER', '缺少 partner2.datetime(第三方的公历出生时间),例如 partner2: {"datetime":"1988-09-09T08:00","gender":"male"}');
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1050
1090
|
const chart = args.chart === 'ziwei' ? 'ziwei' : 'bazi';
|
|
1051
1091
|
// 性别决定双方大运/大限顺逆,两边都不能用默认值
|
|
1052
|
-
const
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
gender: requireGender(partner.gender, '对方'),
|
|
1065
|
-
trueSolar: partner.trueSolar,
|
|
1066
|
-
lateZi: partner.lateZi,
|
|
1067
|
-
dst: partner.dst !== false,
|
|
1068
|
-
address: typeof partner.address === 'string' ? partner.address : undefined,
|
|
1069
|
-
longitude: typeof partner.longitude === 'number' ? partner.longitude : undefined,
|
|
1070
|
-
geo: partner.geo && typeof partner.geo === 'object' ? partner.geo : undefined,
|
|
1092
|
+
const sideOf = (src, who) => {
|
|
1093
|
+
const dt = parseDateTime(src.datetime);
|
|
1094
|
+
return {
|
|
1095
|
+
...dt,
|
|
1096
|
+
gender: requireGender(src.gender, who),
|
|
1097
|
+
trueSolar: src.trueSolar,
|
|
1098
|
+
lateZi: src.lateZi,
|
|
1099
|
+
dst: src.dst !== false,
|
|
1100
|
+
address: typeof src.address === 'string' ? src.address : undefined,
|
|
1101
|
+
longitude: typeof src.longitude === 'number' ? src.longitude : undefined,
|
|
1102
|
+
geo: src.geo && typeof src.geo === 'object' ? src.geo : undefined,
|
|
1103
|
+
};
|
|
1071
1104
|
};
|
|
1072
|
-
const
|
|
1105
|
+
const sideA = sideOf(args, '你(主方)');
|
|
1106
|
+
const sideB = sideOf(partner, '对方');
|
|
1107
|
+
const build = (x, y) => (chart === 'ziwei' ? buildZiweiHepan({ a: x, b: y }) : buildHepan({ a: x, b: y }));
|
|
1108
|
+
const result = build(sideA, sideB);
|
|
1109
|
+
if (partner2) {
|
|
1110
|
+
const sideC = sideOf(partner2, '第三方');
|
|
1111
|
+
result.triple = tripleOf([
|
|
1112
|
+
{ key: 'a-b', a: '你', b: '对方', result },
|
|
1113
|
+
{ key: 'a-c', a: '你', b: '第三方', result: build(sideA, sideC) },
|
|
1114
|
+
{ key: 'b-c', a: '对方', b: '第三方', result: build(sideB, sideC) },
|
|
1115
|
+
]);
|
|
1116
|
+
}
|
|
1073
1117
|
return { ...result, summary: hepanText(result) };
|
|
1074
1118
|
}
|
|
1075
1119
|
if (system === 'meihua') {
|
|
@@ -1156,16 +1200,23 @@ function computeRaw(args = {}) {
|
|
|
1156
1200
|
return { ...result, summary: almanacText(result) };
|
|
1157
1201
|
}
|
|
1158
1202
|
if (system === 'zeri') {
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1203
|
+
const candMode = args.candidates !== undefined && args.candidates !== null;
|
|
1204
|
+
// startDate 必须显式:择日要「从哪天起看」,缺了不能拿本机今天静默代填;候选日模式改用 candidates
|
|
1205
|
+
if (!candMode && (typeof args.startDate !== 'string' || !args.startDate.trim())) {
|
|
1206
|
+
throw fail('E_INPUT', '择日需要 startDate(公历 YYYY-MM-DD,起算日);可另给 days(1–60,默认 30)与 shengXiao(当事人属相)。只想比几天,改给 candidates: ["2026-12-01","2026-12-08"]');
|
|
1207
|
+
}
|
|
1208
|
+
let result;
|
|
1209
|
+
try {
|
|
1210
|
+
result = buildZeri({
|
|
1211
|
+
task: args.task,
|
|
1212
|
+
startDate: args.startDate,
|
|
1213
|
+
days: args.days,
|
|
1214
|
+
shengXiao: args.shengXiao,
|
|
1215
|
+
candidates: args.candidates,
|
|
1216
|
+
});
|
|
1217
|
+
} catch (e) {
|
|
1218
|
+
throw fail('E_INPUT', (e && e.message) || String(e));
|
|
1162
1219
|
}
|
|
1163
|
-
const result = buildZeri({
|
|
1164
|
-
task: args.task,
|
|
1165
|
-
startDate: args.startDate,
|
|
1166
|
-
days: args.days,
|
|
1167
|
-
shengXiao: args.shengXiao,
|
|
1168
|
-
});
|
|
1169
1220
|
return { ...result, summary: zeriText(result) };
|
|
1170
1221
|
}
|
|
1171
1222
|
if (system === 'chenggu') {
|
|
@@ -1355,16 +1406,27 @@ function almanacText(r) {
|
|
|
1355
1406
|
|
|
1356
1407
|
/** 择日文本 */
|
|
1357
1408
|
function zeriText(r) {
|
|
1358
|
-
const
|
|
1359
|
-
const
|
|
1409
|
+
const cand = r.compare && r.compare.mode === 'candidates';
|
|
1410
|
+
const head = cand
|
|
1411
|
+
? `【择日·${r.meta.task}】候选 ${r.meta.days} 天:${r.meta.candidates.join('、')}${r.meta.shengXiao ? ` 当事人属${r.meta.shengXiao}` : '(未给属相,未做冲煞排除)'}`
|
|
1412
|
+
: `【择日·${r.meta.task}】${r.meta.startDate} 起 ${r.meta.days} 天${r.meta.shengXiao ? ` 当事人属${r.meta.shengXiao}` : '(未给属相,未做冲煞排除)'}`;
|
|
1413
|
+
const top = r.days.slice().sort((a, b) => b.score - a.score).slice(0, cand ? 12 : 5)
|
|
1360
1414
|
.map((d) => `· ${d.date} ${d.weekday} ${d.verdict}(${d.score}分) 宜${d.yi.slice(0, 3).join('/')} ${d.reasons.join(';') || '无特别加减分'}`);
|
|
1415
|
+
const bestLine = cand
|
|
1416
|
+
? (r.compare.best
|
|
1417
|
+
? `这一组里最优:${r.compare.best.date}(${r.compare.best.score}分,${r.compare.best.verdict})`
|
|
1418
|
+
+ (r.compare.best.ties.length > 1 ? `;同分:${r.compare.best.ties.filter((d) => d !== r.compare.best.date).join('、')}` : '')
|
|
1419
|
+
: '这一组都因冲属相被排除,没有可用的日子')
|
|
1420
|
+
: `推荐日:${r.best.length ? r.best.join('、') : '本期无(都不够推荐分)'}`;
|
|
1361
1421
|
return [
|
|
1362
1422
|
head,
|
|
1363
|
-
|
|
1423
|
+
bestLine,
|
|
1424
|
+
`推荐日:${r.best.length ? r.best.join('、') : '无'}`,
|
|
1364
1425
|
`可用日:${r.usable.length ? r.usable.join('、') : '无'}`,
|
|
1365
1426
|
`回避日:${r.avoid.length ? r.avoid.slice(0, 6).join('、') : '无'}`,
|
|
1366
|
-
'逐日排序:',
|
|
1427
|
+
cand ? '候选日逐日:' : '逐日排序:',
|
|
1367
1428
|
...top,
|
|
1429
|
+
...(cand ? [`比较口径:${r.compare.note}`] : []),
|
|
1368
1430
|
`口径:${r.meta.scope}`,
|
|
1369
1431
|
].join('\n');
|
|
1370
1432
|
}
|
|
@@ -1614,7 +1676,11 @@ export function renderText(result) {
|
|
|
1614
1676
|
+ c.switches.map((s) => {
|
|
1615
1677
|
if (s.error) return `· ${s.title}:未能对照(${s.error})`;
|
|
1616
1678
|
if (!s.total) return `· ${s.title}:${s.currentLabel} → ${s.altLabel},本盘无变化`;
|
|
1617
|
-
|
|
1679
|
+
const changed = (Array.isArray(s.views) ? s.views : []).filter((v) => v.changed);
|
|
1680
|
+
const side = changed.length
|
|
1681
|
+
? `\n 并排:${changed.map((v) => `${v.label} ${v.current} → ${v.alt}`).join(';')}`
|
|
1682
|
+
: '';
|
|
1683
|
+
return `· ${s.title}:${s.currentLabel} → ${s.altLabel}\n ${s.summary}${side}`;
|
|
1618
1684
|
}).join('\n'));
|
|
1619
1685
|
}
|
|
1620
1686
|
if (result.followup) {
|
|
@@ -1648,6 +1714,8 @@ export { buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buil
|
|
|
1648
1714
|
export { buildTrend, buildFengshui, buildName };
|
|
1649
1715
|
export { buildTrace, traceMarkdown };
|
|
1650
1716
|
export { encodeHandle, decodeHandle, resolveHandle };
|
|
1717
|
+
// C3 对话桥替代:深链编解码、表单还原、三档复制包(面板与独立页共用一份)
|
|
1718
|
+
export { askLink, parseAskLink, formOf, restNote, askPackages };
|
|
1651
1719
|
|
|
1652
1720
|
|
|
1653
1721
|
|
|
@@ -25,7 +25,8 @@ export const KNOWLEDGE = [
|
|
|
25
25
|
system: 'bazi', dims: ['overall', 'career'],
|
|
26
26
|
gist: '天干是露在外面的样子,地支是藏在地下的根。',
|
|
27
27
|
detail: '同一个五行,透在天干叫「显」,扎在地支叫「有根」。只有天干没有地支,是看着有、使不上劲;只有地支不通天干,是有实力、不显眼。判断一个人能不能扛事,看的就是根有多深。',
|
|
28
|
-
source: '
|
|
28
|
+
source: '《滴天髓·干支总论》「天全一气,不可使地德莫之载;地全三物,不可使天道莫之容」',
|
|
29
|
+
note: '常被署给《滴天髓》的「地支所藏之干,本静以待用,透出干头,则显其用矣。故干以通根为美,支以透出为贵」,出自《子平真诠》卷一论十干十二支的注文——滴天髓底本与沈孝瞻原文里都查不到这句,注文自己引的才是上面那句滴天髓。所以本卡引可核的原文,注文只作说明。',
|
|
29
30
|
status: 'settled',
|
|
30
31
|
},
|
|
31
32
|
{
|
|
@@ -372,7 +373,7 @@ export const KNOWLEDGE = [
|
|
|
372
373
|
detail: '进神退神本身只说明这一爻的向外趋势:用神化进为得力,忌神化进则为患加剧;用神化退是力衰,忌神化退反而是解脱。传统还要看它在本月令衰旺、有没有日辰生扶,空亡或受克时进者未必能进。本插件把进退与爻位标出来,再按月建五态给一档力重——得令则进得动、退得慢,失令则进得虚、退得实,月破压过一切;只给档位,不折成加权分数,吉凶仍落在用神与忌神那一层判。',
|
|
373
374
|
source: '《增删卜易》进神退神章、用神章',
|
|
374
375
|
status: 'variant',
|
|
375
|
-
note: '
|
|
376
|
+
note: '土之进退次序各家说法不完全一致,有以丑→辰→未→戌为进、也有只取辰戌丑未相对者;本插件按丑辰未戌成环处理,并用《增删卜易》卦例中「未土化戌土为进」「戌土化未土为退」对拍。喜忌分档的出处是《增删卜易》卷二·進神退神章第二十九:「所喜者宜於化進,所忌者宜化退神」;把「喜/忌」具体落到用神/忌神两档,是本插件的引申。',
|
|
376
377
|
},
|
|
377
378
|
|
|
378
379
|
// ── 梅花 / 六壬 / 奇门 / 塔罗 ───────────────────────────
|
package/engine/trace.js
CHANGED
|
@@ -56,7 +56,7 @@ function liuyaoTrace(r, opts = {}) {
|
|
|
56
56
|
['变卦', bian ? `${text(bian.name)}(上${text(bian.upper)}·下${text(bian.lower)})` : '无'],
|
|
57
57
|
],
|
|
58
58
|
lines.map((l) => `${l.position}爻 ${text(l.ganzhi)}${text(l.element)}`).join('|'),
|
|
59
|
-
'
|
|
59
|
+
'京房纳甲(八宫纳甲表);实现:engine/liuyao.js · NAJIA(规则表,本仓未录入古籍章页)',
|
|
60
60
|
);
|
|
61
61
|
|
|
62
62
|
const liuqin = step(
|
|
@@ -69,7 +69,7 @@ function liuyaoTrace(r, opts = {}) {
|
|
|
69
69
|
['日干起六神', `${text(r.dayGanZhi && r.dayGanZhi.stem)}日`],
|
|
70
70
|
],
|
|
71
71
|
lines.map((l) => `${l.position}爻 ${text(l.liuqin)}(${text(l.element)})`).join('|'),
|
|
72
|
-
'
|
|
72
|
+
'五行生克定六亲;取用可对读《增删卜易》卷一·用神章第八;实现:engine/liuyao.js · liuqin()',
|
|
73
73
|
);
|
|
74
74
|
|
|
75
75
|
const shiying = step(
|
|
@@ -83,7 +83,7 @@ function liuyaoTrace(r, opts = {}) {
|
|
|
83
83
|
],
|
|
84
84
|
`${text(ben.shi)}爻${shi ? ` ${text(shi.liuqin)}·${text(shi.ganzhi)}${text(shi.element)}` : ''}为世,`
|
|
85
85
|
+ `${text(ben.ying)}爻${ying ? ` ${text(ying.liuqin)}·${text(ying.ganzhi)}${text(ying.element)}` : ''}为应`,
|
|
86
|
-
'
|
|
86
|
+
'八宫世应诀(世爻序与应爻隔三位);实现:engine/liuyao.js · SHI_POSITION(通行动诀,本仓未录入古籍章页)',
|
|
87
87
|
);
|
|
88
88
|
|
|
89
89
|
let fushen;
|
|
@@ -97,7 +97,7 @@ function liuyaoTrace(r, opts = {}) {
|
|
|
97
97
|
'用神不上卦时,回本宫首卦的同位取伏神;飞伏之间只判生克与助压。',
|
|
98
98
|
[['用神', ug && ug.ask ? ug.ask : '未取']],
|
|
99
99
|
`${why};本层不适用。`,
|
|
100
|
-
'engine/liuyao.js · yongshenOf()',
|
|
100
|
+
'取伏之法参《增删卜易》卷二·飛伏神章第二十八;实现:engine/liuyao.js · yongshenOf()',
|
|
101
101
|
);
|
|
102
102
|
} else if (ug.missing) {
|
|
103
103
|
const hidden = (ug.fushen || []).map((f) => {
|
|
@@ -117,7 +117,7 @@ function liuyaoTrace(r, opts = {}) {
|
|
|
117
117
|
['月建 / 日辰', `${text(month && month.branch)} / ${text(day && day.branch)}`],
|
|
118
118
|
],
|
|
119
119
|
`${hidden || '本卦无此六亲,首卦同位也未取到伏神'}${access ? `;出伏:${access}` : ''}`,
|
|
120
|
-
'
|
|
120
|
+
'《增删卜易》卷二·飛伏神章第二十八(用神不現,尋得伏神而遇生扶有用);实现:engine/liuyao.js · fushenAccess()',
|
|
121
121
|
);
|
|
122
122
|
} else {
|
|
123
123
|
fushen = step(
|
|
@@ -129,7 +129,7 @@ function liuyaoTrace(r, opts = {}) {
|
|
|
129
129
|
['在位', list((ug.found || []).map((l) => `${l.position}爻`))],
|
|
130
130
|
],
|
|
131
131
|
`用神 ${ug.liuqin} 已在 ${list((ug.found || []).map((l) => `${l.position}爻`))},无需伏神。`,
|
|
132
|
-
'engine/liuyao.js · yongshenOf()',
|
|
132
|
+
'取伏之法参《增删卜易》卷二·飛伏神章第二十八;实现:engine/liuyao.js · yongshenOf()',
|
|
133
133
|
);
|
|
134
134
|
}
|
|
135
135
|
|
|
@@ -150,7 +150,7 @@ function liuyaoTrace(r, opts = {}) {
|
|
|
150
150
|
useStrength ? `用神:${useStrength}${us.labels && us.labels.length ? `(${us.labels.join('、')})` : ''}` : '用神:未取,只看全卦',
|
|
151
151
|
hs && hs.labels && hs.labels.length ? `全卦:${hs.labels.join('、')}` : '',
|
|
152
152
|
].filter(Boolean).join(';'),
|
|
153
|
-
'
|
|
153
|
+
'《增删卜易》卷一·月將章第十六、日辰章第十七;实现:engine/liuyao.js · yongshenStrength / hexagramStrength',
|
|
154
154
|
);
|
|
155
155
|
|
|
156
156
|
return [najia, liuqin, shiying, fushen, wangsheng];
|
|
@@ -179,7 +179,7 @@ function baziTrace(r) {
|
|
|
179
179
|
['虚透', list(parts.virtualHelpers, '无')],
|
|
180
180
|
],
|
|
181
181
|
`${text(s.level)}(${text(s.score)} 分):${text(s.detail)}`,
|
|
182
|
-
'engine/bazi.js ·
|
|
182
|
+
'本仓量化规则(月令权重 3/2/1/0.5/0、藏干通根、三会/三合/六合折根、虚透减半;非古籍定数);实现:engine/bazi.js · 旺衰量化',
|
|
183
183
|
);
|
|
184
184
|
|
|
185
185
|
const primaryName = text(frame.primaryName || (primary && primary.name), '未取格局');
|
|
@@ -211,7 +211,7 @@ function baziTrace(r) {
|
|
|
211
211
|
['调候', tiaohou && tiaohou.kind ? `${text(tiaohou.kind)}${need && need.element ? ` → ${text(need.element)}` : ''}` : '—'],
|
|
212
212
|
],
|
|
213
213
|
`${resultParts}`,
|
|
214
|
-
'
|
|
214
|
+
'《子平真诠》八、论用神(专求月令);调候参《穷通宝鉴》五行总论;实现:engine/geju.js · yongshenOf()',
|
|
215
215
|
);
|
|
216
216
|
|
|
217
217
|
const p = r.palaces && typeof r.palaces === 'object' ? r.palaces : {};
|
|
@@ -228,7 +228,7 @@ function baziTrace(r) {
|
|
|
228
228
|
['命宫 / 身宫', `${text(p.minggong && p.minggong.ganzhi)} / ${text(p.shengong && p.shengong.ganzhi)}`],
|
|
229
229
|
],
|
|
230
230
|
`胎元 ${text(p.taiyuan.ganzhi)};${p.taixi ? `胎息 ${text(p.taixi.ganzhi)};` : ''}命宫 ${text(p.minggong && p.minggong.ganzhi)};身宫 ${text(p.shengong && p.shengong.ganzhi)}。四宫是辅助坐标,不单独折吉凶。`,
|
|
231
|
-
'Tyme
|
|
231
|
+
'Tyme 1.5.4 四宫口径(与 ziwei.pub 704 组日期对拍);本仓未直接照录古籍章页;实现:engine/bazi.js · palaces',
|
|
232
232
|
) : null;
|
|
233
233
|
|
|
234
234
|
return [strength, geju, ...(palaces ? [palaces] : [])];
|
|
@@ -251,7 +251,7 @@ function ziweiTrace(r) {
|
|
|
251
251
|
['命中数', `${patterns.length} / ${total}`],
|
|
252
252
|
],
|
|
253
253
|
patterns.length ? `命中 ${patterns.length} 条:${hit}` : '未命中已收录的格局条件(不表示命盘无结构,只是不在已收录清单内)。',
|
|
254
|
-
'
|
|
254
|
+
'《紫微斗数全书》卷三·论人命入格、谈星要论;实现:engine/ziwei.js · detectPatterns()',
|
|
255
255
|
)];
|
|
256
256
|
}
|
|
257
257
|
|
|
@@ -277,7 +277,7 @@ function qimenTrace(r, opts = {}) {
|
|
|
277
277
|
['空亡 / 驿马', `${list(r.kongWang)} / ${text(ma.zhi)}${ma.gong ? `(${ma.gong}宫)` : ''}`],
|
|
278
278
|
],
|
|
279
279
|
palaces.map((p) => `${p.palace}宫 天${text(p.tianPan)}·${text(p.star)}·${text(p.gate)}·${text(p.god)}`).join('|') || '无九宫数据',
|
|
280
|
-
'engine/qimen.js · buildQimen()',
|
|
280
|
+
'《奇门遁甲统宗》卷一·奇门秘诀总赋(阴阳二遁、五日换元、超神接气);实现:engine/qimen.js · buildQimen()',
|
|
281
281
|
);
|
|
282
282
|
|
|
283
283
|
const ys = qimenYongshen(r, opts.direction);
|
|
@@ -298,7 +298,7 @@ function qimenTrace(r, opts = {}) {
|
|
|
298
298
|
? `${ys.note};${found.map((x) => `${x.key} 落 ${x.palace.palace}宫(${text(x.palace.star)}·${text(x.palace.gate)}·${text(x.palace.god)})`).join(',')}`
|
|
299
299
|
+ (missing.length ? `;${missing.join('、')} 未上盘` : '')
|
|
300
300
|
: `${ys.label}的用神均未上盘,属未决项;先按值符落宫参照。`,
|
|
301
|
-
'
|
|
301
|
+
'本仓用神表(按所问之事取用,非古籍原文);实现:engine/qimen-interpret.js · qimenYongshen()',
|
|
302
302
|
);
|
|
303
303
|
|
|
304
304
|
const order = ['旺', '相', '休', '囚', '死'];
|
|
@@ -315,7 +315,7 @@ function qimenTrace(r, opts = {}) {
|
|
|
315
315
|
['天盘干', stateLine(states.stem)],
|
|
316
316
|
],
|
|
317
317
|
`门:${stateLine(states.gate)};星:${stateLine(states.star)};天盘干:${stateLine(states.stem)}`,
|
|
318
|
-
'
|
|
318
|
+
'《奇门遁甲统宗》卷三(旺相休囚);实现:engine/qimen.js · groupByState()',
|
|
319
319
|
);
|
|
320
320
|
|
|
321
321
|
const forced = [];
|
|
@@ -354,7 +354,7 @@ function qimenTrace(r, opts = {}) {
|
|
|
354
354
|
['空亡', kongCells.join('、') || '无'],
|
|
355
355
|
],
|
|
356
356
|
`门迫 ${forced.length} 处、宫制门 ${controlled.length} 处;天盘干与宫:${stemLine};击刑 ${jiXing.length} 处、三奇入墓 ${ruMu.length} 处、六仪入墓 ${liuYiRuMu.length} 处、落空 ${kongCells.length} 宫。十干克应:${ganying || '—'}。`,
|
|
357
|
-
'
|
|
357
|
+
'《奇门遁甲统宗》卷二(八门迫制)、卷十一·玄机赋(中)(六仪击刑、三奇入墓);十干克应为本仓表;实现:engine/qimen.js · gatePalaceRelation() / stemPalaceRelation()、engine/qimen-ganying.js',
|
|
358
358
|
);
|
|
359
359
|
|
|
360
360
|
return [facts, yongshen, wangshuai, relations];
|
|
@@ -380,7 +380,7 @@ function daliurenTrace(r) {
|
|
|
380
380
|
['昼夜 / 贵人', `${text(r.dayNight)} / ${text(gr.zhi)}(${gr.reverse ? '逆布' : '顺布'})`],
|
|
381
381
|
],
|
|
382
382
|
pan.map((p) => `${p.di}→${p.tian}${p.jiang ? `(${text(p.jiang)})` : ''}`).join('|') || '无天地盘数据',
|
|
383
|
-
'
|
|
383
|
+
'《大六壬大全》卷二·神将释(月将为十二支神,登明为首逆布);加时布盘属通行口诀,未标卷次;实现:engine/daliuren.js · tianDiPan()',
|
|
384
384
|
);
|
|
385
385
|
|
|
386
386
|
const sike = step(
|
|
@@ -393,7 +393,7 @@ function daliurenTrace(r) {
|
|
|
393
393
|
['四课', ke.map((k) => `${k.position}课 ${text(k.shang)}上${text(k.xia)}下`).join(';') || '—'],
|
|
394
394
|
],
|
|
395
395
|
ke.map((k) => `${k.position}课 ${text(k.shang)}上${text(k.xia)}下${k.jiang ? `·${text(k.jiang)}` : ''}:${text(k.relation)}`).join(';') || '无四课数据',
|
|
396
|
-
'engine/daliuren.js · siKe()',
|
|
396
|
+
'《大六壬大全》卷一·起例(十干寄宫);四课余下三课按通行口诀;实现:engine/daliuren.js · siKe()',
|
|
397
397
|
);
|
|
398
398
|
|
|
399
399
|
const chuanLine = (c) => (c
|
|
@@ -410,7 +410,7 @@ function daliurenTrace(r) {
|
|
|
410
410
|
['末传', chuanLine(sc.mo)],
|
|
411
411
|
],
|
|
412
412
|
`${chuanLine(sc.chu)} → ${chuanLine(sc.zhong)} → ${chuanLine(sc.mo)}`,
|
|
413
|
-
'engine/daliuren.js · chuan()',
|
|
413
|
+
'《大六壬大全》卷一·起例(贼克法为首法,比用、涉害、遥克、昴星、八专、伏吟、返吟依次列后);实现:engine/daliuren.js · chuan()',
|
|
414
414
|
);
|
|
415
415
|
|
|
416
416
|
return [tiandipan, sike, sanchuan];
|
package/engine/zeri.js
CHANGED
|
@@ -81,23 +81,68 @@ const VERDICT = (score, ctx) => {
|
|
|
81
81
|
* @param {{task:string, startDate:string, days?:number, shengXiao?:string}} input
|
|
82
82
|
* startDate 必填(公历 YYYY-MM-DD),避免引擎在无时钟环境下静默取「今天」。
|
|
83
83
|
*/
|
|
84
|
+
/** 严格解析公历日期:2 月 30 日这类不存在的日子直接判非法,不滚到下个月 */
|
|
85
|
+
function parseYmd(raw) {
|
|
86
|
+
const m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(String(raw || '').trim());
|
|
87
|
+
if (!m) return null;
|
|
88
|
+
const year = Number(m[1]);
|
|
89
|
+
const month = Number(m[2]);
|
|
90
|
+
const day = Number(m[3]);
|
|
91
|
+
if (month < 1 || month > 12 || day < 1) return null;
|
|
92
|
+
const back = fromJDN(toJDN(year, month, day));
|
|
93
|
+
return back.year === year && back.month === month && back.day === day ? { year, month, day } : null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const ymd = (p) => `${p.year}-${String(p.month).padStart(2, '0')}-${String(p.day).padStart(2, '0')}`;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 择日主函数。
|
|
100
|
+
* @param {{task:string, startDate:string, days?:number, shengXiao?:string,
|
|
101
|
+
* candidates?:string[]}} input
|
|
102
|
+
* startDate 必填(公历 YYYY-MM-DD),避免引擎在无时钟环境下静默取「今天」。
|
|
103
|
+
* candidates 给了就只比这几个候选日(2–12 个,去重、保持输入顺序),startDate 与 days 不参与。
|
|
104
|
+
*/
|
|
84
105
|
export function buildZeri(input) {
|
|
85
106
|
const task = input.task;
|
|
86
107
|
if (!TASKS[task]) throw new Error(`不支持的事项「${task}」。支持:${Object.keys(TASKS).join('、')}`);
|
|
87
|
-
const m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(String(input.startDate || '').trim());
|
|
88
|
-
if (!m) throw new Error('择日需要 startDate(公历 YYYY-MM-DD)——请向用户询问起算日,不要代填');
|
|
89
|
-
const start = { year: Number(m[1]), month: Number(m[2]), day: Number(m[3]) };
|
|
90
|
-
const days = Math.max(1, Math.min(60, Number.isInteger(input.days) ? input.days : 30));
|
|
91
108
|
const shengXiaoRaw = typeof input.shengXiao === 'string' ? input.shengXiao.trim() : '';
|
|
92
109
|
const shengXiao = shengXiaoRaw || null;
|
|
93
110
|
if (shengXiao && !SHENGXIAO.includes(shengXiao)) throw new Error(`shengXiao 须为生肖名:${SHENGXIAO.join('、')}`);
|
|
94
111
|
|
|
112
|
+
// 候选日模式:只比用户给的这几天,不再按区间扫
|
|
113
|
+
let candidates = null;
|
|
114
|
+
if (input.candidates !== undefined && input.candidates !== null) {
|
|
115
|
+
if (!Array.isArray(input.candidates)) {
|
|
116
|
+
throw new Error('candidates 须为日期数组,例如 ["2026-12-01","2026-12-08","2026-12-15"]');
|
|
117
|
+
}
|
|
118
|
+
if (input.candidates.length < 2) throw new Error('candidates 至少给 2 个候选日;只想看一天请用 startDate + days: 1');
|
|
119
|
+
if (input.candidates.length > 12) throw new Error('candidates 最多 12 个候选日;更多请用 startDate + days 扫区间');
|
|
120
|
+
const seen = new Set();
|
|
121
|
+
candidates = [];
|
|
122
|
+
for (const raw of input.candidates) {
|
|
123
|
+
const p = parseYmd(raw);
|
|
124
|
+
if (!p) throw new Error(`候选日不是真实存在的公历日期:「${raw}」,请用 2026-12-01 这种格式`);
|
|
125
|
+
const key = ymd(p);
|
|
126
|
+
if (seen.has(key)) continue;
|
|
127
|
+
seen.add(key);
|
|
128
|
+
candidates.push(p);
|
|
129
|
+
}
|
|
130
|
+
if (candidates.length < 2) throw new Error('候选日去重后不足 2 天;至少要两个不同的日子才谈得上比较');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let start = null;
|
|
134
|
+
let days = 0;
|
|
135
|
+
if (!candidates) {
|
|
136
|
+
const m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(String(input.startDate || '').trim());
|
|
137
|
+
if (!m) throw new Error('择日需要 startDate(公历 YYYY-MM-DD)——请向用户询问起算日,不要代填');
|
|
138
|
+
start = { year: Number(m[1]), month: Number(m[2]), day: Number(m[3]) };
|
|
139
|
+
days = Math.max(1, Math.min(60, Number.isInteger(input.days) ? input.days : 30));
|
|
140
|
+
}
|
|
141
|
+
|
|
95
142
|
const spec = TASKS[task];
|
|
96
143
|
const zhixingSet = ZHIXING_FAVOR[spec.category];
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
for (let i = 0; i < days; i++) {
|
|
100
|
-
const p = fromJDN(startJdn + i);
|
|
144
|
+
|
|
145
|
+
const makeRow = (p) => {
|
|
101
146
|
const a = buildAlmanac(p);
|
|
102
147
|
let score = 0;
|
|
103
148
|
const reasons = [];
|
|
@@ -114,7 +159,7 @@ export function buildZeri(input) {
|
|
|
114
159
|
if (a.zhiXing === '危' && spec.category !== 'travel' && spec.category !== 'worship') { score -= 1; reasons.push('危日(-1)'); }
|
|
115
160
|
|
|
116
161
|
const v = VERDICT(score, { chongSelf, jiHit });
|
|
117
|
-
|
|
162
|
+
return {
|
|
118
163
|
date: a.meta.date,
|
|
119
164
|
weekday: a.meta.weekday,
|
|
120
165
|
lunar: a.lunar.text,
|
|
@@ -128,17 +173,47 @@ export function buildZeri(input) {
|
|
|
128
173
|
verdict: v.verdict,
|
|
129
174
|
verdictText: v.text,
|
|
130
175
|
...(v.excluded ? { excluded: true } : {}),
|
|
131
|
-
}
|
|
132
|
-
}
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const list = candidates
|
|
180
|
+
? candidates.map(makeRow)
|
|
181
|
+
: Array.from({ length: days }, (_, i) => makeRow(fromJDN(toJDN(start.year, start.month, start.day) + i)));
|
|
133
182
|
|
|
134
183
|
const ranked = list.slice().sort((x, y) => y.score - x.score || (x.date < y.date ? -1 : 1));
|
|
184
|
+
const startDate = candidates
|
|
185
|
+
? candidates.slice().sort((x, y) => (ymd(x) < ymd(y) ? -1 : 1)).map(ymd)[0]
|
|
186
|
+
: ymd(start);
|
|
187
|
+
|
|
188
|
+
// 候选日比较:只在这几天里比,给出最高分和同分者;不换算成「好多少」
|
|
189
|
+
let compare = null;
|
|
190
|
+
if (candidates) {
|
|
191
|
+
const pool = ranked.filter((d) => !d.excluded);
|
|
192
|
+
const top = pool[0] || null;
|
|
193
|
+
const scores = list.map((d) => d.score);
|
|
194
|
+
compare = {
|
|
195
|
+
mode: 'candidates',
|
|
196
|
+
count: list.length,
|
|
197
|
+
best: top ? {
|
|
198
|
+
date: top.date,
|
|
199
|
+
score: top.score,
|
|
200
|
+
verdict: top.verdict,
|
|
201
|
+
ties: pool.filter((d) => d.score === top.score).map((d) => d.date),
|
|
202
|
+
} : null,
|
|
203
|
+
spread: Math.max(...scores) - Math.min(...scores),
|
|
204
|
+
note: '候选日只在这几天里比:分数来自建除宜忌与冲煞,胜出只表示更合所问事项,不代表「好多少」。',
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
135
208
|
return {
|
|
136
209
|
system: 'zeri',
|
|
137
210
|
meta: {
|
|
138
211
|
task,
|
|
139
|
-
|
|
140
|
-
|
|
212
|
+
mode: candidates ? 'candidates' : 'range',
|
|
213
|
+
startDate,
|
|
214
|
+
days: list.length,
|
|
141
215
|
shengXiao,
|
|
216
|
+
...(candidates ? { candidates: candidates.map(ymd) } : {}),
|
|
142
217
|
scope: shengXiao
|
|
143
218
|
? `宜忌按建除简表;已给当事人属相(${shengXiao}),凡当日冲该属相径直排除。评分仅用于排序引导。`
|
|
144
219
|
: '宜忌按建除简表;未给当事人属相,未做冲属相排除。评分仅用于排序引导。',
|
|
@@ -147,6 +222,7 @@ export function buildZeri(input) {
|
|
|
147
222
|
usable: ranked.filter((d) => d.verdict === '可用' && !d.excluded).slice(0, 5).map((d) => d.date),
|
|
148
223
|
avoid: list.filter((d) => d.verdict === '回避').map((d) => `${d.date}(${d.reasons.join(';') || '综合减分'})`),
|
|
149
224
|
days: list,
|
|
225
|
+
...(compare ? { compare } : {}),
|
|
150
226
|
excludedCount: list.filter((d) => d.excluded).length,
|
|
151
227
|
sources: ['宜忌:建除十二神通行简表', '建除适配与冲煞:传统通行口径', '排序:宜忌加减分 + 属相排除(确定性)'],
|
|
152
228
|
disclaimer: '择日为传统黄历口径的本地计算,属民俗参考;评分只用于排序,不构成择日结论。',
|
package/index.js
CHANGED
|
@@ -230,11 +230,16 @@ export function apply(ctx) {
|
|
|
230
230
|
},
|
|
231
231
|
startDate: {
|
|
232
232
|
type: 'string',
|
|
233
|
-
description: '仅 zeri 使用:起算日(公历 YYYY-MM-DD
|
|
233
|
+
description: '仅 zeri 使用:起算日(公历 YYYY-MM-DD)。省略则由宿主补今天;给了 candidates 时不需要。',
|
|
234
234
|
},
|
|
235
235
|
days: {
|
|
236
236
|
type: 'number',
|
|
237
|
-
description: '仅 zeri 使用:往后考察天数,1–60,默认 30
|
|
237
|
+
description: '仅 zeri 使用:往后考察天数,1–60,默认 30;给了 candidates 时忽略。',
|
|
238
|
+
},
|
|
239
|
+
candidates: {
|
|
240
|
+
type: 'array',
|
|
241
|
+
items: { type: 'string' },
|
|
242
|
+
description: '仅 zeri 使用:候选日比较(2–12 个真实公历日期,如 ["2026-12-01","2026-12-08"])。给了就只比这几天,结果多一个 compare(这一组最优、同分者、分差)与逐日并排;不替代 startDate 扫区间。',
|
|
238
243
|
},
|
|
239
244
|
shengXiao: {
|
|
240
245
|
type: 'string',
|
|
@@ -330,6 +335,17 @@ export function apply(ctx) {
|
|
|
330
335
|
},
|
|
331
336
|
required: ['datetime', 'gender'],
|
|
332
337
|
},
|
|
338
|
+
partner2: {
|
|
339
|
+
type: 'object',
|
|
340
|
+
description: '三方合盘(可选):第三个人的出生信息,字段与 partner 相同。给了就多回 triple——你×对方、你×第三方、对方×第三方三对分数并列,不合成「三人总分」。仅 hepan 使用;null 与省略等价,不要传 null。',
|
|
341
|
+
properties: {
|
|
342
|
+
datetime: { type: 'string', description: '第三方公历本地时间,如 1988-09-09T08:00' },
|
|
343
|
+
gender: { type: 'string', enum: ['male', 'female'], description: '第三方性别' },
|
|
344
|
+
address: { type: 'string', description: '第三方出生地(省/市即可)' },
|
|
345
|
+
trueSolar: { type: 'boolean', description: '第三方是否启用真太阳时' },
|
|
346
|
+
},
|
|
347
|
+
required: ['datetime', 'gender'],
|
|
348
|
+
},
|
|
333
349
|
mode: {
|
|
334
350
|
type: 'string',
|
|
335
351
|
enum: ['time', 'number'],
|