- 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
271 lines
8.8 KiB
Markdown
271 lines
8.8 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 a **hybrid ERP system** consisting of:
|
|
1. **Backend**: RuoYi-Vue (Spring Boot 2.5.15 + MyBatis) - Java 17 management system
|
|
2. **Desktop Client**: Electron + Vue 3 + TypeScript application
|
|
3. **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)
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
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_account` table (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 changes
|
|
- `window.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 `accountType` field in `ClientAccount` (values: `trial`, `paid`)
|
|
- Trial accounts show `TrialExpiredDialog` when attempting VIP features
|
|
- VIP validation happens in `SettingsDialog.vue` before 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:
|
|
1. Write SQL migration script in `sql/` directory
|
|
2. Update Java entity in `ruoyi-system/src/main/java/com/ruoyi/system/domain/`
|
|
3. Update MyBatis mapper XML in `ruoyi-system/src/main/resources/mapper/system/`
|
|
4. 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
|
|
|
|
1. **Backend** (Spring Boot):
|
|
```java
|
|
// In appropriate Controller (e.g., ClientAccountController.java)
|
|
@PostMapping("/your-endpoint")
|
|
public AjaxResult yourMethod(@RequestBody YourDTO dto) {
|
|
// Implementation
|
|
return AjaxResult.success(result);
|
|
}
|
|
```
|
|
|
|
2. **Frontend** (Vue/TypeScript):
|
|
```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)
|
|
}
|
|
}
|
|
```
|
|
|
|
3. **Component usage**:
|
|
```vue
|
|
<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
|
|
|
|
```typescript
|
|
// 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'))
|
|
}
|
|
}
|
|
```
|
|
|
|
```java
|
|
// 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 in `Authorization` header
|
|
- **Image Proxy**: Custom protocol handler in Electron for loading images from backend
|