guanwei 1.1.1 → 1.1.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.
Files changed (55) hide show
  1. package/README.en.md +5 -2
  2. package/README.md +6 -3
  3. package/dist/assets/index-C3wrtpPY.css +1 -0
  4. package/dist/assets/{index-CsOD5rSo.js → index-CAyAIgw8.js} +25 -25
  5. package/dist/assets/index-CAyAIgw8.js.map +1 -0
  6. package/dist/index.html +2 -2
  7. package/package.json +2 -2
  8. package/scripts/release.sh +29 -5
  9. package/server/src/data/db.json +168 -0
  10. package/server/src/index.ts +27 -4
  11. package/server/src/routes/ai.ts +37 -0
  12. package/server/src/routes/tarot.ts +4 -4
  13. package/server/src/routes/users.ts +42 -7
  14. package/server/src/services/divineStore.ts +1 -5
  15. package/server/src/services/promptBuilder.ts +2 -2
  16. package/server/src/types/index.ts +2 -104
  17. package/{src → shared/core}/data/lifeContext.ts +2 -8
  18. package/{src → shared/core}/data/spreads.ts +1 -1
  19. package/{src → shared/core}/data/tarotCards.ts +1 -1
  20. package/shared/core/engine/bazi.ts +0 -1
  21. package/shared/core/engine/calendar.ts +1 -1
  22. package/{server/src/utils → shared/core/engine}/semanticAnalyzer.ts +9 -46
  23. package/{server/src/utils → shared/core/engine}/tarotEngine.ts +6 -6
  24. package/shared/core/engine/ziwei.ts +3 -2
  25. package/shared/core/engine/ziweiInterpret.ts +0 -3
  26. package/shared/core/types.ts +157 -0
  27. package/src/arts/registry.ts +1 -1
  28. package/src/components/QuestionFields.tsx +0 -1
  29. package/src/components/ReportView.tsx +0 -1
  30. package/src/components/TimeShichenInput.tsx +1 -0
  31. package/src/components/arts/BaziArt.tsx +0 -10
  32. package/src/components/arts/LiurenArt.tsx +1 -1
  33. package/src/components/arts/LiuyaoArt.tsx +0 -1
  34. package/src/components/arts/MeihuaArt.tsx +0 -1
  35. package/src/components/arts/QimenArt.tsx +0 -1
  36. package/src/components/arts/TarotArt.tsx +2 -2
  37. package/src/components/arts/XiaoliurenArt.tsx +1 -2
  38. package/src/components/arts/ZiweiArt.tsx +2 -15
  39. package/src/pages/AuthPage.tsx +4 -6
  40. package/src/pages/DemoPage.tsx +1 -2
  41. package/src/pages/HistoryPage.tsx +10 -9
  42. package/src/pages/ModulePage.tsx +25 -32
  43. package/src/pages/SpreadLibrary.tsx +1 -1
  44. package/src/pages/TarotPage.tsx +7 -9
  45. package/src/services/api.ts +4 -4
  46. package/src/stores/useDivinationStore.ts +1 -1
  47. package/src/types/index.ts +2 -104
  48. package/tsconfig.json +5 -5
  49. package/dist/assets/index-CsOD5rSo.js.map +0 -1
  50. package/dist/assets/index-DQx62TUr.css +0 -1
  51. package/server/src/data/lifeContext.ts +0 -423
  52. package/server/src/data/spreads.ts +0 -255
  53. package/server/src/data/tarotCards.ts +0 -2353
  54. package/src/utils/semanticAnalyzer.ts +0 -555
  55. package/src/utils/tarotEngine.ts +0 -849
@@ -1,53 +1,16 @@
1
1
  // 问题语义分析器
2
2
  // 在解读阶段对用户问题进行多维度分析
3
+ // 类型定义收敛自 shared/core/types.ts(单一副本),此处仅保留分析与函数逻辑
3
4
 
4
- export type Scene = 'love' | 'career' | 'wealth' | 'study' | 'health' | 'family' | 'friendship' | 'spiritual' | 'travel' | 'general';
5
- export type Emotion = 'anxious' | 'hopeful' | 'confused' | 'lost' | 'grateful' | 'calm' | 'angry' | 'sad' | 'curious';
6
- export type Tense = 'past' | 'present' | 'future' | 'hypothetical' | 'ongoing';
7
- export type Subject = 'self' | 'other' | 'mutual' | 'third-party';
8
- export type Depth = 'surface' | 'mid' | 'deep';
9
-
10
- // 问题类型:决策 / 预测 / 原因 / 建议 / 读心 / 时间 / 通用
11
- export type QuestionType = 'decision' | 'prediction' | 'reason' | 'advice' | 'mindreading' | 'timing' | 'general';
12
- // 用户需要的回应方式:安慰 / 方向 / 确认 / 警示
13
- export type ResponseNeed = 'comfort' | 'direction' | 'confirmation' | 'warning';
14
-
15
- // 关键实体
16
- export interface KeyEntity {
17
- type: 'person' | 'event' | 'time';
18
- value: string;
19
- }
20
-
21
- // 问题的深度分析
22
- export interface QuestionAnalysis {
23
- realQuestion: string; // 用户真正想问的是什么
24
- emotionalNeed: string; // 问题背后的情绪需求
25
- responseNeed: ResponseNeed; // 用户需要什么样的回应
26
- responseNeedLabel: string;
27
- }
5
+ import type {
6
+ Scene, Emotion, Tense, Subject, Depth,
7
+ QuestionType, ResponseNeed, KeyEntity, QuestionAnalysis, SemanticAnalysis,
8
+ } from '../types.js';
28
9
 
29
- export interface SemanticAnalysis {
30
- scene: Scene;
31
- sceneLabel: string;
32
- emotion: Emotion;
33
- emotionLabel: string;
34
- tense: Tense;
35
- tenseLabel: string;
36
- subject: Subject;
37
- subjectLabel: string;
38
- depth: Depth;
39
- depthLabel: string;
40
- keywords: string[];
41
- intensity: number; // 0-1,问题强度
42
- confidence: number; // 0-1,分析置信度
43
- // —— 以下为新增字段 ——
44
- questionType: QuestionType; // 问题类型
45
- questionTypeLabel: string; // 问题类型中文标签
46
- questionCore: string; // 问题的核心意图
47
- questionSummary: string; // 一句话概括用户问题的本质
48
- keyEntities: KeyEntity[]; // 问题中的关键实体
49
- questionAnalysis: QuestionAnalysis; // 深度分析问题的潜台词
50
- }
10
+ export type {
11
+ Scene, Emotion, Tense, Subject, Depth,
12
+ QuestionType, ResponseNeed, KeyEntity, QuestionAnalysis, SemanticAnalysis,
13
+ };
51
14
 
52
15
  // 场景关键词库
53
16
  const SCENE_KEYWORDS: Record<Scene, { label: string; words: string[]; weight: number }> = {
@@ -1,6 +1,6 @@
1
- import type { TarotCard, DrawnCard, Spread, QuestionCategory } from '../types/index.js';
1
+ import type { TarotCard, DrawnCard, Spread, QuestionCategory } from '../types.js';
2
2
  import { tarotCards } from '../data/tarotCards.js';
3
- import { analyzeQuestion, type SemanticAnalysis, type Scene, type Emotion } from '../utils/semanticAnalyzer.js';
3
+ import { analyzeQuestion, type SemanticAnalysis, type Scene, type Emotion } from './semanticAnalyzer.js';
4
4
  import { LIFE_CONTEXTS } from '../data/lifeContext.js';
5
5
 
6
6
  type LifeAreaKey = 'love' | 'career' | 'wealth' | 'health' | 'growth';
@@ -157,7 +157,7 @@ ${revealLines[Math.floor(Math.random() * revealLines.length)]}`;
157
157
  function generateOverviewSection(
158
158
  cards: DrawnCard[],
159
159
  spread: Spread,
160
- question: string,
160
+ _question: string,
161
161
  semantic: SemanticAnalysis
162
162
  ): InterpretationSection {
163
163
  const cardData = cards.map((drawn) => {
@@ -316,7 +316,7 @@ function generateOverviewSection(
316
316
 
317
317
  function generateOverviewStoryFlow(
318
318
  cardData: { card: TarotCard; drawn: DrawnCard; position: { name: string; description: string } }[],
319
- semantic: SemanticAnalysis
319
+ _semantic: SemanticAnalysis
320
320
  ): string {
321
321
  if (cardData.length === 0) return '';
322
322
 
@@ -362,7 +362,7 @@ function generateCardSection(
362
362
  position: { name: string; description: string },
363
363
  index: number,
364
364
  semantic: SemanticAnalysis,
365
- lifeContext: typeof LIFE_CONTEXTS.love,
365
+ _lifeContext: typeof LIFE_CONTEXTS.love,
366
366
  totalCards: number
367
367
  ): InterpretationSection {
368
368
  const orientation = drawn.isReversed ? '逆位' : '正位';
@@ -429,7 +429,7 @@ ${selectedSymbols[0] || '画面里的核心意象'}在这个位置倒过来,
429
429
  };
430
430
  }
431
431
 
432
- function generateEsotericSection(cards: DrawnCard[], semantic: SemanticAnalysis): InterpretationSection {
432
+ function generateEsotericSection(cards: DrawnCard[], _semantic: SemanticAnalysis): InterpretationSection {
433
433
  const elements: Record<string, number> = { 火: 0, 水: 0, 风: 0, 土: 0, 以太: 0 };
434
434
  const planets = new Set<string>();
435
435
  const sephiroth = new Set<string>();
@@ -1,8 +1,9 @@
1
1
  // 紫微斗数:简式星盘(命宫/五行局/紫微定位/十四主星)+ 补齐层(辅星/身宫/四化/庙旺/格局)
2
- import { NAYIN, NAYIN_JU, ganZhiIndex, mod } from '../data/ganzhi';
2
+ import { NAYIN, ganZhiIndex, mod } from '../data/ganzhi';
3
+ import { GAN } from '../data/ganzhi';
3
4
  import { trueSolarTime } from './trueSolarTime';
4
5
  import type { ZiweiInput, ZiweiResult } from '../types';
5
- import { GAN, ZHI } from '../data/ganzhi';
6
+
6
7
  import { PALACE_NAMES, ZW_SIHUA, ZW_BRIGHTNESS, LU_CUN, KUI_YUE, TIAN_MA, HUO_START, LING_START, ZW_GEJU } from '../data/ziwei';
7
8
 
8
9
  // 地支位:0=寅 起(与既有约定一致)
@@ -73,9 +73,6 @@ export function interpretZiwei(r: ZiweiResult): ZiweiInsight[] {
73
73
  const stars = starsOf(r, pos);
74
74
  if (stars.length === 0) continue;
75
75
  const pname = PALACE_NAMES[i];
76
- const brief = stars.map(starBrief).join(';');
77
- const line = pname + '宫(' + DIZHI[pos] + ')见' + stars.join('、') + '——' + brief + '。此宫主' + palaceTheme(pname) + '。'
78
- + stars[0] + '入' + pname + ',' + (GOOD_STARS.includes(stars[0]) ? '为得地之象,多主顺遂。' : '须留意分寸,化其棱角则吉。');
79
76
  overview.push({ name: pname, stars, pos });
80
77
  }
81
78
  out.push({
@@ -198,6 +198,163 @@ export interface TarotCardData {
198
198
  reversed: boolean;
199
199
  }
200
200
 
201
+ // ─── 塔罗解读链路(原 src/types + src/utils/semanticAnalyzer 收敛至此,双端单一副本)───
202
+ export interface TarotCard {
203
+ id: number;
204
+ name: string;
205
+ nameEn: string;
206
+ arcana: 'major' | 'minor';
207
+ suit?: 'wands' | 'cups' | 'swords' | 'pentacles';
208
+ number?: number;
209
+ keywords: string[];
210
+ meanings: {
211
+ upright: string;
212
+ reversed: string;
213
+ };
214
+ deepMeaning: {
215
+ coreTheme: string;
216
+ psychological: string;
217
+ spiritual: string;
218
+ shadow: string;
219
+ lifeAreas: {
220
+ love: string;
221
+ career: string;
222
+ wealth: string;
223
+ health: string;
224
+ growth: string;
225
+ };
226
+ advice: string;
227
+ warning: string;
228
+ };
229
+ imageSymbols: string[];
230
+ story: string;
231
+ astrology: {
232
+ zodiac?: string;
233
+ planet?: string;
234
+ element?: string;
235
+ };
236
+ kabbalah: {
237
+ path?: number;
238
+ sephirah?: string;
239
+ };
240
+ alchemy: {
241
+ stage?: string;
242
+ element?: string;
243
+ };
244
+ numerology: {
245
+ number: number;
246
+ meaning: string;
247
+ };
248
+ image: string;
249
+ }
250
+
251
+ export interface SpreadPosition {
252
+ id: number;
253
+ name: string;
254
+ description: string;
255
+ x: number;
256
+ y: number;
257
+ }
258
+
259
+ export interface Spread {
260
+ id: string;
261
+ name: string;
262
+ description: string;
263
+ positions: SpreadPosition[];
264
+ category: 'basic' | 'advanced' | 'custom';
265
+ scene?: string[];
266
+ isCustom?: boolean;
267
+ }
268
+
269
+ export interface DrawnCard {
270
+ cardId: number;
271
+ isReversed: boolean;
272
+ positionId: number;
273
+ }
274
+
275
+ export interface DivinationRecord {
276
+ id: string;
277
+ type: 'tarot' | 'combo' | 'ziwei' | 'bazi' | 'astrology';
278
+ question: string;
279
+ category: string;
280
+ spreadId?: string;
281
+ cards?: DrawnCard[];
282
+ comboMethod?: string;
283
+ comboResult?: string;
284
+ interpretation: string;
285
+ timestamp: number;
286
+ }
287
+
288
+ export interface ComboResult {
289
+ method: 'xiaoliuren' | 'daliuren' | 'liuyao' | 'meihua' | 'qimen';
290
+ methodName: string;
291
+ result: string;
292
+ detail: string;
293
+ relationToTarot: string;
294
+ }
295
+
296
+ export type QuestionCategory = 'love' | 'career' | 'wealth' | 'health' | 'study' | 'family' | 'friendship' | 'spiritual' | 'travel' | 'general';
297
+
298
+ export interface TarotReading {
299
+ question: string;
300
+ category: QuestionCategory;
301
+ spreadId: string;
302
+ cards: DrawnCard[];
303
+ interpretation: string;
304
+ comboResult?: ComboResult;
305
+ }
306
+
307
+ // 问题语义分析(原 src/utils/semanticAnalyzer 类型部分)
308
+ export type Scene = 'love' | 'career' | 'wealth' | 'study' | 'health' | 'family' | 'friendship' | 'spiritual' | 'travel' | 'general';
309
+ export type Emotion = 'anxious' | 'hopeful' | 'confused' | 'lost' | 'grateful' | 'calm' | 'angry' | 'sad' | 'curious';
310
+ export type Tense = 'past' | 'present' | 'future' | 'hypothetical' | 'ongoing';
311
+ export type Subject = 'self' | 'other' | 'mutual' | 'third-party';
312
+ export type Depth = 'surface' | 'mid' | 'deep';
313
+ export type QuestionType = 'decision' | 'prediction' | 'reason' | 'advice' | 'mindreading' | 'timing' | 'general';
314
+ export type ResponseNeed = 'comfort' | 'direction' | 'confirmation' | 'warning';
315
+
316
+ export interface KeyEntity {
317
+ type: 'person' | 'event' | 'time';
318
+ value: string;
319
+ }
320
+
321
+ export interface QuestionAnalysis {
322
+ realQuestion: string;
323
+ emotionalNeed: string;
324
+ responseNeed: ResponseNeed;
325
+ responseNeedLabel: string;
326
+ }
327
+
328
+ export interface SemanticAnalysis {
329
+ scene: Scene;
330
+ sceneLabel: string;
331
+ emotion: Emotion;
332
+ emotionLabel: string;
333
+ tense: Tense;
334
+ tenseLabel: string;
335
+ subject: Subject;
336
+ subjectLabel: string;
337
+ depth: Depth;
338
+ depthLabel: string;
339
+ keywords: string[];
340
+ intensity: number; // 0-1,问题强度
341
+ confidence: number; // 0-1,分析置信度
342
+ questionType: QuestionType; // 问题类型
343
+ questionTypeLabel: string; // 问题类型中文标签
344
+ questionCore: string; // 问题的核心意图
345
+ questionSummary: string; // 一句话概括用户问题的本质
346
+ keyEntities: KeyEntity[]; // 问题中的关键实体
347
+ questionAnalysis: QuestionAnalysis; // 深度分析问题的潜台词
348
+ }
349
+
350
+ export interface LifeContext {
351
+ scenes: string[];
352
+ actions: string[];
353
+ warnings: string[];
354
+ timeline: { short: string; mid: string; long: string };
355
+ emotionAdvice: Record<Emotion, string>;
356
+ }
357
+
201
358
  // 通用引擎契约
202
359
  export interface ArtEngine<TInput, TResult> {
203
360
  id: ArtId;
@@ -11,7 +11,7 @@ import { AstrologyPanel, AstrologyResult } from '@/components/arts/AstrologyArt'
11
11
  import { TarotPanel, TarotResult } from '@/components/arts/TarotArt';
12
12
 
13
13
  export interface ArtPair {
14
- Panel: ComponentType<{ onDivine: (fn: () => unknown) => void }>;
14
+ Panel: ComponentType<{ onDivine: (...args: any[]) => void }>;
15
15
  Result: ComponentType<{ data: any }>;
16
16
  placeholder: string;
17
17
  }
@@ -1,5 +1,4 @@
1
1
  // 所问之事的统一输入:类型选择 + 问题输入(占问类必填区,命盘类可留白)
2
- import { useState } from 'react';
3
2
  import SongSelect from '@/components/SongSelect';
4
3
 
5
4
  const DEFAULT_TYPES = [
@@ -1,6 +1,5 @@
1
1
  // AI 解读报告结构化展示:按 Schema 匹配填充(命盘类/占问类)
2
2
  import type { AIReport } from '@/services/api';
3
- import { ResultCard } from '@/components/ResultCard';
4
3
 
5
4
  interface Props {
6
5
  report: AIReport;
@@ -9,6 +9,7 @@ interface Props {
9
9
  }
10
10
 
11
11
  export default function TimeShichenInput({ value, onChange, id, label = '出生时刻(精确)' }: Props) {
12
+ void label;
12
13
  return (
13
14
  <div>
14
15
  <div style={{ display: 'flex', gap: '.5rem', alignItems: 'stretch' }}>
@@ -1,6 +1,5 @@
1
1
  // 四柱八字:输入面板(含出生地点→真太阳时)+ 结果渲染(四柱/五行/十神)
2
2
  import { useState } from 'react';
3
- import { baziCalc } from '@core/engine/bazi';
4
3
  import { SHISHEN_MAP, WUXING } from '@core/data/ganzhi';
5
4
  import type { BaziResult, GeoLocation } from '@core/types';
6
5
  import type { UserProfile } from '@/utils/userStore';
@@ -258,12 +257,3 @@ export function BaziResult({ data }: { data: BaziResult }) {
258
257
  </>
259
258
  );
260
259
  }
261
- // 十神格局点睛
262
- function shishenFocus(r: any): string {
263
- const names = r.shishen.map((s: any) => s.name);
264
- if (names.includes('正官') || names.includes('七杀')) return '官杀透干,主担当与约束,成事在于守正。';
265
- if (names.includes('正财') || names.includes('偏财')) return '财星显露,主经营与所得,宜务实聚财。';
266
- if (names.includes('正印') || names.includes('偏印')) return '印星为用,主学识与荫庇,宜向学深造。';
267
- if (names.includes('食神') || names.includes('伤官')) return '食伤泄秀,主才情与输出,宜展露所长。';
268
- return '比劫同气,主自立与同侪,宜广结善缘。';
269
- }
@@ -1,6 +1,6 @@
1
1
  // 大六壬:起课面板 + 天地盘/四课三传渲染
2
2
  import { useState } from 'react';
3
- import { liurenCalc, jiangName } from '@core/engine/liuren';
3
+ import { jiangName } from '@core/engine/liuren';
4
4
  import { ZHI } from '@core/data/ganzhi';
5
5
  import { LR_JIANG_SYMBOL, LR_JIANG_WX } from '@core/data/liuren';
6
6
  import type { LiurenResult } from '@core/types';
@@ -1,6 +1,5 @@
1
1
  // 六爻:铜钱摇卦面板 + 六爻/卦象渲染
2
2
  import { useState } from 'react';
3
- import { liuyaoCalc } from '@core/engine/liuyao';
4
3
  import type { LiuyaoResult } from '@core/types';
5
4
  import { ResultCard } from '@/components/ResultCard';
6
5
  import SongSelect from '@/components/SongSelect';
@@ -1,6 +1,5 @@
1
1
  // 梅花易数:起卦面板(时间/报数)+ 卦象渲染(本卦/互卦/变卦 + 体用)
2
2
  import { useState } from 'react';
3
- import { meihuaCalc } from '@core/engine/meihua';
4
3
  import { BAGUA } from '@core/data/gua64';
5
4
  import type { MeihuaResult } from '@core/types';
6
5
  import { ResultCard } from '@/components/ResultCard';
@@ -1,6 +1,5 @@
1
1
  // 奇门遁甲:起局面板 + 九宫盘渲染
2
2
  import { useState } from 'react';
3
- import { qimenCalc } from '@core/engine/qimen';
4
3
  import type { QimenResult } from '@core/types';
5
4
  import { ResultCard } from '@/components/ResultCard';
6
5
  import SongSelect from '@/components/SongSelect';
@@ -1,7 +1,7 @@
1
1
  // 塔罗:问镜面板(牌阵选择)+ 扇形翻牌(未翻开不示牌名)+ 牌阵之示
2
2
  import { useState } from 'react';
3
3
  import { Link } from 'react-router-dom';
4
- import { tarotDraw, SUIT } from '@core/engine/tarot';
4
+ import { SUIT } from '@core/engine/tarot';
5
5
  import { allTarotSpreads, type TarotSpread } from '@core/data/tarotSpreads';
6
6
  import type { TarotCardData } from '@core/types';
7
7
  import { ResultCard } from '@/components/ResultCard';
@@ -96,7 +96,7 @@ export function TarotResult({ data }: { data: DrawResult }) {
96
96
  );
97
97
  }
98
98
  // 塔罗全阵参详(正逆位比例 + 元素侧重,现代语言)
99
- function tarotSummary(cards: any[], spread: any): string {
99
+ function tarotSummary(cards: any[], _spread: any): string {
100
100
  const rev = cards.filter(c => c.reversed).length;
101
101
  const majors = cards.filter(c => c.major).length;
102
102
  const parts: string[] = [];
@@ -1,7 +1,6 @@
1
1
  // 小六壬:掐指占时面板 + 掌诀/推演轨迹渲染
2
2
  import { useState } from 'react';
3
- import { xiaoliurenCalc } from '@core/engine/xiaoliuren';
4
- import { XLR_ORDER, XLR } from '@core/data/xiaoliuren';
3
+ import { XLR_ORDER } from '@core/data/xiaoliuren';
5
4
  import { mod } from '@core/data/ganzhi';
6
5
  import type { XiaoliurenResult } from '@core/types';
7
6
  import { ResultCard } from '@/components/ResultCard';
@@ -1,9 +1,7 @@
1
1
  // 紫微斗数:输入面板(干支年/农历月日时 + 地点经度校正)+ 紫微盘渲染
2
2
  import { useState } from 'react';
3
- import { ziweiCalc } from '@core/engine/ziwei';
4
- import { ZW_STARS, ZW_STAR_MEAN, PALACE_NAMES } from '@core/data/ziwei';
3
+ import { PALACE_NAMES } from '@core/data/ziwei';
5
4
  import { interpretZiwei } from '@core/engine/ziweiInterpret';
6
- import { ganZhiIndex, GAN, ZHI, NAYIN } from '@core/data/ganzhi';
7
5
  import { timeToHourIndex, hourIndexLabel } from '@/data/shichen';
8
6
  import TimeShichenInput from '@/components/TimeShichenInput';
9
7
  import type { ZiweiResult, GeoLocation } from '@core/types';
@@ -22,16 +20,6 @@ import LifeEventsInput, { type LifeEvent } from '@/components/LifeEventsInput';
22
20
  const DIZHI = ['寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥', '子', '丑'];
23
21
  const mod = (a: number, n: number) => ((a % n) + n) % n;
24
22
 
25
- // 干支年选项(1950-2010)
26
- function ganzhiOptions() {
27
- const out: { gz: string; year: number }[] = [];
28
- for (let y = 1950; y <= 2010; y++) {
29
- const i = ((y - 4) % 60 + 60) % 60;
30
- out.push({ gz: GAN[i % 10] + ZHI[i % 12], year: y });
31
- }
32
- return out;
33
- }
34
-
35
23
  interface PanelProps { onDivine: (inputs: unknown, profile?: UserProfile, question?: string, profileId?: string) => void; }
36
24
 
37
25
  export function ZiweiPanel({ onDivine }: PanelProps) {
@@ -53,7 +41,7 @@ export function ZiweiPanel({ onDivine }: PanelProps) {
53
41
  if (new Date(yy, mm - 1, dd).getMonth() !== mm - 1) { setFormMsg('⚠ 出生日期不合法,请检查'); return; }
54
42
  setFormMsg('');
55
43
  // 公历 → 农历(万年历),紫微依农历排盘
56
- let lm = 1, ld = 1, gz = '甲子', birthYear = yy;
44
+ let lm = 1, ld = 1, gz = '甲子';
57
45
  try {
58
46
  const lunar = Solar.fromYmd(yy, mm, dd).getLunar();
59
47
  const rawMonth = lunar.getMonth();
@@ -61,7 +49,6 @@ export function ZiweiPanel({ onDivine }: PanelProps) {
61
49
  // 闰月(lunar 返回负数):按 iztro fixLeap 规则,后半月算下月
62
50
  lm = Math.abs(rawMonth) + (rawMonth < 0 && ld > 15 ? 1 : 0);
63
51
  gz = lunar.getYearInGanZhi();
64
- birthYear = lunar.getYear();
65
52
  } catch { /* 非法日期回退默认 */ }
66
53
  // 时辰未知:紫微以午时示例排盘(仅命局五行参考),档案标记未知供 AI 解读约束
67
54
  const hourIdx = hourUnknown ? 6 : timeToHourIndex(birthTime);
@@ -5,15 +5,13 @@ import { apiDivineHistory, apiDivineDetail, apiDivineDelete, downloadReport } fr
5
5
  import ReportView from '@/components/ReportView';
6
6
  import {
7
7
  register, login, logout, currentUser, updateProfile,
8
- addSampleProfile, updateSampleProfile, removeSampleProfile, promoteSampleProfile,
9
- DEFAULT_PROFILE, type UserProfile, type NamedProfile,
8
+ updateSampleProfile, removeSampleProfile, promoteSampleProfile,
9
+ type UserProfile, type NamedProfile,
10
10
  } from '@/utils/userStore';
11
11
  import { useConfirm } from '@/components/SongDialog';
12
12
  import { syncRecordsFromServer } from '@/utils/recordStore';
13
13
  import { syncProfileToServer } from '@/utils/userStore';
14
14
  import ProfileForm from '@/components/ProfileForm';
15
- import SongSelect from '@/components/SongSelect';
16
-
17
15
  export default function AuthPage() {
18
16
  const navigate = useNavigate();
19
17
  const confirm = useConfirm();
@@ -220,12 +218,12 @@ export default function AuthPage() {
220
218
  <p>此占尚未召 AI 成文,仅存排盘之象</p>
221
219
  </div>
222
220
  )}
223
- {histDetail.resultRaw && (
221
+ {histDetail.resultRaw ? (
224
222
  <details className="mh-intro" style={{ marginTop: 'var(--sp-2)' }}>
225
223
  <summary>排盘原始数据</summary>
226
224
  <pre style={{ fontSize: '.72rem', lineHeight: 1.7, whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>{JSON.stringify(histDetail.resultRaw, null, 1)}</pre>
227
225
  </details>
228
- )}
226
+ ) : null}
229
227
  </div>
230
228
  </div>
231
229
  )}
@@ -67,7 +67,6 @@ export default function DemoPage() {
67
67
  const [artId, setArtId] = useState('bazi');
68
68
  const [localResult, setLocalResult] = useState<unknown>(null);
69
69
  const art = ARTS.find(a => a.id === artId)!;
70
- const chart = baziCalc(DEMO_BIRTH);
71
70
 
72
71
  const reset = () => {
73
72
  setPhase('idle');
@@ -136,7 +135,7 @@ export default function DemoPage() {
136
135
  {phase === 'done' && (
137
136
  <>
138
137
  <div className="altar-result stagger">
139
- {localResult && RESULT_VIEWS[artId]?.(localResult)}
138
+ {localResult ? RESULT_VIEWS[artId]?.(localResult) : null}
140
139
  {report && (
141
140
  <div className="result-card mt-3">
142
141
  <h3>AI 深度解读 <span className="tag-cool" style={{ marginLeft: '.4rem', fontSize: '.72rem' }}>示例报告</span></h3>
@@ -61,7 +61,7 @@ export default function HistoryPage() {
61
61
  }
62
62
 
63
63
  const records = useMemo(() => getRecords(), [tick, artFilter, search]);
64
- const [profileFilter, setProfileFilter] = useState('all');
64
+ const [profileFilter] = useState('all');
65
65
  const filtered = records.filter(r => {
66
66
  if (profileFilter !== 'all' && (r.profileId || 'main') !== profileFilter) return false;
67
67
  if (artFilter !== 'all' && r.artId !== artFilter) return false;
@@ -115,15 +115,16 @@ export default function HistoryPage() {
115
115
  function summarize(result: unknown): string {
116
116
  const r = result as Record<string, any>;
117
117
  if (!r) return '(结果不可读)';
118
- if (r.yearGZ) return `${r.yearGZ}年 ${r.monthGZ}月 ${r.dayGZ}日 ${r.hourGZ}时 · ${r.strength || ''}`;
119
- if (r.benGua) return `本卦${r.benGua.name} · ${r.bianGua ? '变' + r.bianGua.name : ''} · ${r.shengke || ''}`;
120
- if (r.ju) return `${r.jqName} · ${r.yin ? '阴' : '阳'}遁${r.ju}局 · ${r.dayGZ}日`;
121
- if (r.name && r.detail) return `${r.name} · ${r.detail.ji || ''} · ${r.detail.wx || ''}`;
122
- if (r.jiang) return `${r.jiang}将加时 · 四课${r.ke1}/${r.ke2}/${r.ke3}/${r.ke4}`;
123
- if (r.ming !== undefined) return `命宫@${r.ming} · ${r.juName || ''} · 紫微@${r.zwPos}`;
118
+ const o: Record<string, any> = Array.isArray(r) ? {} : r;
119
+ if (o.yearGZ) return `${o.yearGZ}年 ${o.monthGZ}月 ${o.dayGZ}日 ${o.hourGZ}时 · ${o.strength || ''}`;
120
+ if (o.benGua) return `本卦${o.benGua.name} · ${o.bianGua ? '变' + o.bianGua.name : ''} · ${o.shengke || ''}`;
121
+ if (o.ju) return `${o.jqName} · ${o.yin ? '阴' : '阳'}遁${o.ju}局 · ${o.dayGZ}日`;
122
+ if (o.name && o.detail) return `${o.name} · ${o.detail.ji || ''} · ${o.detail.wx || ''}`;
123
+ if (o.jiang) return `${o.jiang}将加时 · 四课${o.ke1}/${o.ke2}/${o.ke3}/${o.ke4}`;
124
+ if (o.ming !== undefined) return `命宫@${o.ming} · ${o.juName || ''} · 紫微@${o.zwPos}`;
124
125
  if (Array.isArray(r) && r[0] && r[0].name) return `${r.length} 张牌:${r.map((c: any) => c.name).join('、')}`;
125
- if (r.planets) return `太阳落${signOf(r.sun)} · 月亮落${signOf(r.moon)}`;
126
- if (r.yin !== undefined) return `${r.jqName || ''} · ${r.yin ? '阴' : '阳'}遁${r.ju}局`;
126
+ if (o.planets) return `太阳落${signOf(o.sun)} · 月亮落${signOf(o.moon)}`;
127
+ if (o.yin !== undefined) return `${o.jqName || ''} · ${o.yin ? '阴' : '阳'}遁${o.ju}局`;
127
128
  return JSON.stringify(r).slice(0, 40);
128
129
  }
129
130