guanwei 1.1.1

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 (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +202 -0
  3. package/README.md +247 -0
  4. package/dist/assets/index-CsOD5rSo.js +102 -0
  5. package/dist/assets/index-CsOD5rSo.js.map +1 -0
  6. package/dist/assets/index-DQx62TUr.css +1 -0
  7. package/dist/favicon.svg +12 -0
  8. package/dist/index.html +15 -0
  9. package/eslint.config.js +28 -0
  10. package/index.html +25 -0
  11. package/package.json +96 -0
  12. package/postcss.config.js +10 -0
  13. package/public/favicon.svg +12 -0
  14. package/scripts/guanwei +245 -0
  15. package/scripts/install.sh +79 -0
  16. package/scripts/release.sh +42 -0
  17. package/scripts/setup.bat +36 -0
  18. package/scripts/setup.sh +123 -0
  19. package/server/src/data/db.json +12059 -0
  20. package/server/src/data/guanwei.db +0 -0
  21. package/server/src/data/lifeContext.ts +423 -0
  22. package/server/src/data/spreads.ts +255 -0
  23. package/server/src/data/tarotCards.ts +2353 -0
  24. package/server/src/index.ts +71 -0
  25. package/server/src/routes/ai.ts +376 -0
  26. package/server/src/routes/divine.ts +140 -0
  27. package/server/src/routes/hour.ts +40 -0
  28. package/server/src/routes/tarot.ts +129 -0
  29. package/server/src/routes/users.ts +140 -0
  30. package/server/src/services/chartBrief.ts +131 -0
  31. package/server/src/services/divineStore.ts +188 -0
  32. package/server/src/services/hourInference.ts +150 -0
  33. package/server/src/services/llmProvider.ts +181 -0
  34. package/server/src/services/promptBuilder.ts +327 -0
  35. package/server/src/services/relativesCheck.ts +139 -0
  36. package/server/src/services/sixRelatives.ts +70 -0
  37. package/server/src/services/skills.ts +116 -0
  38. package/server/src/types/index.ts +104 -0
  39. package/server/src/utils/semanticAnalyzer.ts +555 -0
  40. package/server/src/utils/tarotEngine.ts +849 -0
  41. package/server/tsconfig.json +18 -0
  42. package/shared/core/data/classics.ts +276 -0
  43. package/shared/core/data/courses.ts +211 -0
  44. package/shared/core/data/duanyu.ts +148 -0
  45. package/shared/core/data/ganzhi.ts +53 -0
  46. package/shared/core/data/gua64.ts +93 -0
  47. package/shared/core/data/liuren.ts +18 -0
  48. package/shared/core/data/liuyao.ts +73 -0
  49. package/shared/core/data/qimen.ts +27 -0
  50. package/shared/core/data/region-full.ts +3 -0
  51. package/shared/core/data/region.ts +310 -0
  52. package/shared/core/data/tarotSpreads.ts +78 -0
  53. package/shared/core/data/xiaoliuren.ts +18 -0
  54. package/shared/core/data/ziwei.ts +97 -0
  55. package/shared/core/data/zodiac.ts +20 -0
  56. package/shared/core/engine/astrology.ts +169 -0
  57. package/shared/core/engine/bazi.ts +306 -0
  58. package/shared/core/engine/calendar.ts +127 -0
  59. package/shared/core/engine/daily.ts +133 -0
  60. package/shared/core/engine/liuren.ts +86 -0
  61. package/shared/core/engine/liuyao.ts +93 -0
  62. package/shared/core/engine/meihua.ts +87 -0
  63. package/shared/core/engine/qimen.ts +78 -0
  64. package/shared/core/engine/questionFit.ts +94 -0
  65. package/shared/core/engine/tarot.ts +69 -0
  66. package/shared/core/engine/trueSolarTime.ts +86 -0
  67. package/shared/core/engine/xiaoliuren.ts +19 -0
  68. package/shared/core/engine/ziwei.ts +217 -0
  69. package/shared/core/engine/ziweiInterpret.ts +161 -0
  70. package/shared/core/types.ts +206 -0
  71. package/src/App.tsx +69 -0
  72. package/src/arts/registry.ts +31 -0
  73. package/src/assets/react.svg +1 -0
  74. package/src/components/Backdrop.tsx +27 -0
  75. package/src/components/BambooArt.tsx +41 -0
  76. package/src/components/CalendarInput.tsx +131 -0
  77. package/src/components/DateInput.tsx +103 -0
  78. package/src/components/Disclaimer.tsx +12 -0
  79. package/src/components/Empty.tsx +8 -0
  80. package/src/components/ErrorBoundary.tsx +38 -0
  81. package/src/components/HomeSideAnchor.tsx +62 -0
  82. package/src/components/InkVein.tsx +10 -0
  83. package/src/components/LifeEventsInput.tsx +47 -0
  84. package/src/components/LocationPicker.tsx +117 -0
  85. package/src/components/Motes.tsx +65 -0
  86. package/src/components/Navigation.tsx +80 -0
  87. package/src/components/ProfileForm.tsx +40 -0
  88. package/src/components/ProfilePicker.tsx +40 -0
  89. package/src/components/QuestionFields.tsx +47 -0
  90. package/src/components/ReportView.tsx +211 -0
  91. package/src/components/ResultCard.tsx +40 -0
  92. package/src/components/SealButton.tsx +18 -0
  93. package/src/components/SiteFooter.tsx +17 -0
  94. package/src/components/SiteNav.tsx +103 -0
  95. package/src/components/SongDialog.tsx +64 -0
  96. package/src/components/SongSearchSelect.tsx +81 -0
  97. package/src/components/SongSelect.tsx +61 -0
  98. package/src/components/StarField.tsx +119 -0
  99. package/src/components/TarotCard.tsx +129 -0
  100. package/src/components/TimeShichenInput.tsx +29 -0
  101. package/src/components/arts/AstrologyArt.tsx +141 -0
  102. package/src/components/arts/BaziArt.tsx +269 -0
  103. package/src/components/arts/LiurenArt.tsx +87 -0
  104. package/src/components/arts/LiuyaoArt.tsx +111 -0
  105. package/src/components/arts/MeihuaArt.tsx +105 -0
  106. package/src/components/arts/QimenArt.tsx +86 -0
  107. package/src/components/arts/TarotArt.tsx +110 -0
  108. package/src/components/arts/XiaoliurenArt.tsx +93 -0
  109. package/src/components/arts/ZiweiArt.tsx +296 -0
  110. package/src/data/arts.ts +84 -0
  111. package/src/data/lifeContext.ts +423 -0
  112. package/src/data/sample-report.json +146 -0
  113. package/src/data/shichen.ts +21 -0
  114. package/src/data/spreads.ts +255 -0
  115. package/src/data/tarotCards.ts +2353 -0
  116. package/src/hooks/useAIInterpret.ts +76 -0
  117. package/src/hooks/useDivine.ts +39 -0
  118. package/src/hooks/useTheme.ts +29 -0
  119. package/src/index.css +190 -0
  120. package/src/lib/utils.ts +6 -0
  121. package/src/main.tsx +12 -0
  122. package/src/pages/AboutPage.tsx +25 -0
  123. package/src/pages/AcademyPage.tsx +128 -0
  124. package/src/pages/AstrologyPage.tsx +33 -0
  125. package/src/pages/AuthPage.tsx +263 -0
  126. package/src/pages/BaZiPage.tsx +33 -0
  127. package/src/pages/ClassicsPage.tsx +120 -0
  128. package/src/pages/DemoPage.tsx +161 -0
  129. package/src/pages/HistoryPage.tsx +133 -0
  130. package/src/pages/Home.tsx +179 -0
  131. package/src/pages/HomePage.tsx +174 -0
  132. package/src/pages/ModulePage.tsx +320 -0
  133. package/src/pages/SpreadEditor.tsx +230 -0
  134. package/src/pages/SpreadEditorPage.tsx +105 -0
  135. package/src/pages/SpreadLibrary.tsx +199 -0
  136. package/src/pages/SpreadLibraryPage.tsx +17 -0
  137. package/src/pages/TarotPage.tsx +738 -0
  138. package/src/pages/ZiWeiPage.tsx +33 -0
  139. package/src/services/api.ts +342 -0
  140. package/src/stores/useDivinationStore.ts +22 -0
  141. package/src/styles/song.css +1066 -0
  142. package/src/styles/tokens.css +60 -0
  143. package/src/types/index.ts +104 -0
  144. package/src/utils/astrologyCalc.ts +61 -0
  145. package/src/utils/comboEngine.ts +134 -0
  146. package/src/utils/dst.ts +24 -0
  147. package/src/utils/panTone.ts +206 -0
  148. package/src/utils/recordStore.ts +60 -0
  149. package/src/utils/semanticAnalyzer.ts +555 -0
  150. package/src/utils/spreadStorage.ts +32 -0
  151. package/src/utils/storage.ts +27 -0
  152. package/src/utils/tarotEngine.ts +849 -0
  153. package/src/utils/userStore.ts +234 -0
  154. package/src/vite-env.d.ts +1 -0
  155. package/tailwind.config.js +52 -0
  156. package/tsconfig.json +40 -0
  157. package/vite.config.ts +34 -0
@@ -0,0 +1,199 @@
1
+ import { useState, useMemo } from 'react';
2
+ import { Link } from 'react-router-dom';
3
+ import { Search, Plus, Sparkles, Filter, X, Star } from 'lucide-react';
4
+ import { defaultSpreads } from '@/data/spreads';
5
+ import { getCustomSpreads } from '@/utils/spreadStorage';
6
+ import type { Spread } from '@/types';
7
+ import { useEffect } from 'react';
8
+
9
+ const SCENE_FILTERS: { value: string; label: string }[] = [
10
+ { value: 'all', label: '全部' },
11
+ { value: 'love', label: '爱情' },
12
+ { value: 'career', label: '事业' },
13
+ { value: 'wealth', label: '财运' },
14
+ { value: 'health', label: '健康' },
15
+ { value: 'general', label: '通用' },
16
+ ];
17
+
18
+ const COMPLEXITY_FILTERS = [
19
+ { value: 'all', label: '全部复杂度' },
20
+ { value: 'simple', label: '简单 (1-3张)' },
21
+ { value: 'medium', label: '中等 (4-7张)' },
22
+ { value: 'complex', label: '复杂 (8张+)' },
23
+ ];
24
+
25
+ interface SpreadLibraryProps {
26
+ onSelect?: (spread: Spread) => void;
27
+ showCustomButton?: boolean;
28
+ }
29
+
30
+ export default function SpreadLibrary({ onSelect, showCustomButton = true }: SpreadLibraryProps) {
31
+ const [search, setSearch] = useState('');
32
+ const [sceneFilter, setSceneFilter] = useState('all');
33
+ const [complexityFilter, setComplexityFilter] = useState('all');
34
+ const [customSpreads, setCustomSpreads] = useState<Spread[]>([]);
35
+
36
+ useEffect(() => {
37
+ setCustomSpreads(getCustomSpreads());
38
+ }, []);
39
+
40
+ const allSpreads = useMemo(() => [...defaultSpreads, ...customSpreads], [customSpreads]);
41
+
42
+ const filtered = useMemo(() => {
43
+ return allSpreads.filter((spread) => {
44
+ if (search && !spread.name.toLowerCase().includes(search.toLowerCase()) && !spread.description.includes(search)) {
45
+ return false;
46
+ }
47
+ if (sceneFilter !== 'all' && spread.scene && !spread.scene.includes(sceneFilter)) {
48
+ return false;
49
+ }
50
+ const cardCount = spread.positions.length;
51
+ if (complexityFilter === 'simple' && cardCount > 3) return false;
52
+ if (complexityFilter === 'medium' && (cardCount < 4 || cardCount > 7)) return false;
53
+ if (complexityFilter === 'complex' && cardCount < 8) return false;
54
+ return true;
55
+ });
56
+ }, [allSpreads, search, sceneFilter, complexityFilter]);
57
+
58
+ const presetCount = filtered.filter(s => !s.isCustom).length;
59
+ const customCount = filtered.filter(s => s.isCustom).length;
60
+
61
+ return (
62
+ <div className="space-y-6">
63
+ {/* Header */}
64
+ <div className="flex flex-wrap items-center justify-between gap-4">
65
+ <div>
66
+ <h2 className="font-display text-xl text-ancient tracking-wider flex items-center gap-2">
67
+ <Sparkles className="w-5 h-5" />
68
+ 牌阵库
69
+ </h2>
70
+ <p className="text-stardust/50 text-xs mt-1">共 {allSpreads.length} 个牌阵 · {presetCount} 预设 · {customCount} 自定义</p>
71
+ </div>
72
+ {showCustomButton && (
73
+ <Link
74
+ to="/spread-editor"
75
+ className="inline-flex items-center gap-2 px-4 py-2 bg-ancient/20 border border-ancient/50 text-ancient hover:bg-ancient/30 transition-all rounded-sm text-sm"
76
+ >
77
+ <Plus className="w-4 h-4" />
78
+ 创建自定义牌阵
79
+ </Link>
80
+ )}
81
+ </div>
82
+
83
+ {/* Search & Filter */}
84
+ <div className="glass-panel p-4 space-y-3">
85
+ <div className="relative">
86
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-stardust/40" />
87
+ <input
88
+ type="text"
89
+ value={search}
90
+ onChange={(e) => setSearch(e.target.value)}
91
+ placeholder="搜索牌阵名称或描述..."
92
+ className="w-full bg-void/50 border border-ancient/20 rounded pl-10 pr-10 py-2 text-sm text-stardust placeholder-stardust/30 focus:border-ancient/60 focus:outline-none"
93
+ />
94
+ {search && (
95
+ <button
96
+ onClick={() => setSearch('')}
97
+ className="absolute right-3 top-1/2 -translate-y-1/2 text-stardust/40 hover:text-stardust"
98
+ >
99
+ <X className="w-4 h-4" />
100
+ </button>
101
+ )}
102
+ </div>
103
+
104
+ <div className="space-y-2">
105
+ <div className="flex items-center gap-2">
106
+ <Filter className="w-3 h-3 text-ancient/60" />
107
+ <span className="text-xs text-ancient/60">场景</span>
108
+ </div>
109
+ <div className="flex flex-wrap gap-2">
110
+ {SCENE_FILTERS.map((f) => (
111
+ <button
112
+ key={f.value}
113
+ onClick={() => setSceneFilter(f.value)}
114
+ className={`px-3 py-1 rounded-full text-xs transition-all ${
115
+ sceneFilter === f.value
116
+ ? 'bg-ancient/20 border border-ancient/50 text-ancient'
117
+ : 'border border-stardust/20 text-stardust/60 hover:border-ancient/30'
118
+ }`}
119
+ >
120
+ {f.label}
121
+ </button>
122
+ ))}
123
+ </div>
124
+ </div>
125
+
126
+ <div className="space-y-2">
127
+ <span className="text-xs text-ancient/60">复杂度</span>
128
+ <div className="flex flex-wrap gap-2">
129
+ {COMPLEXITY_FILTERS.map((f) => (
130
+ <button
131
+ key={f.value}
132
+ onClick={() => setComplexityFilter(f.value)}
133
+ className={`px-3 py-1 rounded-full text-xs transition-all ${
134
+ complexityFilter === f.value
135
+ ? 'bg-ancient/20 border border-ancient/50 text-ancient'
136
+ : 'border border-stardust/20 text-stardust/60 hover:border-ancient/30'
137
+ }`}
138
+ >
139
+ {f.label}
140
+ </button>
141
+ ))}
142
+ </div>
143
+ </div>
144
+ </div>
145
+
146
+ {/* Spread Grid */}
147
+ {filtered.length === 0 ? (
148
+ <div className="glass-panel p-12 text-center">
149
+ <p className="text-stardust/50 text-sm">没有匹配的牌阵</p>
150
+ </div>
151
+ ) : (
152
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
153
+ {filtered.map((spread) => (
154
+ <SpreadCard key={spread.id} spread={spread} onSelect={onSelect} />
155
+ ))}
156
+ </div>
157
+ )}
158
+ </div>
159
+ );
160
+ }
161
+
162
+ function SpreadCard({ spread, onSelect }: { spread: Spread; onSelect?: (s: Spread) => void }) {
163
+ const isCustom = spread.isCustom;
164
+ const cardCount = spread.positions.length;
165
+
166
+ return (
167
+ <button
168
+ onClick={() => onSelect?.(spread)}
169
+ className={`glass-panel p-4 text-left hover:border-ancient/40 transition-all ${
170
+ isCustom ? 'border-mystic/30' : ''
171
+ }`}
172
+ >
173
+ <div className="flex items-center justify-between mb-2">
174
+ <h3 className="font-display text-stardust text-sm flex items-center gap-2">
175
+ {spread.name}
176
+ {isCustom && <Star className="w-3 h-3 text-mystic/60" />}
177
+ </h3>
178
+ <span className="text-xs text-stardust/40">{cardCount}张</span>
179
+ </div>
180
+ <p className="text-stardust/50 text-xs leading-relaxed mb-3 line-clamp-3">
181
+ {spread.description}
182
+ </p>
183
+ <div className="flex flex-wrap gap-1">
184
+ {spread.scene?.slice(0, 2).map((s) => (
185
+ <span key={s} className="px-2 py-0.5 rounded text-[10px] bg-ancient/5 border border-ancient/20 text-ancient/60">
186
+ {SCENE_FILTERS.find(f => f.value === s)?.label || s}
187
+ </span>
188
+ ))}
189
+ <span className={`px-2 py-0.5 rounded text-[10px] border ${
190
+ cardCount <= 3 ? 'border-green-500/20 text-green-400/60' :
191
+ cardCount <= 7 ? 'border-yellow-500/20 text-yellow-400/60' :
192
+ 'border-red-500/20 text-red-400/60'
193
+ }`}>
194
+ {cardCount <= 3 ? '简单' : cardCount <= 7 ? '中等' : '复杂'}
195
+ </span>
196
+ </div>
197
+ </button>
198
+ );
199
+ }
@@ -0,0 +1,17 @@
1
+ import SpreadLibrary from './SpreadLibrary';
2
+
3
+ export default function SpreadLibraryPage() {
4
+ return (
5
+ <div className="relative min-h-screen pt-20 pb-16 px-4">
6
+ <div className="max-w-6xl mx-auto">
7
+ <div className="text-center mb-12">
8
+ <h1 className="font-display text-3xl md:text-4xl text-ancient tracking-wider mb-3">
9
+ 牌阵库
10
+ </h1>
11
+ <p className="text-stardust/50 text-sm">选择适合你问题的牌阵,或创建专属的</p>
12
+ </div>
13
+ <SpreadLibrary />
14
+ </div>
15
+ </div>
16
+ );
17
+ }