4.5 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
福安德综合办公系统 (FAD OA) — 基于 RuoYi-Flowable-Plus 二次开发,面向工程项目的投标管理、进度控制、成本核算及日常 OA 办公。
Tech Stack: Spring Boot 2.7 + MyBatis-Plus 3.5 + Flowable 6.8 + Vue 2 + Element UI + MySQL 8.0 + Redis
Build & Run
# Backend build (dev profile, skip tests)
mvn clean package -D maven.test.skip=true -P dev
# Backend build (prod)
mvn clean package -D maven.test.skip=true -P prod
# Frontend dev server (port 80)
cd ruoyi-ui && npm run dev
# Frontend lint
cd ruoyi-ui && npm run lint
# Frontend prod build
cd ruoyi-ui && npm run build:prod
Active Maven profile defaults to dev (pom.xml line 72). Backend entry point: ruoyi-admin/.
Database
Init script: script/sql/mysql/ry-vue-flowable-xg.sql. Module-specific migrations live in sql/ (e.g. oa_approval.sql, warehouse_*.sql, hrm_*.sql).
Dev DB: fad_oa_dev @ 49.232.154.205:13306
Prod DB: fad_oa @ 49.232.154.205:13306
Redis: 49.232.154.205:6379 (password: WANGyu11!)
Menu SQL pattern: When adding menus to sys_menu, use fixed snowflake IDs (not RAND()). Reference sql/warehouse_phase0_menu.sql for the correct pattern. Menu changes require COMMIT + restart backend to flush Redis cache — clearing Redis is not enough on its own.
Module Architecture
| Module | Purpose |
|---|---|
ruoyi-admin/ |
Spring Boot entry point, YAML configs |
ruoyi-framework/ |
Security (Sa-Token), interceptors, global config |
ruoyi-system/ |
Users, roles, menus, depts, dicts, posts |
ruoyi-flowable/ |
Flowable workflow engine integration |
ruoyi-oa/ |
Core OA: projects, contracts, bidding, finance, warehouse, approval |
ruoyi-ui/ |
Vue 2 frontend (Element UI) |
fad-hrm/ |
HRM: employees, attendance, leave, travel, seal, payroll, flow tasks |
fad-app/ |
Mobile app API endpoints |
fad-export/ |
Foreign trade public web pages |
fad-rolling-mill/ |
Rolling mill business module |
klp-wms/ |
Warehouse management module |
Dynamic Menu System (Critical)
Menus are not hardcoded in Vue Router. They are stored in sys_menu DB table and delivered by GET /getRouters. The frontend flow:
ruoyi-ui/src/store/modules/permission.js→GenerateRoutesaction- Calls
getRouters()→@/api/menu.js→GET /getRouters - Backend returns JSON with
componentpaths (e.g."hrm/employee/index") filterAsyncRouter()resolves strings to actual Vue components via dynamicimport()- Routes are added at runtime via
router.addRoutes()
Implication: Adding a new page requires both a sys_menu INSERT (with correct component path) AND the actual .vue file at ruoyi-ui/src/views/<component>. No changes to router/index.js are needed for C-type page menus — only hidden/detail routes go there.
F-type menus (buttons) use perms field for permission checks (e.g. system:user:add). M-type menus are directory containers with no component.
HRM Module Structure
The HRM module (fad-hrm/ backend, ruoyi-ui/src/views/hrm/ frontend) is a self-contained HR system built on a custom flow engine (NOT Flowable — uses its own hrm_flow_* tables).
Two separate approval systems exist:
- HRM flow engine:
hrm_flow_task,hrm_flow_instanceetc. — handles leave/travel/seal/reimburse/appropriation workflows. Pages:hrm/requests/ - OA approval center:
oa_approval_instancetable — lightweight generic approval for purchase/contract. Pages:oa/approval/
Both have items named "我的审批" in the menu. They serve different data sources and must NOT be conflated.
Key Auth Patterns
- Uses Sa-Token (not Spring Security), configured in
application.yml @SaCheckPermissionfor API-level permission checks- Frontend permission checks:
v-hasPermidirective andauth.hasPermiOr()in@/plugins/auth - Menu visibility is controlled by
sys_role_menutable — role-to-menu many-to-many
API Response Conventions
The backend uses two response wrappers:
TableDataInfo<T>:{ total, rows, code, msg }— paginated lists → frontend accessesres.rowsR<T>:{ data, code, msg }— single entities → frontend accessesres.data
Frontend API modules are in ruoyi-ui/src/api/. The axios interceptor in @/utils/request unwraps the HTTP response, so .then(res => ...) receives the JSON body directly (not the full axios response).