# 架构文档(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 清单)