- Remove extra spaces in CSS property declarations - Consolidate multi-line CSS rules into single lines - Maintain consistent formatting across component styles - Improve readability by removing unnecessary line breaks - Ensure uniform styling structure in scoped CSS blocks
8.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is a hybrid ERP system consisting of:
- Backend: RuoYi-Vue (Spring Boot 2.5.15 + MyBatis) - Java 17 management system
- Desktop Client: Electron + Vue 3 + TypeScript application
- Embedded Spring Boot Service: Java service that runs within the Electron app
The architecture uses a dual-service pattern where the Electron app communicates with both:
- Local embedded Spring Boot service (port 8081)
- Remote RuoYi admin backend (port 8085)
Repository Structure
C:\wox\erp\
├── electron-vue-template/ # Electron + Vue 3 desktop client
│ ├── src/
│ │ ├── main/ # Electron main process (TypeScript)
│ │ └── renderer/ # Vue 3 renderer process
│ │ ├── api/ # API client modules
│ │ ├── components/ # Vue components
│ │ └── utils/ # Utility functions
│ ├── scripts/ # Build scripts
│ └── package.json
├── ruoyi-admin/ # Main Spring Boot application entry
├── ruoyi-system/ # System management module
├── ruoyi-framework/ # Framework core (Security, Redis, etc.)
├── ruoyi-common/ # Common utilities
├── ruoyi-generator/ # Code generator
├── ruoyi-quartz/ # Scheduled tasks
├── erp_client_sb/ # Embedded Spring Boot service for client
├── sql/ # Database migration scripts
└── pom.xml # Root Maven configuration
Development Commands
Backend (Spring Boot)
# Build the project (from root)
mvn clean package
# Run the RuoYi admin backend
cd ruoyi-admin
mvn spring-boot:run
# Runs on http://localhost:8085
# Build without tests
mvn clean package -DskipTests
Frontend (Electron + Vue)
cd electron-vue-template
# Install dependencies
npm install
# Development mode with hot reload
npm run dev
# Build for distribution
npm run build # Cross-platform
npm run build:win # Windows
npm run build:mac # macOS
npm run build:linux # Linux
Key Architecture Patterns
1. Dual-Backend Routing (http.ts)
The Electron client uses intelligent routing to determine which backend to call:
- Paths starting with
/monitor/,/system/,/tool/banma,/tool/genmai→ RuoYi backend (port 8085) - All other paths → Embedded Spring Boot service (port 8081)
Location: electron-vue-template/src/renderer/api/http.ts
2. Account-Based Resource Isolation
User-specific resources (splash images, brand logos) are stored per account:
- Backend stores URLs in the
client_accounttable (columns:splash_image,brand_logo) - Files are uploaded to Qiniu Cloud (七牛云) configured in
application.yml - Each user sees only their own uploaded assets
Key files:
- Java entity:
ruoyi-system/src/main/java/com/ruoyi/system/domain/ClientAccount.java - MyBatis mapper:
ruoyi-system/src/main/resources/mapper/system/ClientAccountMapper.xml - API endpoints:
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ClientAccountController.java
3. Event-Driven UI Updates
The Vue application uses custom browser events to propagate state changes between components:
window.dispatchEvent(new CustomEvent('brandLogoChanged'))- notifies when brand logo changeswindow.addEventListener('brandLogoChanged', handler)- listens for changes in App.vue
This pattern ensures immediate UI updates after upload/delete operations without requiring page refreshes.
4. VIP Feature Gating
Certain features (e.g., custom splash images, brand logos) are gated by VIP status:
- Check
accountTypefield inClientAccount(values:trial,paid) - Trial accounts show
TrialExpiredDialogwhen attempting VIP features - VIP validation happens in
SettingsDialog.vuebefore allowing uploads
Important Configuration
Backend Configuration
File: ruoyi-admin/src/main/resources/application.yml
Key settings:
- Server port:
8085 - Upload path:
ruoyi.profile: D:/ruoyi/uploadPath - Redis:
8.138.23.49:6379(password:123123) - Qiniu Cloud credentials for file storage
- Token expiration: 30 minutes
Database
The system uses MySQL with MyBatis. When adding new fields:
- Write SQL migration script in
sql/directory - Update Java entity in
ruoyi-system/src/main/java/com/ruoyi/system/domain/ - Update MyBatis mapper XML in
ruoyi-system/src/main/resources/mapper/system/ - Include field in
<resultMap>,<sql id="select...">,<insert>, and<update>sections
Electron Main Process
File: electron-vue-template/src/main/main.ts
- Manages embedded Spring Boot process lifecycle
- Handles splash screen display
- Configures tray icon
- Manages auto-updates
- Uses app data directory:
app.getPath('userData')
Development Workflow (from .cursor/rules/guize.mdc)
When making code changes, follow this three-phase approach:
Phase 1: Analyze Problem (【分析问题】)
- Understand user intent and ask clarifying questions
- Search all related code
- Identify root cause
- Look for code smells: duplication, poor naming, outdated patterns, inconsistent types
- Ask questions if multiple solutions exist
Phase 2: Plan Solution (【制定方案】)
- List files to be created/modified/deleted
- Describe changes briefly for each file
- Eliminate code duplication through reuse/abstraction
- Ensure DRY principles and good architecture
- Ask questions if key decisions are unclear
Phase 3: Execute (【执行方案】)
- Implement according to the approved plan
- Run type checking after modifications
- DO NOT commit code unless explicitly requested
- DO NOT start dev servers automatically
Common Patterns
Adding a New API Endpoint
-
Backend (Spring Boot):
// In appropriate Controller (e.g., ClientAccountController.java) @PostMapping("/your-endpoint") public AjaxResult yourMethod(@RequestBody YourDTO dto) { // Implementation return AjaxResult.success(result); } -
Frontend (Vue/TypeScript):
// In electron-vue-template/src/renderer/api/your-module.ts export const yourApi = { async yourMethod(data: YourType) { return http.post<ResponseType>('/your-endpoint', data) } } -
Component usage:
<script setup lang="ts"> import { yourApi } from '@/api/your-module' const handleAction = async () => { try { const res = await yourApi.yourMethod(data) // Handle success, update local state immediately localState.value = res.data // Dispatch event if other components need to know window.dispatchEvent(new CustomEvent('yourEventName')) } catch (error) { ElMessage.error(error.message) } } </script>
File Upload Pattern
// Frontend
const handleUpload = async (file: File) => {
const formData = new FormData()
formData.append('file', file)
formData.append('username', currentUsername)
const res = await splashApi.uploadSomething(file, username)
if (res.url) {
localImageUrl.value = res.url // Update immediately
window.dispatchEvent(new CustomEvent('imageChanged'))
}
}
// Backend Controller
@PostMapping("/upload")
public AjaxResult upload(@RequestParam("file") MultipartFile file) {
String url = qiniuService.uploadFile(file);
// Save URL to database
return AjaxResult.success(url);
}
Technology Stack Details
Backend
- Framework: Spring Boot 2.5.15
- Security: Spring Security 5.7.12 + JWT
- ORM: MyBatis with PageHelper
- Database: MySQL
- Cache: Redis (Lettuce client)
- File Storage: Qiniu Cloud (七牛云)
- API Docs: Swagger 3.0.0
- Build: Maven
Frontend
- Framework: Vue 3.3.8 (Composition API with
<script setup>) - Desktop: Electron 32.1.2
- Build: Vite 4.5.0
- UI Library: Element Plus 2.11.3
- Language: TypeScript 5.2.2
- Excel: ExcelJS 4.4.0
Testing
Currently, there is no explicit test framework configured. When adding tests:
- Backend: Use JUnit with Spring Boot Test
- Frontend: Consider Vitest (already compatible with Vite)
Important Notes
- Chinese Language: All user-facing text should be in Chinese (simplified)
- Code Style: Follow existing patterns - keep code concise and avoid unnecessary abstractions
- No Auto-commit: Never commit changes unless explicitly requested by the user
- Secrets: Qiniu Cloud keys are in
application.yml- never expose in client code - Token Management: JWT tokens stored in Electron via
utils/token.ts, sent inAuthorizationheader - Image Proxy: Custom protocol handler in Electron for loading images from backend