fix(hrm): 修复流程数据空值时的渲染异常
针对印章详情和流程详情页面,在缺少流程实例ID时提前返回,避免调用接口产生无效请求和脏数据
This commit is contained in:
95
CLAUDE.md
Normal file
95
CLAUDE.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
1. `ruoyi-ui/src/store/modules/permission.js` → `GenerateRoutes` action
|
||||
2. Calls `getRouters()` → `@/api/menu.js` → `GET /getRouters`
|
||||
3. Backend returns JSON with `component` paths (e.g. `"hrm/employee/index"`)
|
||||
4. `filterAsyncRouter()` resolves strings to actual Vue components via dynamic `import()`
|
||||
5. 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_instance` etc. — handles leave/travel/seal/reimburse/appropriation workflows. Pages: `hrm/requests/`
|
||||
- **OA approval center**: `oa_approval_instance` table — 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`
|
||||
- `@SaCheckPermission` for API-level permission checks
|
||||
- Frontend permission checks: `v-hasPermi` directive and `auth.hasPermiOr()` in `@/plugins/auth`
|
||||
- Menu visibility is controlled by `sys_role_menu` table — role-to-menu many-to-many
|
||||
|
||||
## API Response Conventions
|
||||
|
||||
The backend uses two response wrappers:
|
||||
- `TableDataInfo<T>`: `{ total, rows, code, msg }` — paginated lists → frontend accesses `res.rows`
|
||||
- `R<T>`: `{ data, code, msg }` — single entities → frontend accesses `res.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).
|
||||
@@ -295,6 +295,10 @@ export default {
|
||||
}
|
||||
},
|
||||
async loadComment () {
|
||||
if (!this.flowInstance || !this.flowInstance.instId) {
|
||||
this.commentList = []
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await listFlowComment({ instId: this.flowInstance.instId })
|
||||
this.commentList = res.rows
|
||||
@@ -352,6 +356,10 @@ export default {
|
||||
}
|
||||
},
|
||||
async loadAssignTask () {
|
||||
if (!this.detail.instId) {
|
||||
this.assignTasks = []
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await listAssignTask(this.detail.instId)
|
||||
this.assignTasks = res?.data || []
|
||||
|
||||
@@ -427,6 +427,10 @@ export default {
|
||||
})
|
||||
},
|
||||
async loadAssignTask () {
|
||||
if (!this.seal || !this.seal.instId) {
|
||||
this.assignTasks = []
|
||||
return
|
||||
}
|
||||
try {
|
||||
// const res = await getTodoTaskByBiz('seal', this.currentBizId)
|
||||
console.log(this.seal)
|
||||
|
||||
Reference in New Issue
Block a user