163 lines
8.3 KiB
Markdown
163 lines
8.3 KiB
Markdown
# 架构文档(Architecture)
|
||
|
||
> 最后更新:2026-08-03
|
||
|
||
## 1. 项目概述
|
||
|
||
万年历(Lunar Calendar App):中国农历/黄历应用,提供农历转换、黄历宜忌、八字排盘、每日运势、梅花易数、称骨算命、节气等命理功能,移动端优先,支持 PWA 离线安装。
|
||
|
||
## 2. 技术栈
|
||
|
||
| 层 | 技术 |
|
||
|---|---|
|
||
| Monorepo | pnpm workspaces(`packages/*`) |
|
||
| 核心引擎 | TypeScript + [tyme4ts](https://github.com/6tail/tyme4ts) ^1.5.1(历法/干支计算) |
|
||
| 构建 | tsup(core)、Vite 6 + tsc(web) |
|
||
| UI | React 19、React Router v7、Zustand 5、TailwindCSS v4(CSS-first)、Framer Motion、lucide-react |
|
||
| PWA | vite-plugin-pwa 0.21(Workbox,已启用) |
|
||
|
||
## 3. 目录结构
|
||
|
||
```
|
||
lunar/
|
||
├── docs/ # 项目文档(本目录,含 RETROSPECT 会话回顾)
|
||
├── AGENTS.md # 开发代理指引
|
||
├── package.json # workspace 聚合脚本
|
||
├── pnpm-workspace.yaml # 工作区定义
|
||
├── tsconfig.base.json # 共享 TS 配置
|
||
└── packages/
|
||
├── core/ # @lunar/core —— 纯 TS 计算引擎,零 UI 依赖
|
||
│ ├── tsup.config.ts
|
||
│ └── src/
|
||
│ ├── index.ts # 公共 API 出口(barrel)
|
||
│ ├── types/ # calendar.ts / bazi.ts / almanac.ts / fortune.ts
|
||
│ ├── transformers/ # day.ts / bazi.ts / almanac.ts / yearMonths.ts(tyme4ts → 纯对象)
|
||
│ └── calculators/ # dailyMatch / relationship / elementStrength / plumBlossom / boneWeight / buddhistDates / shensha / fortuneLuck
|
||
└── web/ # @lunar/web —— React 应用
|
||
├── vite.config.ts # Vite + Tailwind v4 + PWA
|
||
├── index.html
|
||
└── src/
|
||
├── App.tsx # 路由 + 懒加载 + 页面过渡 + ErrorBoundary
|
||
├── main.tsx
|
||
├── styles/globals.css # 设计令牌(亮/暗主题)
|
||
├── lib/utils.ts # cn、日期格式化等工具
|
||
├── stores/ # calendar / user / settings / ui / bookmarks(Zustand)
|
||
├── hooks/ # useCalendar / useDayDetail / useBazi / useDailyFortune
|
||
├── components/
|
||
│ ├── calendar/ # CalendarGrid / CalendarCell / MonthYearPicker / WeekDayBar
|
||
│ ├── layout/ # AppShell / Header / BottomNav
|
||
│ ├── ui/ # Badge / Button / Card / AnimatedPanel / ErrorBoundary / Skeleton
|
||
│ ├── day-detail/ bazi/ daily-fortune/(页面内联实现,目录内暂无独立组件)
|
||
└── pages/ # 8 个页面(见路由表)
|
||
```
|
||
|
||
## 4. 分层设计
|
||
|
||
```
|
||
┌───────────────────────────────┐
|
||
│ @lunar/web (React 页面层) │
|
||
│ pages → hooks → stores │
|
||
├───────────────────────────────┤
|
||
│ @lunar/core (纯计算引擎) │
|
||
│ index.ts │
|
||
│ ├─ transformers tyme4ts → │
|
||
│ │ 纯 JS 对象 │
|
||
│ ├─ calculators 业务算法 │
|
||
│ └─ types 类型定义 │
|
||
├───────────────────────────────┤
|
||
│ tyme4ts (历法计算源) │
|
||
└───────────────────────────────┘
|
||
```
|
||
|
||
### 4.1 核心原则
|
||
|
||
1. **tyme4ts 对象永不进入 React**:所有历法对象在 `@lunar/core` 内转换为普通 JS 对象(`DayInfo`、`AlmanacInfo`、`BaziFullResult` 等),React 层只消费纯数据。
|
||
2. **@lunar/core 零 UI 依赖**:仅依赖 tyme4ts,可在任意 JS 运行时运行(web / Node / RN / 小程序)。
|
||
3. **移动端优先**:手机优先布局,桌面端自适应。
|
||
4. **暗色模式**:CSS 自定义属性 + `.dark` class,跟随系统偏好 + 手动切换。
|
||
|
||
### 4.2 数据流示例
|
||
|
||
```
|
||
SolarDay (tyme4ts)
|
||
→ solarDayToDayInfo() # DayInfo
|
||
→ solarDayToAlmanacInfo() # AlmanacInfo(含 12 时辰)
|
||
→ birthInfoToBazi() # BaziFullResult(四柱/十神/大运…)
|
||
→ calculateDailyFortune() # DailyFortuneResult(每日运势)
|
||
```
|
||
|
||
## 5. @lunar/core API 一览
|
||
|
||
### 类型
|
||
`DayInfo`、`AlmanacInfo`、`HourAlmanac`、`PillarInfo`、`HideStemInfo`、`EightCharInfo`、`DecadeFortuneInfo`、`FortuneInfo`、`ChildLimitInfo`、`BaziFullResult`、`PillarRelationship`、`DailyFortuneResult`、`BirthParams`、`BranchRelationship`、`ElementProfile`、`TrigramInfo`、`HexagramInfo`、`PlumBlossomResult`、`BoneWeightResult`
|
||
|
||
### 函数
|
||
|
||
| 函数 | 说明 |
|
||
|---|---|
|
||
| `solarDayToDayInfo(solarDay)` | SolarDay → DayInfo(含季节/节气进度/儒略日/佛历/伊斯兰历/佛教节日) |
|
||
| `getDayInfo(y, m, d)` / `getTodayInfo()` | 获取某日/今日信息 |
|
||
| `getMonthCalendar(y, m, weekStart?)` | 月历二维数组(周 × 天),可指定周起始 |
|
||
| `solarDayToAlmanacInfo(solarDay)` | SolarDay → AlmanacInfo |
|
||
| `getAlmanacInfo(y, m, d)` | 获取黄历信息(宜忌/值神/冲煞/时辰) |
|
||
| `birthInfoToBazi(params)` | 出生信息 → 完整八字排盘(`ziSect` 流派参数:晚子时换日) |
|
||
| `getYearMonths(year)` | 按节气月返回某年 12 个流月 |
|
||
| `getBranchRelationship(a, b)` | 地支六合/三合/六冲/六害/相刑 |
|
||
| `getTenStarRelationship(s, o)` / `checkStemCombine` / `checkStemOpposite` | 干支关系判断 |
|
||
| `calculateDailyFortune(userBazi, date)` | 用户八字 × 日期 → 每日运势评分 |
|
||
| `analyzeElementBalance(bazi)` | 五行力量分析 |
|
||
| `calculatePlumBlossom(y, m, d, h?)` | 梅花易数起卦 |
|
||
| `calculateBoneWeight(...)` | 袁天罡称骨算命 |
|
||
| `getBuddhistFestival(lunarMonth, lunarDay)` | 农历佛教节日 |
|
||
| `analyzeShensha(bazi)` | 22 个常见神煞 |
|
||
| `analyzeFortuneGanzhi(ganzhi, dayStem, dayBranch)` | 大运/流年/流月/流日 vs 日主生克冲合 |
|
||
|
||
## 6. 前端状态管理(Zustand)
|
||
|
||
| Store | 持久化 Key | 职责 | 备注 |
|
||
|---|---|---|---|
|
||
| `calendar` | — | 视图日期 / 选中日期 / 周起始 | `weekStart`、`clearSelection` 当前未被使用 |
|
||
| `user` | `lunar-user-profiles` | 出生档案(最多 3 个)、active 档案、八字结果 | |
|
||
| `settings` | `lunar-settings` | 主题、周起始、显示开关、八字来源 | `showLunar` 等 4 个字段未被消费 |
|
||
| `ui` | — | 侧栏 / 移动端 / 底部面板 | 多数 action 未被消费 |
|
||
| `bookmarks` | `lunar-bookmarks` | 日期收藏(标记在日历格上) | `getByDate`/`getByLunarDate` 未使用 |
|
||
|
||
## 7. 路由(React Router v7,全部懒加载)
|
||
|
||
| 路径 | 页面 | 底部导航 |
|
||
|---|---|---|
|
||
| `/` | HomePage(今日概览) | ✔ |
|
||
| `/calendar` | CalendarPage(月/周视图) | ✔ |
|
||
| `/calendar/:date` | DayDetailPage(日详情) | — |
|
||
| `/bazi` | BaziPage(八字排盘) | ✔ |
|
||
| `/daily-fortune` | DailyFortunePage(每日运势) | ✔ |
|
||
| `/settings` | SettingsPage(设置) | ✔ |
|
||
| `/divination` | DivinationPage(梅花易数 + 称骨) | 首页快捷入口 |
|
||
| `/solar-terms` | SolarTermsPage(节气) | 首页快捷入口 |
|
||
| `*` | 重定向 `/` | — |
|
||
|
||
## 8. PWA(已启用)
|
||
|
||
- `vite-plugin-pwa`:autoUpdate 模式 + Workbox 预缓存 + google-fonts 运行时缓存
|
||
- 构建产物:`manifest.webmanifest`、`sw.js`、`registerSW.js`
|
||
- manifest 已与 index.html 对齐(`lang: zh-CN`、`theme_color: #FFFBF5`)
|
||
|
||
## 9. 构建与命令
|
||
|
||
| 命令 | 说明 |
|
||
|---|---|
|
||
| `pnpm dev` | 启动 web dev(端口 4258) |
|
||
| `pnpm build` | 构建 core → web |
|
||
| `pnpm --filter @lunar/core build` | 仅构建 core(tsup,ESM+CJS) |
|
||
| `pnpm --filter @lunar/web build` | 仅构建 web(tsc -b && vite build) |
|
||
| `pnpm preview` | 预览构建产物 |
|
||
| `pnpm test` | core 单元测试(vitest,50 例) |
|
||
| `pnpm lint` | ESLint(flat config + typescript-eslint) |
|
||
| `pnpm clean` | 清理 dist |
|
||
|
||
## 10. 已知架构问题(详见 BUGS.md)
|
||
|
||
- 梅花易数互卦为简化实现(上下卦互换,非真·互卦 2-4/3-5 爻法)
|
||
- 每日运势当日八字固定取午时;称骨极端总重仍取"最近值"
|
||
- 若干死代码(未使用的 hooks / 组件 / store action,见 BUGS.md 清单)
|