dsh-metaphysics 0.14.2 → 0.14.3

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/client.js CHANGED
@@ -544,7 +544,7 @@ function resolveAddress(input) {
544
544
 
545
545
  const DETAIL = /(区|县|镇|乡|村|小区|街道|路|号|巷|弄|组|队)/;
546
546
 
547
- const USER_AGENT = 'dsh-metaphysics/0.14.2 (+https://github.com/xuanfu-web/dsh-metaphysics)';
547
+ const USER_AGENT = 'dsh-metaphysics/0.14.3 (+https://github.com/xuanfu-web/dsh-metaphysics)';
548
548
 
549
549
  async function onlineLookup(text, { timeoutMs = 2500 } = {}) {
550
550
  if (typeof fetch !== 'function') return null;
@@ -1798,7 +1798,7 @@ return { HIDDEN_STEMS, STEM_ELEMENT, BRANCH_ELEMENT, buildRelations, tenGod, nay
1798
1798
  })();
1799
1799
 
1800
1800
  __mods.liuyao = (function () {
1801
- const { STEMS, BRANCHES, toJDN, ganzhiName, dayGanzhiIndex } = __mods.calendar;
1801
+ const { STEMS, BRANCHES, toJDN, ganzhiName, dayGanzhiIndex, sexagenaryIndex } = __mods.calendar;
1802
1802
 
1803
1803
  const TRIGRAM_BITS = {
1804
1804
  乾: [1, 1, 1], 兑: [1, 1, 0], 离: [1, 0, 1], 震: [1, 0, 0],
@@ -1942,6 +1942,13 @@ function buildLiuyao(input = {}) {
1942
1942
 
1943
1943
  const liushenStart = LIUSHEN_START[dayGanZhi.stem] ?? 0;
1944
1944
 
1945
+ const dayIdx = sexagenaryIndex(STEMS.indexOf(dayGanZhi.stem), BRANCHES.indexOf(dayGanZhi.branch));
1946
+ const xun = dayIdx >= 0 ? Math.floor(dayIdx / 10) : -1;
1947
+ const xunKong = xun >= 0
1948
+ ? [BRANCHES[(10 - 2 * xun + 12) % 12], BRANCHES[(11 - 2 * xun + 12) % 12]]
1949
+ : [];
1950
+ const xunShou = xun >= 0 ? ganzhiName(xun * 10).name : '';
1951
+
1945
1952
  function decorate(hex, movingSet) {
1946
1953
  const rows = [];
1947
1954
  for (let i = 0; i < 6; i++) {
@@ -1987,6 +1994,8 @@ function buildLiuyao(input = {}) {
1987
1994
  movingPositions: moving.map((i) => i + 1),
1988
1995
  },
1989
1996
  dayGanZhi: { name: dayGanZhi.name, stem: dayGanZhi.stem, branch: dayGanZhi.branch },
1997
+ xunShou,
1998
+ xunKong,
1990
1999
  ben: {
1991
2000
  name: ben.name,
1992
2001
  upper: ben.upper,
@@ -3603,7 +3612,7 @@ function buildDaliuren(input) {
3603
3612
  };
3604
3613
  }
3605
3614
 
3606
- return { ZHI, GAN, TIAN_JIANG, JIANG_FULL, JIEQI_YUE_JIANG, calcShensha, buildDaliuren };
3615
+ return { ZHI, GAN, TIAN_JIANG, JIANG_FULL, JIEQI_YUE_JIANG, GAN_JI_GONG, calcShensha, buildDaliuren };
3607
3616
  })();
3608
3617
 
3609
3618
  __mods.hepan = (function () {
@@ -4939,6 +4948,55 @@ function baziInterpret(r) {
4939
4948
 
4940
4949
  const sections = [
4941
4950
  ...(cross.length ? [{ key: 'cross', label: '交叉判断', text: cross.join(' ') }] : []),
4951
+ {
4952
+ key: 'reasoning', label: '看盘顺序',
4953
+ text: [
4954
+ `① 先看月令:${st.parts && st.parts.season ? `${st.parts.season.branch}月,日主${dm.element}${st.parts.season.word}(${st.parts.season.weight})` : '月令已定'},得旺衰 ${level}(${pick(st, 'score', '—')} 分)。这一步定的是"你有没有力气"。`,
4955
+ `② 再定用神:身强则取泄、耗、制——喜${join(favor)}(${join(ys.favorRoles || [])}),忌${join(avoid)}(${join(ys.avoidRoles || [])})。这一步定的是"往哪走省力"。`,
4956
+ `③ 看格局:主格${primary}${(() => {
4957
+ const others = (Array.isArray(frame.geju) ? frame.geju : []).map((g) => g.name).filter((n) => n && n !== primary);
4958
+ return others.length ? `,另有${others.join('、')}` : '';
4959
+ })()}。格局与前两步同向时可信度更高;冲突时以用神为先。`,
4960
+ `④ 看大运:当前${pick(cur, 'ganzhi', '—')}(${curTier})${ln && ln.year ? `,${ln.year} 年流年${ln.ganzhi}为${lnTier}` : ''}。行运的吉凶不看名字,看它落在喜用还是忌神(下方「时间窗」给了理由)。`,
4961
+ `⑤ 落到维度:工作看喜用五行与十神权重;感情看配偶星与日支;健康看最旺与最弱的五行。五维度都只是这套推导的应用,不是另一套算法。`,
4962
+ ].join('\n'),
4963
+ },
4964
+ {
4965
+ key: 'timeline', label: '时间窗',
4966
+ text: (() => {
4967
+ const curSpan = cur && cur.startAge != null ? `${cur.startAge}–${cur.startAge + 9}岁,${curTier}${curLuck.reasons && curLuck.reasons.length ? `;${curLuck.reasons.join(',')}` : ''}` : '—';
4968
+ const nextTwo = (ahead || []).slice(0, 2).map((d) => `${d.ganzhi}(${d.startAge}–${d.startAge + 9}岁,${d.luck?.tier || '平'})`).join(' → ') || '—';
4969
+ const years = (r.liunian || []).slice(0, 5).map((l) => {
4970
+ const lk = isObj(l.luck) ? l.luck : {};
4971
+ const why = (lk.reasons || []).slice(0, 2).join(',');
4972
+ return `${l.year} ${l.ganzhi}·${l.stemTenGod || ''}·${lk.tier || '平'}${why ? `(${why})` : ''}`;
4973
+ }).join(';');
4974
+ return `当前大运:${pick(cur, 'ganzhi', '—')}(${curSpan})。后续两步:${nextTwo}。\n近五年流年:${years || '—'}。\n读法:大运管"这十年的大环境",流年管"今年的具体天气";两者打架时,以能否动到用神为准。`;
4975
+ })(),
4976
+ },
4977
+ {
4978
+ key: 'checks', label: '交叉校验',
4979
+ text: (() => {
4980
+ const favorScore = favor.reduce((sum, el) => sum + (Number(wx[el]) || 0), 0);
4981
+ const avoidScore = avoid.reduce((sum, el) => sum + (Number(wx[el]) || 0), 0);
4982
+ const out = [];
4983
+ out.push(favorScore < avoidScore
4984
+ ? `喜用合计 ${favorScore.toFixed?.(1) ?? favorScore} 低于忌神合计 ${avoidScore.toFixed?.(1) ?? avoidScore}:原局里"顺风的条件"偏少,靠行运与外部环境补更现实,别硬扛。`
4985
+ : `喜用合计 ${favorScore} 不低于忌神合计 ${avoidScore}:原局自带可用的条件,行运只是把它放大或压住。`);
4986
+ if (curTier && lnTier) {
4987
+ const good = ['吉', '大吉'];
4988
+ if (good.includes(curTier) && !good.includes(lnTier)) out.push('大运顺、当年逆:方向可以按大运走,具体动作挑流年的顺月做,不必因为一年不顺就推翻长期计划。');
4989
+ else if (!good.includes(curTier) && good.includes(lnTier)) out.push('大运逆、当年顺:今年适合借势处理具体事务,但不宜把长期结构性问题押在这一年解决。');
4990
+ else if (!good.includes(curTier) && !good.includes(lnTier)) out.push('大运与流年都偏逆:以守住基本盘为主,减少新增承诺。');
4991
+ else out.push('大运与流年同向偏顺:可以把想做但一直拖着的事排上日程。');
4992
+ }
4993
+ const tiao = ys.tiaohou && ys.tiaohou.element;
4994
+ if (tiao) out.push(favor.includes(tiao)
4995
+ ? `调候喜${tiao},与扶抑用神同向:取用上不打架,${tiao}相关的行业与环境优先。`
4996
+ : `调候喜${tiao},不在扶抑的喜用里:两套取法有分歧,这里以扶抑为主,${tiao}只作环境上的小幅偏好。`);
4997
+ return out.join(' ');
4998
+ })(),
4999
+ },
4942
5000
  {
4943
5001
  key: 'yongshen', label: '用神与忌神',
4944
5002
  text: `喜用:${join(favor)}(对应十神:${join(ys.favorTenGods || ys.favorRoles || [])});忌:${join(avoid)}(对应十神:${join(ys.avoidTenGods || ys.avoidRoles || [])})。` +
@@ -4948,6 +5006,10 @@ function baziInterpret(r) {
4948
5006
  key: 'geju', label: '格局依据',
4949
5007
  text: (Array.isArray(frame.geju) ? frame.geju : []).map((g) => `${g.name}(${g.kind}):${g.evidence}`).join(';') || '未取到格局',
4950
5008
  },
5009
+ {
5010
+ key: 'limits', label: '未纳入',
5011
+ text: '本盘没有计算:流月与流日、神煞的加权轻重、地支藏干的动态引化(合冲后再论)。取用以扶抑为主、调候只做简化提示,各派取法不同;真太阳时未含历史时区与夏令时。把这些补上会改变"强弱"的边际判断,所以这里只给方向,不下断语。',
5012
+ },
4951
5013
  ];
4952
5014
 
4953
5015
  return {
@@ -5112,6 +5174,38 @@ function ziweiInterpret(r) {
5112
5174
  const sections = [
5113
5175
  { key: 'palaces', label: '关键宫位', text: `命宫${soulStar} 官禄${careerStar || '无正曜'} 财帛${wealthStar || '无正曜'} 夫妻${spouseStar || '无正曜'} 疾厄${healthStar || '无正曜'}` },
5114
5176
  { key: 'patterns', label: '格局', text: patText },
5177
+ {
5178
+ key: 'reasoning', label: '看盘顺序',
5179
+ text: [
5180
+ `① 先看命宫:${soulFrom}${S.trait ? `,底色是「${S.trait}」` : ''}。命宫回答的是"你是谁",不是"会遇到什么"。`,
5181
+ `② 再看三方四正:${(soul && soul.sanfang) ? soul.sanfang.join('、') : '命/财/官/迁'},会到的主星是${(() => {
5182
+ const names = (soul && soul.sanfang ? soul.sanfang : [])
5183
+ .map((n) => zwMainStar(zwPalace(r, n)))
5184
+ .filter(Boolean);
5185
+ const uniq = [...new Set(names)];
5186
+ return uniq.length ? uniq.join('、') : '无正曜';
5187
+ })()}——这是你与外界打交道时的常用手法。`,
5188
+ natalSihuaText ? `③ 生年四化:${natalSihuaText}。四化比星曜更能指出"你在意什么、哪里会反复"。` : '③ 生年四化:本盘四化信号不明显。',
5189
+ `④ 大限:${daxianPalace ? `${daxianPalace.palace}(${daxianPalace.daxian.start}–${daxianPalace.daxian.end}岁)` : '当前阶段'}。紫微里大限比流年重:十年的主题定下来,流年只是其中一年的天气。`,
5190
+ lnMutagen ? `⑤ 流年四化:${lnMutagen}${r.flow && r.flow.month ? `;流月命宫 ${r.flow.month.ganzhi}${r.flow.month.palace ? `(${r.flow.month.palace})` : ''}` : ''}。` : '⑤ 流年四化:信号不明显。',
5191
+ '⑥ 落到维度:工作看命宫与官禄的配合;感情看夫妻宫与煞星;健康看疾厄宫——五维度都是上面几步的应用。',
5192
+ ].join('\n'),
5193
+ },
5194
+ {
5195
+ key: 'timeline', label: '时间窗',
5196
+ text: (() => {
5197
+ const list = (r.daxianList || []).slice().sort((a, b) => a.ages[0] - b.ages[0]);
5198
+ const idx = list.findIndex((d) => Number.isFinite(age) && age >= d.ages[0] && age <= d.ages[1]);
5199
+ const pick3 = list.slice(idx >= 0 ? idx : 0, (idx >= 0 ? idx : 0) + 3);
5200
+ const dx = pick3.map((d) => `${d.palace} ${d.ages[0]}–${d.ages[1]}岁·会${(d.mainStars || []).join('') || '—'}${(d.mutagenHits || []).length ? `·${d.mutagenHits.map((m) => m.star + m.type).join('')}` : ''}`).join(' → ');
5201
+ const yrs = (r.liunian || []).slice(0, 5).map((l) => `${l.year} ${l.ganzhi} ${l.age}岁·命宫${l.lifePalace ? l.lifePalace.palace : '—'}`).join(';');
5202
+ return `大限:${dx || '—'}。\n近五年流年:${yrs || '—'}。\n读法:大限定十年的主题,流年四化指出今年往哪边偏;两层方向相反时,以守住大限主题为主。`;
5203
+ })(),
5204
+ },
5205
+ {
5206
+ key: 'limits', label: '未纳入',
5207
+ text: '本盘没有计算:飞星四化(宫干引发的连锁)、小限与大限的加权、流日流时的具体事项定位,以及双星组合的强弱细分。四化表取中州派常用口径,其他流派(如飞星派)结论会不同;这些不改变盘面事实,只影响轻重,所以只作方向参考。',
5208
+ },
5115
5209
  ];
5116
5210
  if (natalSihua.length) {
5117
5211
  const ke = natalSihua.find((m) => m.type === '科') || null;
@@ -5200,6 +5294,9 @@ function liuyaoInterpret(r) {
5200
5294
  const movingLiuqin = moving?.liuqin || '';
5201
5295
  const movingLiushen = moving?.liushen || '';
5202
5296
  const dayGZ = pick(r.dayGanZhi, 'name', '');
5297
+ const cnt = (k) => lines.filter((l) => l.liuqin === k).length;
5298
+ const lineEv = (l) => (l ? `${l.position}爻${l.liuqin}${l.liushen ? '·' + l.liushen : ''}${l.moving ? '(动)' : ''}` : '—');
5299
+ const ev = (...xs) => xs.filter((x) => x != null && x !== '');
5203
5300
 
5204
5301
  sections.push({
5205
5302
  key: 'liuqin', label: '六亲取用',
@@ -5207,18 +5304,45 @@ function liuyaoInterpret(r) {
5207
5304
  `如果你心里有具体问题,可以对号入座:${Object.entries(LIUQIN_USE).map(([k, v]) => `${k}主${v.split(',')[0]}`).join(';')}。`,
5208
5305
  });
5209
5306
 
5307
+ sections.push({
5308
+ key: 'reasoning', label: '看卦顺序',
5309
+ text: [
5310
+ `① 先定卦宫:本卦「${ben.name || '—'}」属${String(pick(ben, 'palace', '—')).replace(/宫$/, '')}宫(${palaceEl || '—'}),六亲由此排定——宫变了,同一个字的六亲就变了。`,
5311
+ `② 再看世应:世在${ben.shi}爻(${shiLine ? `${shiLine.liuqin}${shiLine.liushen ? `·${shiLine.liushen}` : ''}` : '—'}),应在${ben.ying}爻(${yingLine ? `${yingLine.liuqin}` : '—'});世代表你,应代表对方与环境。`,
5312
+ `③ 看动爻:${moving ? `${moving.position}爻${moving.liuqin}${moving.liushen ? `(${moving.liushen})` : ''}发动,事情的变化点在这里` : '六爻安静,短期不会有大的转折'}。`,
5313
+ `④ 定用神:按所问之事取六亲——问工作看官鬼、文书看父母、求财与感情(男)看妻财、健康看官鬼与子孙;用神不上卦时,看伏神或借日月。`,
5314
+ `⑤ 看日辰:${dayGZ || '—'}日起六神、定旬空;日辰能生克动爻,但不被爻所伤。`,
5315
+ `⑥ 看变卦:${bian.name ? `变出「${bian.name}」,是事情后续的走向` : '本卦无变,以静卦论'}。以上每一步都能在下方「依据」里对上号。`,
5316
+ ].join('\n'),
5317
+ });
5318
+ sections.push({
5319
+ key: 'limits', label: '未纳入',
5320
+ text: '本卦没有计算:月建对爻的旺衰(只用了日辰)、伏神与飞神的完整生克链、进神退神与反吟伏吟的细节,以及用神多重时的取舍权重。这些会改变"旺不旺"的判断,所以这里只给取象与方向。',
5321
+ });
5322
+
5210
5323
  const dimensions = [
5211
5324
  {
5212
5325
  key: 'overall', label: '整体运势',
5213
5326
  text: `这一卦是「${benInfo.full}」,${benInfo.meaning}。${movingLiushen ? `动爻带${movingLiushen},事情带一点${movingLiushen === '青龙' ? '喜庆顺遂' : movingLiushen === '白虎' ? '压力与阻碍' : movingLiushen === '朱雀' ? '口舌与是非' : movingLiushen === '玄武' ? '不明朗、需要核实' : '反复与牵扯'}的色彩。` : ''}` +
5214
5327
  `日辰为${dayGZ},卦宫属${palaceEl},整体更像是${benInfo.scene}的阶段。`,
5215
5328
  advice: `${benInfo.scene}——顺着这句做就行。${moving ? '既然有动爻,说明事情还在变化,先观察几天再定也不迟。' : '暂无动爻,说明短期内不会有大的转折,维持现状反而是稳妥选择。'}`,
5329
+ evidence: ev(
5330
+ `本卦 ${ben.name || '—'}(${ben.upper || ''}/${ben.lower || ''})`,
5331
+ moving ? `动爻 ${lineEv(moving)}` : '无动爻',
5332
+ `日辰 ${dayGZ || '—'}`,
5333
+ `卦宫 ${pick(ben, 'palace', '—')}·${palaceEl || '—'}`,
5334
+ ),
5216
5335
  },
5217
5336
  {
5218
5337
  key: 'work', label: '工作与职业选择',
5219
5338
  text: `问工作看官鬼与父母:本卦中${(lines.filter((l) => l.liuqin === '官鬼').length ? `官鬼出现${lines.filter((l) => l.liuqin === '官鬼').length}处,${lines.find((l) => l.liuqin === '官鬼').moving ? '且有发动,岗位或考核层面会有动作' : '但未发动,职位层面暂时平稳'}` : '未见官鬼,工作这件事在卦中不是主要矛盾')};` +
5220
5339
  `${(lines.filter((l) => l.liuqin === '父母').length ? '父母(文书、合同、资质)有出现,涉及手续与材料的事要提前准备' : '父母未现,手续类事务暂无明显阻碍')}。`,
5221
5340
  advice: `如果正在看机会,建议先把合同、岗位职责这些落到纸面上的东西问清楚;${moving?.liuqin === '官鬼' ? '动爻在官鬼,工作层面近期有变动的迹象,可以主动谈,但别先辞再找。' : '工作层面暂无强动象,稳住手上的事更划算。'}`,
5341
+ evidence: ev(
5342
+ `官鬼 ${cnt('官鬼')} 现`,
5343
+ `父母 ${cnt('父母')} 现`,
5344
+ movingLiuqin ? `动爻六亲 ${movingLiuqin}` : '无动爻',
5345
+ ),
5222
5346
  },
5223
5347
  {
5224
5348
  key: 'career', label: '事业发展',
@@ -5226,18 +5350,33 @@ function liuyaoInterpret(r) {
5226
5350
  `世应之间${shiLine && yingLine ? (shiLine.liuqin === yingLine.liuqin ? '同气相求,双方立场接近' : '立场有别,需要多沟通') : '信号不明'},` +
5227
5351
  `${bianInfo ? `变卦「${bianInfo.full}」提示后续走向是${bianInfo.scene}` : '暂无变卦'}。`,
5228
5352
  advice: `事业上的建议是:${shiLine?.moving ? '你自己这边有主动变化的意思,那就把想法说出来、把动作做出来' : '先不动,把手上的事做扎实'};${bianInfo ? `按${bianInfo.scene}的方向去准备,会比被动等结果好。` : ''}`,
5353
+ evidence: ev(
5354
+ `世 ${lineEv(shiLine)}`,
5355
+ `应 ${lineEv(yingLine)}`,
5356
+ bian.name ? `变卦 ${bian.name}` : '无变卦',
5357
+ ),
5229
5358
  },
5230
5359
  {
5231
5360
  key: 'love', label: '爱情与感情',
5232
5361
  text: `问感情,男看妻财、女看官鬼。本卦中${(lines.filter((l) => l.liuqin === '妻财').length ? `妻财${lines.filter((l) => l.liuqin === '妻财').length}现${lines.find((l) => l.liuqin === '妻财').moving ? '且发动,感情层面有动静' : '但安静,关系暂时平缓'}` : '妻财未现,感情不是当前卦象的重点')};` +
5233
5362
  `${(lines.filter((l) => l.liuqin === '官鬼').length ? '官鬼有现,对方或关系中的压力面是被看到的' : '官鬼未现')}。${benInfo.meaning},放在关系里就是${benInfo.scene}。`,
5234
5363
  advice: `关系里${moving?.liuqin === '妻财' || moving?.liuqin === '官鬼' ? '近期有变化的可能,适合把话说开,别憋着' : '暂时平稳,可以按自己的节奏相处'}。卦象只给倾向,真正决定关系的是你们怎么沟通。`,
5364
+ evidence: ev(
5365
+ `妻财 ${cnt('妻财')} 现`,
5366
+ `官鬼 ${cnt('官鬼')} 现`,
5367
+ `世应 ${lineEv(shiLine)} / ${lineEv(yingLine)}`,
5368
+ ),
5235
5369
  },
5236
5370
  {
5237
5371
  key: 'health', label: '健康状况',
5238
5372
  text: `问健康,看官鬼(病)与子孙(医药、消散)。本卦中${(lines.filter((l) => l.liuqin === '官鬼').length ? `官鬼有现${lines.find((l) => l.liuqin === '官鬼').moving ? '且发动,提示身体上可能有需要留意的地方' : ',但安静,暂无明显变化'}` : '官鬼未现,卦象未指向明显的身体问题')};` +
5239
5373
  `${(lines.filter((l) => l.liuqin === '子孙').length ? '子孙有现,恢复与调养的出口是有的' : '子孙未现,休息与调养需要自己主动安排')}。${movingLiushen === '白虎' ? '动爻带白虎,尤其别忽视突发的身体信号。' : ''}`,
5240
5374
  advice: `这一卦在健康上的提醒是${(lines.filter((l) => l.liuqin === '官鬼').length ? '别硬扛,累了就休息,有机会就做一次检查' : '维持现有作息即可,别自己吓自己')}。任何不适请就医,卦象不能替代诊断。`,
5375
+ evidence: ev(
5376
+ `官鬼 ${cnt('官鬼')} 现`,
5377
+ `子孙 ${cnt('子孙')} 现`,
5378
+ movingLiushen ? `动爻六神 ${movingLiushen}` : '',
5379
+ ),
5241
5380
  },
5242
5381
  ];
5243
5382
 
@@ -5286,30 +5425,53 @@ function meihuaInterpret(r) {
5286
5425
  text: `本卦「${benInfo.full}」,${benInfo.meaning}。体${bodyEl}用${useEl},${relation},判定为${mhLevel}。` +
5287
5426
  `${isJi ? '整体的倾向是顺的:外部环境对你不算苛刻,可以正常推进' : isXiong ? '整体有阻力:不是不能做,而是要多留余量与耐心' : '整体平稳,不会有大的起落'}。`,
5288
5427
  advice: `${benInfo.scene}。${isXiong ? '建议把节奏放慢,先解决卡点再谈推进' : isJi ? '可以趁势把想做的事往前推一步' : '按原计划走,不必刻意改变'}。`,
5428
+ evidence: [
5429
+ `本卦 ${benInfo.full}`,
5430
+ `互卦 ${pick(hu, 'name', '—')}`,
5431
+ `变卦 ${pick(bian, 'name', '—')}`,
5432
+ `体${bodyEl} / 用${useEl}·${relation || '—'}`,
5433
+ `判定 ${mhLevel || '—'}`,
5434
+ ].filter(Boolean),
5289
5435
  },
5290
5436
  {
5291
5437
  key: 'work', label: '工作与职业选择',
5292
5438
  text: `梅花里工作看用卦与体卦的生克:现在用卦${useEl}${isJi ? '对体卦有利,说明当下的工作环境或岗位与你的匹配度还不错' : isXiong ? '与体卦相耗,说明眼下这份工作消耗感偏重' : '与体卦关系平和,属于不好不坏'}` +
5293
5439
  `。本卦${benInfo.meaning},对应到工作里就是${benInfo.scene}。`,
5294
5440
  advice: `${isXiong ? '如果长期觉得被消耗,可以先在内部争取调整职责,再考虑外部机会' : isJi ? '适合主动争取更多责任或更好的岗位' : '把手上的事做好,等一个明确的信号再动'}。选工作时优先考虑让你舒服的环境,长期看比短期收益重要。`,
5441
+ evidence: [`体卦 ${bodyEl}`, `用卦 ${useEl}`, `体用 ${relation || '—'}`],
5295
5442
  },
5296
5443
  {
5297
5444
  key: 'career', label: '事业发展',
5298
5445
  text: `变卦「${bianInfo ? bianInfo.full : ''}」代表事情的结局方向,${bianInfo ? bianInfo.meaning : ''}。互卦「${pick(hu, 'name', '')}」代表过程,${hexInfo(hu.name, hu.upper, hu.lower).meaning}。` +
5299
5446
  `合起来看:过程${hexInfo(hu.name, hu.upper, hu.lower).scene},结果${bianInfo ? bianInfo.scene : '暂不明朗'}。`,
5300
5447
  advice: `按这个结构,建议${isJi ? '现在就把关键的一步迈出去' : isXiong ? '先补短板、攒条件,等下一轮再动' : '小步推进,边做边看'}。动爻在${pick(r, 'movingName', '某爻')},变化点就在那里,值得重点关注。`,
5448
+ evidence: [
5449
+ `互卦 ${pick(hu, 'name', '—')}`,
5450
+ `变卦 ${pick(bian, 'name', '—')}`,
5451
+ `动爻 ${pick(r, 'movingName', '—')}`,
5452
+ ],
5301
5453
  },
5302
5454
  {
5303
5455
  key: 'love', label: '爱情与感情',
5304
5456
  text: `感情上看体用是否相合:体${bodyEl}与用${useEl}之间是${relation},${isJi ? '这种组合在关系里意味着双方相处比较顺,彼此能给到支撑' : isXiong ? '这种组合提示相处中有一方付出更多,需要留意平衡' : '关系处在常态,没有特别的张力'}` +
5305
5457
  `。本卦${benInfo.meaning},放到两人之间就是${benInfo.scene}。`,
5306
5458
  advice: `${isXiong ? '别把不满攒着,找个合适的时机说清楚;也别指望对方猜' : isJi ? '可以主动推进关系,做一些共同的事' : '维持现在的相处节奏就好'}。卦象看的是当下的气氛,关系的走向取决于你们怎么经营。`,
5459
+ evidence: [
5460
+ `体 ${bodyEl} / 用 ${useEl}`,
5461
+ `体用 ${relation || '—'}`,
5462
+ `本卦 ${benInfo.full}`,
5463
+ ],
5307
5464
  },
5308
5465
  {
5309
5466
  key: 'health', label: '健康状况',
5310
5467
  text: `梅花里健康看体卦的强弱:体卦${pick(bu.body, 'trigram', '')}属${bodyEl},${isXiong ? '被用卦所耗,传统取象上提示近期精力消耗偏大' : isJi ? '得到生扶,精力状态相对好' : '平顺,无明显偏枯'}。` +
5311
5468
  `${WUXING_ORGAN[bodyEl] ? `${bodyEl}对应${WUXING_ORGAN[bodyEl].part},${WUXING_ORGAN[bodyEl].note}。` : ''}这是取象提示,不是诊断。`,
5312
5469
  advice: `${isXiong ? '近期别硬撑,睡眠与饮食先稳住,有条件做一次常规体检' : '保持现在的作息即可,顺势多动一动更好'}。身体有明确的症状请直接看医生。`,
5470
+ evidence: [
5471
+ `体卦 ${pick(bu.body, 'trigram', '—')}属${bodyEl}`,
5472
+ `用卦 ${pick(bu.use, 'trigram', '—')}属${useEl}`,
5473
+ `体用 ${relation || '—'}`,
5474
+ ],
5313
5475
  },
5314
5476
  ];
5315
5477
 
@@ -5327,6 +5489,12 @@ function daliurenInterpret(r) {
5327
5489
  const gj = isObj(r.geJu) ? r.geJu : {};
5328
5490
  const ke = Array.isArray(r.siKe) ? r.siKe : [];
5329
5491
  const jiangOf = (x) => LIUREN_JIANG[x?.jiangFull] || LIUREN_JIANG[x?.jiang] || '';
5492
+ const chuQin = pick(chu, 'liuQin', '');
5493
+ const moQin = pick(mo, 'liuQin', '');
5494
+ const hasKong = !!(chu.xunKong || zhong.xunKong || mo.xunKong);
5495
+ const scText = JSON.stringify(sc);
5496
+ const has = (x) => scText.includes(x);
5497
+ const chuan = `初${pick(chu, 'zhi', '—')} → 中${pick(zhong, 'zhi', '—')} → 末${pick(mo, 'zhi', '—')}`;
5330
5498
 
5331
5499
  const sections = [
5332
5500
  {
@@ -5340,12 +5508,23 @@ function daliurenInterpret(r) {
5340
5508
  key: 'geju', label: '课体与四课',
5341
5509
  text: `本课为${pick(gj, 'name', '未定')}${gj.detail ? `(${gj.detail})` : ''}。${ke.length ? `四课:${ke.map((k, i) => `${i + 1}课 ${k.shang || ''}上${k.xia || ''}下`).join(' ')}` : ''}`,
5342
5510
  },
5511
+ {
5512
+ key: 'reasoning', label: '看课顺序',
5513
+ text: [
5514
+ `① 先看月将加时:月将${pick(r.yueJiang, 'name', '—')}${pick(r.yueJiang, 'zhi', '')}加在${pick(r, 'hourZhi', '—')}时上,定出天地盘——后面所有关系都从这张盘推。`,
5515
+ `② 再看四课:日干寄宫起一课,日支起二课,依次得三、四课;四课是"事情的四个面"。`,
5516
+ `③ 看三传:初传${pick(chu, 'zhi', '—')}(${chuQin || '—'})起,中传${pick(zhong, 'zhi', '—')}(${pick(zhong, 'liuQin', '—')}),末传${pick(mo, 'zhi', '—')}(${moQin || '—'})落——发端、过程、结局。`,
5517
+ `④ 定课体:${pick(gj, 'name', '未定')}${gj.detail ? `(${gj.detail})` : ''};课体决定这件事"以什么方式"推进,不是吉凶标签。`,
5518
+ `⑤ 看神将:月将、贵人与旬空决定信号强弱;旬空处多为"看着有、实则虚",须核实。`,
5519
+ '⑥ 落到维度:工作看官鬼与青龙、朱雀;感情看六合、天后与妻财;健康看白虎与子孙——都是上面几步的应用。',
5520
+ ].join('\n'),
5521
+ },
5522
+ {
5523
+ key: 'limits', label: '未纳入',
5524
+ text: '本课没有计算:年命与行年(命上神)、神煞的加权轻重、伏吟反吟的细分,以及课体之间的互涉。三传只取九宗门里的主要取法,其他流派(如以贵神起课)结论可能不同;这些只影响轻重,不改变课面事实。',
5525
+ },
5343
5526
  ];
5344
5527
 
5345
- const chuQin = pick(chu, 'liuQin', '');
5346
- const moQin = pick(mo, 'liuQin', '');
5347
- const hasKong = !!(chu.xunKong || zhong.xunKong || mo.xunKong);
5348
-
5349
5528
  const dimensions = [
5350
5529
  {
5351
5530
  key: 'overall', label: '整体运势',
@@ -5353,6 +5532,12 @@ function daliurenInterpret(r) {
5353
5532
  `${hasKong ? '课中有旬空,提示事情里有「看着有、实则虚」的部分,涉及承诺与数字的要核实。' : '课中无旬空,事情相对实在。'}` +
5354
5533
  `整体倾向是:${/吉|生|合/.test(jiangOf(chu) + jiangOf(mo)) ? '开局与结局的象都不差,可以正常推进' : /虎|蛇|勾|空/.test(jiangOf(chu) + jiangOf(mo)) ? '过程中有牵绊与不明朗处,宜慢不宜快' : '平顺中带一点摩擦' }。`,
5355
5534
  advice: `${hasKong ? '先把信息核实清楚,别在含糊的基础上做决定' : '按你原本的计划推进即可'}。${/虎/.test(jiangOf(chu)) ? '开局带白虎,头几天别硬碰,先观察。' : ''}事情的局面是动态的,这一课看的是当下这一刻的气象。`,
5535
+ evidence: [
5536
+ `课体 ${pick(gj, 'name', '—')}`,
5537
+ `三传 ${chuan}`,
5538
+ `月将 ${pick(r.yueJiang, 'name', '—')}`,
5539
+ hasKong ? '课中见旬空' : '无旬空',
5540
+ ],
5356
5541
  },
5357
5542
  {
5358
5543
  key: 'work', label: '工作与职业选择',
@@ -5360,12 +5545,22 @@ function daliurenInterpret(r) {
5360
5545
  `${/青龙/.test(JSON.stringify(sc)) ? '课中见青龙,工作层面有喜庆与进益的象' : '课中未见青龙,工作层面属常态推进'};` +
5361
5546
  `${/朱雀/.test(JSON.stringify(sc)) ? '见朱雀,文书、沟通与口舌要留意,材料务必留底' : ''}`,
5362
5547
  advice: `涉及岗位与待遇的事,建议把口头承诺落成文字;${/朱雀/.test(JSON.stringify(sc)) ? '沟通时少说满话,多留余地。' : '正常沟通即可。'}选工作时优先考虑课象中显示出支撑力的方向。`,
5548
+ evidence: [
5549
+ `初传 ${pick(chu, 'zhi', '—')}·${chuQin || '未取'}·${jiangOf(chu) || '—'}`,
5550
+ has('青龙') ? '见青龙' : '无青龙',
5551
+ has('朱雀') ? '见朱雀' : '无朱雀',
5552
+ ],
5363
5553
  },
5364
5554
  {
5365
5555
  key: 'career', label: '事业发展',
5366
5556
  text: `末传${pick(mo, 'zhi', '')}(${moQin || ''}·${jiangOf(mo) || ''})主结局,${moQin === '官鬼' ? '结局落在官鬼,事业这条线会有明确的结果或位置变化' : moQin === '妻财' ? '结局落在妻财,更多体现为收入与资源的落袋' : moQin === '子孙' ? '结局落在子孙,压力会消散,适合收尾与转向' : '结局的信号相对中性'}。` +
5367
5557
  `${mo.xunKong ? '末传旬空,结局有落空的可能,别把预期定得太满。' : '末传不空,结果相对实在。'}`,
5368
5558
  advice: `按三传的顺序安排节奏:初传阶段先摸清情况,中传阶段处理摩擦,末传阶段收果。${mo.xunKong ? '对结果保留一点弹性,Plan B 提前想好。' : '可以朝着末传给出的方向去准备。'}`,
5559
+ evidence: [
5560
+ `末传 ${pick(mo, 'zhi', '—')}·${moQin || '未取'}·${jiangOf(mo) || '—'}`,
5561
+ mo.xunKong ? '末传旬空' : '末传不空',
5562
+ `三传 ${chuan}`,
5563
+ ],
5369
5564
  },
5370
5565
  {
5371
5566
  key: 'love', label: '爱情与感情',
@@ -5373,12 +5568,22 @@ function daliurenInterpret(r) {
5373
5568
  `${/天后/.test(JSON.stringify(sc)) ? '见天后,有被照顾、被回应的象' : ''}${/玄武/.test(JSON.stringify(sc)) ? '见玄武,提示信息不明或有隐瞒,重要的事要当面问清' : ''}` +
5374
5569
  `${/妻财/.test(JSON.stringify(sc)) ? '课中见妻财,感情这条线是被看到的' : ''}。`,
5375
5570
  advice: `${/玄武/.test(JSON.stringify(sc)) ? '关系里有看不清的地方,别猜,直接问。' : '按你感受到的相处状态来判断就好。'}卦象只反映当下的气氛,关系如何取决于两个人怎么做。`,
5571
+ evidence: [
5572
+ has('六合') ? '见六合' : '无六合',
5573
+ has('天后') ? '见天后' : '无天后',
5574
+ has('妻财') ? '见妻财' : '无妻财',
5575
+ ],
5376
5576
  },
5377
5577
  {
5378
5578
  key: 'health', label: '健康状况',
5379
5579
  text: `健康看白虎与子孙:本课${/白虎/.test(JSON.stringify(sc)) ? '见白虎,传统取象上提示身体有需要留意的地方,尤其突发的不适别忽视' : '未见白虎,卦象未指向明显的身体问题'};` +
5380
5580
  `${/子孙/.test(JSON.stringify(sc)) ? '见子孙,医药与调养的出口是有的,恢复的象在' : '未见子孙,休息与调养需要自己主动安排'}。这些都是象征提示,不构成医学判断。`,
5381
5581
  advice: `${/白虎/.test(JSON.stringify(sc)) ? '近期别熬夜、别硬扛,有条件做一次检查' : '保持现有作息,适度运动即可'}。任何不适请就医,这一课不能替代诊断。`,
5582
+ evidence: [
5583
+ has('白虎') ? '见白虎' : '无白虎',
5584
+ has('子孙') ? '见子孙' : '无子孙',
5585
+ `课体 ${pick(gj, 'name', '—')}`,
5586
+ ],
5382
5587
  },
5383
5588
  ];
5384
5589
 
@@ -5442,6 +5647,12 @@ function tarotInterpret(r) {
5442
5647
  `${reversed.length ? `其中${join(reversed.map((c) => `${c.name}(${c.position})`))}是逆位,逆位不等于凶,更像那股力量还没顺过来或用力过猛,它是这张牌阵里最值得你先看的部分。` : '全部为正位,说明牌面呈现的状态与你当下的处境是通的。'}` +
5443
5648
  `${lack.length ? `元素上缺${join(lack)},${lack.map((e) => TAROT_ELEMENT_FOCUS[e]?.area).filter(Boolean).join('、')}这一块容易被忽略。` : ''}`,
5444
5649
  advice: `${reversed.length ? `先把${reversed[0].name}指出的卡点处理掉(${(reversed[0].keywords || []).join('、')}),暂时不要加码推进` : '按牌面呈现的节奏走'};${lack.length ? `补一点${lack[0]}的力量:${TAROT_ELEMENT_FOCUS[lack[0]]?.advice || ''}` : '把注意力放在能立刻做的小事上,先动一件'}。牌是镜子,照的是你此刻的状态。`,
5650
+ evidence: [
5651
+ `牌阵 ${n} 张(${cards.map((c) => c.position).join(' / ')})`,
5652
+ `主轴 ${axis ? `${axis.name}·${axis.position}·${axis.orientation}` : '—'}`,
5653
+ `逆位 ${reversed.length} / 正位 ${upright.length}`,
5654
+ lack.length ? `缺 ${join(lack)}` : '五行元素齐',
5655
+ ],
5445
5656
  },
5446
5657
  {
5447
5658
  key: 'work', label: '工作与职业选择',
@@ -5449,6 +5660,11 @@ function tarotInterpret(r) {
5449
5660
  `${court.length ? `牌中有宫廷牌${join(court.map((c) => c.name))},说明局面里有具体的人(也可能就是你自己的某个侧面)在起作用。` : ''}` +
5450
5661
  `${elCount.土 ? '有土元素,现实条件与资源是被这张牌阵看到的。' : '缺土元素,现实条件与资源这块容易估计不足。'}`,
5451
5662
  advice: `工作上建议:${elCount.土 ? '把计划落到预算与时间表上,别停在口头' : '先把现实条件摸清楚——薪资、工时、稳定性,再谈喜好'};${dimBase('work') && !dimBase('work').upright ? '这张相关牌是逆位,说明当下的不适主要来自状态而非岗位本身,可以调状态再看。' : ''}`,
5663
+ evidence: [
5664
+ `工作相关牌 ${dimBase('work') ? `${dimBase('work').name}·${dimBase('work').position}·${dimBase('work').orientation}` : '无'}`,
5665
+ `宫廷牌 ${court.length} 张`,
5666
+ `土元素 ${elCount.土 || 0} 张`,
5667
+ ],
5452
5668
  },
5453
5669
  {
5454
5670
  key: 'career', label: '事业发展',
@@ -5456,12 +5672,20 @@ function tarotInterpret(r) {
5456
5672
  `${major.length >= Math.ceil(n / 2) ? '大牌过半,事业这条线牵动的不只是岗位,还有你对自己要往哪走的判断' : '变化更多发生在具体事务层面,先把眼前的项目做成'}` +
5457
5673
  `${axis ? `;结局位置的「${axis.name}」给出的方向是${axis.core || ''}` : ''}。`,
5458
5674
  advice: `建议把${cards[0]?.position || '最初'}这一环的课题先收尾,再往${axis?.position || '结果'}的方向推进;${elCount.火 ? '火的能量在,适合主动出击一步' : '缺火时别等热情来,先用流程推着自己动'}。事业发展是长线,牌面只反映当前这一段。`,
5675
+ evidence: [
5676
+ `时间线 ${cards.map((c) => `${c.position}·${c.name}${c.orientation}`).join(' → ')}`,
5677
+ `大阿卡纳 ${major.length}/${n}`,
5678
+ ],
5459
5679
  },
5460
5680
  {
5461
5681
  key: 'love', label: '爱情与感情',
5462
5682
  text: `${dimBase('love') ? `与感情最相关的是「${dimBase('love').name}」(${dimBase('love').position}·${dimBase('love').orientation}):${dimBase('love').core || (dimBase('love').keywords || []).join('、')}。` : '牌面上没有明确指向感情的牌,当下这段关系不是主要议题。'}` +
5463
5683
  `${elCount.水 ? '有水元素,情感与感受在这件事里占的分量不轻。' : '缺水元素,容易用理性压过感受,留意别忽略自己的情绪。'}`,
5464
5684
  advice: `${elCount.水 ? '先照顾好感受再谈效率:把想说的话说出口,比猜对方心思有效' : '给自己留一点感受情绪的时间,别把所有事都当任务处理'};${dimBase('love') && !dimBase('love').upright ? '相关牌为逆位,提示关系里有没说开的地方,找个合适时机讲清楚。' : ''}关系取决于你们怎么做,牌只帮你把问题问清楚。`,
5685
+ evidence: [
5686
+ `感情相关牌 ${dimBase('love') ? `${dimBase('love').name}·${dimBase('love').position}·${dimBase('love').orientation}` : '无'}`,
5687
+ `水元素 ${elCount.水 || 0} 张`,
5688
+ ],
5465
5689
  },
5466
5690
  {
5467
5691
  key: 'health', label: '健康状况',
@@ -5469,6 +5693,11 @@ function tarotInterpret(r) {
5469
5693
  `${reversed.length >= 2 ? `${reversed.length} 张逆位,提示内在消耗偏大,身体往往是第一个反映出来的` : '整体状态与牌面呈现的相对一致'}` +
5470
5694
  `${elCount.土 || elCount.水 ? '' : ';缺土与水,作息与身体的基本盘容易被牺牲'}。这些是象征性的提示,不是诊断。`,
5471
5695
  advice: `${reversed.length >= 2 ? '建议先把睡眠与饮食稳住,别在这个阶段额外加压' : '维持现有作息,适度运动即可'};${lack.length ? `补${lack[0]}所代表的${TAROT_ELEMENT_FOCUS[lack[0]]?.area || ''}:${TAROT_ELEMENT_FOCUS[lack[0]]?.advice || ''}` : ''}身体有明确不适请就医,牌面不能替代专业意见。`,
5696
+ evidence: [
5697
+ `健康相关牌 ${dimBase('health') ? `${dimBase('health').name}·${dimBase('health').position}` : '无'}`,
5698
+ `逆位 ${reversed.length} 张`,
5699
+ `元素 土${elCount.土 || 0} / 水${elCount.水 || 0}`,
5700
+ ],
5472
5701
  },
5473
5702
  ];
5474
5703
 
@@ -5777,6 +6006,7 @@ function liuyaoText(r) {
5777
6006
  const out = [
5778
6007
  `起卦:${r.cast.notation.join('、')}(自下而上)`,
5779
6008
  `日辰:${r.dayGanZhi.name}`,
6009
+ r.xunShou ? `旬首:${r.xunShou} 旬空:${(r.xunKong || []).join('') || '—'}` : '',
5780
6010
  r.question ? `所问:${r.question}` : '',
5781
6011
  '本卦:',
5782
6012
  fmt(r.ben),
@@ -5998,6 +6228,34 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
5998
6228
 
5999
6229
  const Engine = __mods.index;
6000
6230
  window.Engine = Engine;
6231
+ (function () {
6232
+ const NEED_ASK = { liuyao: true, meihua: true, daliuren: true, tarot: true };
6233
+ const needAsk = (kind) => !!NEED_ASK[kind];
6234
+
6235
+ function parseLines(text) {
6236
+ const raw = String(text == null ? '' : text).trim();
6237
+ if (!raw) return { lines: null, warning: '' };
6238
+ const v = raw.split(/[^0-9]+/).filter(Boolean).map(Number);
6239
+ const bad = v.filter((n) => ![6, 7, 8, 9].includes(n));
6240
+ if (v.length === 6 && bad.length === 0) return { lines: v, warning: '' };
6241
+ return {
6242
+ lines: null,
6243
+ warning: v.length !== 6
6244
+ ? `爻值需要正好 6 个数字(当前 ${v.length} 个),本次按随机摇卦。`
6245
+ : `爻值只能是 6/7/8/9(收到 ${bad.join('/')}),本次按随机摇卦。`,
6246
+ };
6247
+ }
6248
+
6249
+ function toNumber(text) {
6250
+ const raw = String(text == null ? '' : text).trim();
6251
+ if (!raw) return null;
6252
+ const n = Number(raw);
6253
+ return Number.isFinite(n) ? n : null;
6254
+ }
6255
+
6256
+ window.__MPCore = { NEED_ASK, needAsk, parseLines, toNumber };
6257
+ })();
6258
+
6001
6259
  (function () {
6002
6260
  const CSS = `
6003
6261
  .pp,.mp-it{--ink:#1b1b1b;--ink2:#3f3a33;--muted:#6f6a60;--label:#8a8378;--faint:#a9a296;
@@ -6997,6 +7255,24 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
6997
7255
  </div>`;
6998
7256
  };
6999
7257
 
7258
+ pp.qimenFactsHTML = function (r) {
7259
+ if (!r || !r.palaces) return '';
7260
+ const row = (k, v) => `<div class="relation__row"><dt>${esc(k)}</dt><dd>${esc(v)}</dd></div>`;
7261
+ const rows = [
7262
+ ['局数', `${r.ju}${r.yuan ? `(${r.yuan})` : ''}`],
7263
+ ['节气', `${r.jieqi || '—'}${r.jieqiTime ? `(${r.jieqiTime})` : ''}`],
7264
+ ['四柱', `${r.siZhu ? `${r.siZhu.year} ${r.siZhu.month} ${r.siZhu.day} ${r.siZhu.time}` : '—'}`],
7265
+ ['值符', r.zhiFu ? `${r.zhiFu.star} · ${r.zhiFu.gong}宫` : '—'],
7266
+ ['值使', r.zhiShi ? `${r.zhiShi.gate} · ${r.zhiShi.gong}宫` : '—'],
7267
+ ['旬首', r.xunshou || '—'],
7268
+ ['空亡', (r.kongWang || []).join('') || '—'],
7269
+ ['驿马', r.ma && r.ma.zhi ? `${r.ma.zhi}${r.ma.gong ? `(${r.ma.gong}宫)` : ''}` : '—'],
7270
+ ['换局规则', r.juMethodNote || r.juMethod || '—'],
7271
+ ['晚子时', r.lateZiHourMode === 'next-day' ? '23:00 后归次日' : '23:00 后仍归当日'],
7272
+ ];
7273
+ return `<dl class="relation mp-qm-facts" aria-label="奇门盘面事实">${rows.map(([k, v]) => row(k, v)).join('')}</dl>`;
7274
+ };
7275
+
7000
7276
  const QM_ROWS = [['4', '9', '2'], ['3', '5', '7'], ['8', '1', '6']];
7001
7277
  pp.qimenHTML = function (r) {
7002
7278
  const byGong = {};
@@ -7254,6 +7530,18 @@ const CSS = `
7254
7530
  .mp-seg{display:flex;width:100%;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;overflow:hidden;height:36px}
7255
7531
  .mp-seg button{flex:1;padding:0 8px;background:transparent;border:none;color:var(--dsw-alias-label-secondary);font-size:13px;cursor:pointer}
7256
7532
  .mp-seg button.on{background:var(--dsw-alias-brand-primary);color:#fff}
7533
+ .mp-qmrule{grid-column:1 / -1;border:0;margin:0;padding:0;display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px}
7534
+ .mp-qmrule legend{padding:0}
7535
+ .mp-qmopts{display:flex;flex-wrap:wrap;gap:8px}
7536
+ .mp-qmopt{display:inline-flex;align-items:center;gap:7px;padding:7px 12px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;font-size:13px;cursor:pointer;color:var(--dsw-alias-label-primary)}
7537
+ .mp-qmopt input{accent-color:var(--dsw-alias-brand-primary);margin:0}
7538
+ .mp-qmhelp{flex:1 1 100%;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
7539
+ .mp-qmhelp summary{cursor:pointer}
7540
+ .mp-qmhelp p{margin:6px 0 0}
7541
+ .relation{display:flex;flex-direction:column;gap:6px;margin:14px 0 0;padding:12px;background:var(--dsw-alias-bg-layer-2);border-left:3px solid var(--dsw-alias-brand-primary);border-radius:8px}
7542
+ .relation__row{display:grid;grid-template-columns:96px minmax(0,1fr);gap:8px;align-items:baseline}
7543
+ .relation__row dt{margin:0;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
7544
+ .relation__row dd{margin:0;font-size:13.5px;color:var(--dsw-alias-label-primary)}
7257
7545
  .mp-hist{margin-bottom:14px}
7258
7546
  .mp-hist-h{display:flex;align-items:center;justify-content:space-between;font-size:12px;color:var(--dsw-alias-label-secondary);margin-bottom:6px}
7259
7547
  .mp-hist-clear{background:transparent;border:none;color:var(--dsw-alias-label-secondary);font-size:12px;cursor:pointer;padding:0}
@@ -7321,6 +7609,7 @@ const TABS = [
7321
7609
  { k: 'liuyao', label: '六爻', timeLabel: '起卦时刻', hint: '六爻不需要出生时间:只用起卦当下的日辰定六神、月建定旺衰,卦由摇出。' },
7322
7610
  { k: 'meihua', label: '梅花', timeLabel: '起卦时刻', hint: '梅花用起卦时刻的年月日时数成卦,也可直接给两个数字起卦;与出生时间无关。' },
7323
7611
  { k: 'daliuren', label: '六壬', timeLabel: '起卦时刻', hint: '大六壬用起卦时刻的日干支、时支与月将起天地盘;同样与出生时间无关。' },
7612
+ { k: 'qimen', label: '奇门', timeLabel: '起局时刻', hint: '奇门时家转盘:用起局时刻定节气、三元与局数;换局规则决定符头与节气如何对齐。' },
7324
7613
  { k: 'hepan', label: '合盘', timeLabel: '你的出生时刻', hint: '合盘按「日主 + 夫妻宫 + 五行互补」看两个人的相处与互补,需要双方出生信息。' },
7325
7614
  { k: 'tarot', label: '塔罗', timeLabel: '', hint: '塔罗不看时间,只记录抽牌时刻与你的提问。' },
7326
7615
  ];
@@ -7334,14 +7623,14 @@ function nowParts() {
7334
7623
 
7335
7624
  const TIME_KIND = {
7336
7625
  ziwei: 'birth', bazi: 'birth', hepan: 'birth',
7337
- liuyao: 'cast', meihua: 'cast', daliuren: 'cast',
7626
+ liuyao: 'cast', meihua: 'cast', daliuren: 'cast', qimen: 'cast',
7338
7627
  tarot: 'none',
7339
7628
  };
7340
7629
  const SAMPLE = { date: '1990-05-12', time: '14:30' };
7341
7630
  const kindOf = (t) => TIME_KIND[t] || 'none';
7342
7631
 
7343
- const NEED_ASK = { liuyao: true, meihua: true, daliuren: true, tarot: true };
7344
- const needAsk = (t) => !!NEED_ASK[t];
7632
+ const Core = window.__MPCore || {};
7633
+ const needAsk = Core.needAsk || ((t) => false);
7345
7634
 
7346
7635
  function App() {
7347
7636
  const [tab, setTab] = useState('ziwei');
@@ -7354,6 +7643,7 @@ function App() {
7354
7643
  const [pGender, setPGender] = useState('female');
7355
7644
  const [pAddress, setPAddress] = useState('');
7356
7645
  const [hpChart, setHpChart] = useState('bazi');
7646
+ const [qimenRule, setQimenRule] = useState('chaibu');
7357
7647
  const [trueSolar, setTrueSolar] = useState(true);
7358
7648
  const [onlineGeo, setOnlineGeo] = useState(false);
7359
7649
  const [lines, setLines] = useState('');
@@ -7388,7 +7678,7 @@ function App() {
7388
7678
  const datetime = `${dt.date}T${dt.time}`;
7389
7679
  const args = { system: k };
7390
7680
  if (k !== 'tarot') args.datetime = datetime;
7391
- if (k === 'bazi' || k === 'ziwei') {
7681
+ if (k === 'bazi' || k === 'ziwei' || k === 'hepan') {
7392
7682
  args.gender = gender;
7393
7683
  args.trueSolar = trueSolar;
7394
7684
  if (address.trim()) {
@@ -7402,16 +7692,11 @@ function App() {
7402
7692
  }
7403
7693
  }
7404
7694
  if (k === 'liuyao') {
7405
- const parsed = lines.split(/[^0-9]+/).filter(Boolean).map(Number);
7406
- const bad = parsed.filter((n) => ![6, 7, 8, 9].includes(n));
7407
- if (parsed.length === 6 && bad.length === 0) {
7408
- args.lines = parsed;
7409
- } else if (lines.trim()) {
7410
- setNotice(parsed.length !== 6
7411
- ? `爻值需要正好 6 个数字(当前 ${parsed.length} 个),本次按随机摇卦。`
7412
- : `爻值只能是 6/7/8/9(收到 ${bad.join('/')}),本次按随机摇卦。`);
7413
- }
7695
+ const parsed = Core.parseLines(lines);
7696
+ if (parsed.lines) args.lines = parsed.lines;
7697
+ else if (parsed.warning) setNotice(parsed.warning);
7414
7698
  }
7699
+ if (k === 'qimen') args.juMethod = qimenRule;
7415
7700
  if (k === 'tarot') args.count = Number(count);
7416
7701
  if (k === 'hepan') {
7417
7702
  args.chart = hpChart;
@@ -7451,9 +7736,10 @@ function App() {
7451
7736
  }
7452
7737
  }
7453
7738
  const r = Engine.compute(args);
7454
- const it = Engine.interpret
7455
- ? Engine.interpret(r, needAsk(k) ? { question: question.trim(), direction } : undefined)
7456
- : null;
7739
+ const ask = (needAsk(k) || k === 'qimen')
7740
+ ? { question: needAsk(k) ? question.trim() : '', direction }
7741
+ : undefined;
7742
+ const it = Engine.interpret ? Engine.interpret(r, ask) : null;
7457
7743
  const timed = kindOf(k) === 'cast' && (k !== 'meihua' || mh === 'time');
7458
7744
  setResult({ kind: k, r, it, at: dt, timed });
7459
7745
  setError(''); setCopied('');
@@ -7540,8 +7826,11 @@ function App() {
7540
7826
  };
7541
7827
 
7542
7828
  const refreshInterpret = (dir, q) => {
7543
- if (!result || !needAsk(tab)) return;
7544
- const ask = { question: (q === undefined ? question : q).trim(), direction: dir === undefined ? direction : dir };
7829
+ if (!result || !(needAsk(tab) || tab === 'qimen')) return;
7830
+ const ask = {
7831
+ question: needAsk(tab) ? (q === undefined ? question : q).trim() : '',
7832
+ direction: dir === undefined ? direction : dir,
7833
+ };
7545
7834
  const it = Engine.interpret ? Engine.interpret(result.r, ask) : null;
7546
7835
  setResult(Object.assign({}, result, { it }));
7547
7836
  };
@@ -7627,7 +7916,22 @@ function App() {
7627
7916
  className: 'mp-input', placeholder: '如 四川成都', value: pAddress,
7628
7917
  onChange: (e) => setPAddress(e.target.value),
7629
7918
  })) : null,
7630
- needAsk(tab) ? field('询问方向', h('select', {
7919
+ tab === 'qimen' ? h('fieldset', { key: 'qmr', className: 'mp-qmrule' },
7920
+ h('legend', { className: 'mp-lbl' }, '换局规则'),
7921
+ h('div', { className: 'mp-qmopts', role: 'radiogroup', 'aria-label': '奇门换局规则' },
7922
+ [['chaibu', '拆补'], ['chaoshen', '超神接气'], ['zhirun', '置闰']].map(([value, label]) => h('label', {
7923
+ key: value, className: 'mp-qmopt',
7924
+ },
7925
+ h('input', {
7926
+ type: 'radio', name: 'qimen_rule', value,
7927
+ checked: qimenRule === value,
7928
+ onChange: () => setQimenRule(value),
7929
+ }),
7930
+ h('span', null, label)))),
7931
+ h('details', { className: 'mp-qmhelp' },
7932
+ h('summary', null, '三种规则有什么区别?'),
7933
+ h('p', null, '决定符头与节气如何对齐、是否插入闰局;同一个时刻在不同规则下可能得到不同局数。默认「拆补」与工具层一致。'))) : null,
7934
+ needAsk(tab) || tab === 'qimen' ? field(tab === 'qimen' ? '询问方向(定用神)' : '询问方向', h('select', {
7631
7935
  className: 'mp-input', value: direction,
7632
7936
  onChange: (e) => { setDirection(e.target.value); refreshInterpret(e.target.value); },
7633
7937
  }, (Engine.DIRECTIONS || []).map((d) => h('option', { key: d.key, value: d.key }, d.label)))) : null,
@@ -7713,6 +8017,7 @@ function App() {
7713
8017
  : result.kind === 'bazi' ? PP.baziHTML(result.r)
7714
8018
  : result.kind === 'meihua' ? PP.meihuaHTML(result.r)
7715
8019
  : result.kind === 'daliuren' ? PP.daliurenHTML(result.r)
8020
+ : result.kind === 'qimen' ? (PP.qimenHTML(result.r) + PP.qimenFactsHTML(result.r))
7716
8021
  : result.kind === 'hepan' ? (result.r.chart === 'ziwei' ? PP.ziweiHepanHTML(result.r) : PP.hepanHTML(result.r))
7717
8022
  : result.kind === 'tarot' ? PP.tarotHTML(result.r)
7718
8023
  : PP.liuyaoHTML(result.r),