You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
6.5 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
This is the **RuoYi-Vue-Plus** frontend — a multi-tenant enterprise management system (Vue 3 + TypeScript + Element Plus + Vite). It is the UI for a Java Spring Boot backend and follows a standard admin panel architecture with RBAC, dynamic routing, and multi-tenant support.
## Commands
```bash
# Development (uses pnpm)
pnpm dev # Start dev server (port from VITE_APP_PORT, default 80)
pnpm build:prod # Production build
pnpm build:dev # Development build
pnpm preview # Preview production build locally
# Code quality
pnpm lint:eslint # Run ESLint
pnpm lint:eslint:fix # Auto-fix ESLint issues
pnpm prettier # Format all files with Prettier
# No test runner configured yet (vitest is installed but no vitest.config.ts exists)
```
## Architecture
### Entry & Bootstrap (`src/main.ts`)
- Creates Vue app → mounts Pinia → Vue Router → vue-i18n → plugins → custom directives → VXE Table
- Loads UnoCSS, Element Plus styles, Highlight.js, SVG icons
- Imports `src/permission.ts` for route guards
### Routing (`src/router/index.ts`)
Two-tier route system:
1. **`constantRoutes`** — always loaded (login, register, 401, 404, index, redirect, profile)
2. **`dynamicRoutes`** — initially empty array; populated by frontend-defined routes checked against user permissions
Actual menus come from the **backend API** (`/getRouters`). `permission.ts` store fetches these, converts backend route configs to Vue Router routes via `filterAsyncRouter()`, and dynamically adds them. Component strings from backend (e.g., `"system/user/index"`) are resolved against `import.meta.glob('./../../views/**/*.vue')`.
### Permission Guard (`src/permission.ts`)
Router `beforeEach`:
- No token → redirect to `/login` (unless whitelisted)
- Has token + no roles loaded → fetch user info (`useUserStore().getInfo()`) then generate routes (`usePermissionStore().generateRoutes()`) → dynamically add routes → redirect to target
- Has token + roles loaded → allow navigation
### State Management (Pinia)
| Store | File | Purpose |
|-------|------|---------|
| `user` | `src/store/modules/user.ts` | Auth token, user info, roles, permissions |
| `permission` | `src/store/modules/permission.ts` | Dynamic routes generation, sidebar/topbar route trees |
| `app` | `src/store/modules/app.ts` | Sidebar state, device type, language, size |
| `settings` | `src/store/modules/settings.ts` | Layout config (theme, navType, tagsView, etc.) persisted to localStorage |
| `dict` | `src/store/modules/dict.ts` | Dictionary data cache |
| `tagsView` | `src/store/modules/tagsView.ts` | Multi-tab page management |
| `notice` | `src/store/modules/notice.ts` | Notification/announcement state |
### HTTP Layer (`src/utils/request.ts`)
Axios instance with:
- **Request interceptor**: injects Bearer token + `Content-Language` header, GET params serialization, duplicate submit detection (500ms window via sessionStorage), optional AES body encryption (ECB mode, key encrypted with RSA public key)
- **Response interceptor**: AES decryption, 401 → re-login prompt, 500 → error message, 601 → warning
- **`download()`** helper for file downloads with loading state
Encryption is toggleable via `VITE_APP_ENCRYPT` env var — must match backend config.
### Permission System (`src/plugins/auth.ts`)
- `hasPermi(permission)` — exact permission match (admin `*:*:*` wildcard supported)
- `hasPermiOr(permissions)` — any match
- `hasPermiAnd(permissions)` — all match
- `hasRole(role)` / `hasRoleOr(roles)` / `hasRoleAnd(roles)` — role-based equivalents
- Used in route filtering and button-level UI control via custom directives
### Layout (`src/layout/index.vue`)
Classic admin layout: Sidebar + Navbar + TagsView + AppMain + Settings drawer. Supports:
- `NavTypeEnum.LEFT` — left sidebar
- `NavTypeEnum.TOP` — top navigation
- `NavTypeEnum.MIX` — mixed mode
- Responsive: mobile detection at 992px breakpoint
### API Layer (`src/api/`)
Organized by backend module:
- `src/api/login.ts` — auth (login, logout, register, tenant list)
- `src/api/menu.ts` — menu/routing
- `src/api/system/` — user, role, menu, dept, post, dict, config, notice, tenant, oss, client, social
- `src/api/monitor/` — online users, operlog, loginInfo, cache
- `src/api/tool/gen/` — code generation
- `src/api/workflow/` — workflow (category, definition, instance, task, leave)
- `src/api/demo/` — demo/demo, demo/tree
### Directory Quick Reference
| Directory | Purpose |
|-----------|---------|
| `src/views/` | Page components, mirrors `src/api/` module structure |
| `src/components/` | Shared components (Breadcrumb, DictTag, FileUpload, ImageUpload, Editor, Pagination, etc.) |
| `src/plugins/` | Global Vue plugins installed via `app.use()` — auth, cache, modal, tab, download, svgicon |
| `src/directive/` | Custom directives (permission checks, common utilities) |
| `src/utils/` | Utilities — request, auth (token storage), crypto (AES+RSA), validate, websocket, sse, ruoyi (helper fns), dict, theme, scroll-to |
| `src/lang/` | vue-i18n language packs (zh_CN, en_US) |
| `src/enums/` | TypeScript enums (HttpStatus, NavTypeEnum, LanguageEnum, SideThemeEnum, MenuTypeEnum) |
| `src/types/` | Global type declarations (env.d.ts, router.d.ts, global.d.ts, etc.) |
| `vite/plugins/` | Vite plugin configs — auto-import, auto-components, UnoCSS, SVG icons, compression, setup-extend |
### Key Conventions
- Auto-imported: `vue`, `vue-router`, `@vueuse/core`, `pinia` (via `unplugin-auto-import`)
- Auto-registered: Element Plus components + `icon-park` icons (via `unplugin-vue-components`)
- Path alias: `@/``src/`
- Uses UnoCSS with `presetAttributify` (attribute-based utilities) and `presetIcons`
- SCSS variables in `src/assets/styles/variables.module.scss`
- Backend API prefix: `/dev-api` (dev), configurable via `VITE_APP_BASE_API`
- Token stored in localStorage under key `Admin-Token`, managed via `@vueuse/core`'s `useStorage`
- SSR/SSE: `src/utils/sse.ts` for Server-Sent Events, `src/utils/websocket.ts` for WebSocket
### Important: Backend-Driven Nature
Many UI aspects are controlled by backend API responses:
- **Menus/routes** come from backend (not frontend route definitions)
- **Dictionaries** (`dict` store) provide dynamic dropdown options throughout the app
- **Tenant info** is fetched on auth and drives data isolation
- Always check the backend API contract when modifying UI modules