7.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
任何项目都务必遵守的规则(极其重要!!!)
Communication
- 永远使用简体中文进行思考和对话
Documentation
- 编写 .md 文档时,也要用中文
- 正式文档写到项目的 docs/ 目录下
- 用于讨论和评审的计划、方案等文档,写到项目的 discuss/ 目录下
Code Architecture
- 编写代码的硬性指标,包括以下原则: (1)对于 Python、JavaScript、TypeScript 等动态语言,尽可能确保每个代码文件不要超过 500 行 (3)每层文件夹中的文件,尽可能不超过 8 个。如有超过,需要规划为多层子文件夹
- 除了硬性指标以外,还需要时刻关注优雅的架构设计,避免出现以下可能侵蚀我们代码质量的「坏味道」: (1)僵化 (Rigidity): 系统难以变更,任何微小的改动都会引发一连串的连锁修改。 (2)冗余 (Redundancy): 同样的代码逻辑在多处重复出现,导致维护困难且容易产生不一致。 (3)循环依赖 (Circular Dependency): 两个或多个模块互相纠缠,形成无法解耦的“死结”,导致难以测试与复用。 (4)脆弱性 (Fragility): 对代码一处的修改,导致了系统中其他看似无关部分功能的意外损坏。 (5)晦涩性 (Obscurity): 代码意图不明,结构混乱,导致阅读者难以理解其功能和设计。 (6)数据泥团 (Data Clump): 多个数据项总是一起出现在不同方法的参数中,暗示着它们应该被组合成一个独立的对象。 (7)不必要的复杂性 (Needless Complexity): 用“杀牛刀”去解决“杀鸡”的问题,过度设计使系统变得臃肿且难以理解。
- 【非常重要!!】无论是你自己编写代码,还是阅读或审核他人代码时,都要严格遵守上述硬性指标,以及时刻关注优雅的架构设计。
- 【非常重要!!】无论何时,一旦你识别出那些可能侵蚀我们代码质量的「坏味道」,都应当立即询问用户是否需要优化,并给出合理的优化建议。
Commands
- Dev server:
bun run dev(usesbunx --bun vite) - Build:
bun run build(type-checks then bundles via Vite) - Type check only:
bun run type-check - Preview build:
bun run preview
No test runner is configured. Use Playwright for UI automation when needed (see AGENTS.md).
Architecture Overview
This is a browser-only Vue 3 SPA — no backend, no SSR. All data is persisted client-side via IndexedDB (through localforage). The domain is 交通建设项目工程造价咨询 (transport infrastructure cost-consulting fee calculation for road, railway, and waterway projects).
App Entry & Routing
There is no Vue Router. Navigation is tab-based, managed entirely by useTabStore (src/pinia/tab.ts). src/App.vue shows either HomeEntryView (first-launch onboarding) or the main Tab layout depending on tabStore.hasCompletedSetup.
The Tab layout (src/layout/tab.vue) renders the active tab's component by name using defineAsyncComponent with a map of component names → import paths.
Workspace Modes
Defined in src/lib/workspace.ts. Three modes: home, project, quick. The current mode is persisted to localStorage under key jgjs-workspace-mode-v1. Two fixed/protected tab IDs exist: ProjectCalcView and QuickCalcView (and the quick-contract tab), which cannot be closed.
State & Persistence
- Pinia is used for all state management with
pinia-plugin-persistedstate. - The persistence plugin is customized at
src/pinia/Plugin/indexdb— it stores pinia state in IndexedDB (not localStorage), using localforage withmode: 'multiple'(each store in its own IndexedDB store namedpinia). useTabStore(src/pinia/tab.ts): tab list, active tab, setup flag. Persisted.useZxFwPricingStore(src/pinia/zxFwPricing.ts): the core domain store. Manages contract-level 咨询服务 (consulting service) pricing state, per-service pricing method states, and contract extra-fee states. Uses a generic key/value layer (getKeyState/setKeyState/loadKeyState) backed byuseKvStore.useKvStore(src/pinia/kv.ts): raw key-value access to IndexedDB via localforage.
Data Layer (src/sql.ts)
Despite the name, there is no SQL database. src/sql.ts is a large static data file containing:
industryTypeList: road / railway / waterwaymajorList: engineering specialties (E1–E4 codes) with coefficient rangesserviceList: consulting service types (D1–D5 codes) with pricing method flagsadditionalWorkList: extra work item definitionsexportFile: Excel export logic using ExcelJS
All fee calculation formulas and coefficient tables live here.
Lib Utilities (src/lib/)
decimal.ts/number.ts/numberFormat.ts: safe arithmetic usingdecimal.js, thousand-separator formattingzwArchive.ts: AES-GCM encryption/decryption for.zwsave files (import/export format). The key is derived from a fixed seed via SHA-256. File magic bytes:JGJSZW.workspace.ts: workspace mode constants and storage helpersdiyAgGridOptions.ts: shared AG Grid configuration defaultspricingScaleFee.ts/pricingMethodTotals.ts: fee calculation helpersprojectWorkspace.ts/xmFactorDefaults.ts: project-level workspace helperszxFwPricingSync.ts: syncs pricing store state to/from IndexedDB on demand
Views (src/components/views/)
Key views:
HomeEntryView.vue: onboarding screen shown on first launch; dispatcheshome-import-selectedDOM event on completionProjectWorkspaceView.vue/xmCard.vue: project card workspace (项目卡片)QuickCalcView.vue: quick calculation modeZxFwView.vue: 咨询服务 (consulting services) grid — the primary fee input viewHt.vue/htCard.vue: contract (合同) viewsHtFeeMethodTypeLineView.vue: per-service fee method line (rate/hourly/quantity-unit-price)WorkContentGrid.vue: AG Grid-based work content table
AG Grid
AG Grid Enterprise is used throughout. Modules are registered once globally in src/main.ts. A license key is set there. Shared grid option defaults live in src/lib/diyAgGridOptions.ts.
UI Components
Reka UI (headless component library) + Tailwind CSS v4 + lucide-vue-next icons + @iconify/vue. Shared UI primitives are in src/components/ui/. Tailwind is integrated as a Vite plugin (@tailwindcss/vite).
Build
Vite 8 with rolldown. Output goes to dist/ with base: './' (relative paths — important for local file:// deployment). Code-splitting separates ag-grid, vue/pinia, and reka-ui into distinct vendor chunks.
Code Conventions
- All code comments are in Chinese.
- Composition API (
<script setup>) everywhere. - No Vue Router — use
useTabStore.openTab()to navigate. - Numeric calculations always go through
src/lib/decimal.tshelpers to avoid floating-point errors. - Storage keys follow patterns like
zxFW-{contractId},tzGMF-{contractId}-{serviceId},htExtraFee-{contractId}-{feeType}.