编辑 | blame | 历史 | 原始文档

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

TMS (Transportation Management System) is a full-stack application for managing transportation operations, built on the RuoYi framework.

  • Backend: Java Spring Boot 2.5.15 (Java 8), Maven multi-module architecture
  • Frontend: Vue 3 + TypeScript + Vite with Element Plus UI library
  • Database: MySQL with MyBatis-Plus ORM
  • Key Custom Module: tms for transportation management features

Architecture Overview

Backend Architecture (Maven Multi-Module)

manage (parent pom)
├── admin          # Spring Boot entry point & web server
├── framework      # Core security, permissions, base classes
├── system         # System management (users, roles, menus)
├── common         # Shared utilities and constants
├── service        # Business service layer
├── api            # API contracts/interfaces
├── tms            # Transportation Management System domain
└── quartz         # Scheduled task management

Key Architectural Pattern:
- Layered Architecture: Controller → Service → Mapper (MyBatis) → Database
- Security: Spring Security with custom PermissionService (@Service("ss")) for permission checking
- Permission Model: @PreAuthorize("@ss.hasPermi('module:action:operation')") on controllers
- Async Processing: AsyncManager for fire-and-forget async operations
- API Documentation: Swagger 3.0 available at /swagger-ui.html

Frontend Architecture (Vue 3 + Vite)

src/
├── api/          # API service classes (axios calls)
├── router/       # Route definitions & navigation guards
├── store/        # Pinia stores (user, app state)
├── views/        # Page components (organized by module)
├── components/   # Reusable UI components
├── hooks/        # Composition API hooks
├── directive/    # Vue directives (permission checks, etc.)
├── layout/       # Layout templates
├── utils/        # Helper functions & utilities
├── assets/       # Static resources (images, styles)
└── plugins/      # Vue plugin configuration

Key Architectural Patterns:
- CRUD Forms: Built with Avue (@smallwei/avue) - declarative configuration-based CRUD
- State Management: Pinia for user auth, permissions, global app state
- API Layer: Axios instance with interceptors for auth/error handling
- Permission Control: v-hasPermi directive and hasPermission() function
- Responsive: Element Plus component library for UI

Build & Development Commands

Backend (Java/Maven)

# Build all modules
mvn clean package

# Build specific module (e.g., admin)
mvn clean package -pl admin -am

# Run tests (currently disabled in pom.xml)
mvn test -DskipTests=false

# Build and skip tests
mvn clean package -DskipTests

# Start development with Spring Boot DevTools
# Run from admin module's main class: com.ruoyi.RuoyiApplication
# IDE: Right-click Application.java → Run

Note: The admin module is the web entry point. Start the application by running the Application class in admin/src/main/java/com/ruoyi/.

Frontend (Vue 3/Vite)

cd ui/admin-ui3

# Install dependencies
npm install
# or
pnpm install

# Development server (hot reload on port 5173)
npm run dev

# Production build
npm run build:prod

# Staging build (with staging config)
npm run build:stage

# Preview production build
npm run preview

Environment Configuration:
- .env.development - development environment variables
- Check vite.config.ts for proxy settings and build configuration

Permission System

Backend Permission Structure

Permission String Format: module:action:operation

Examples:
- tms:tmsDispatchOrder:list - List dispatch orders
- tms:tmsDispatchOrder:add - Create dispatch order
- tms:tmsDispatchOrder:edit - Edit dispatch order
- tms:tmsDispatchOrder:remove - Delete dispatch order
- tms:tmsDispatchOrder:export - Export dispatch orders

Usage in Controllers:

@PreAuthorize("@ss.hasPermi('tms:tmsDispatchOrder:list')")
@GetMapping("/list")
public TableDataInfo list(TmsDispatchOrder order) {
    startPage();
    List<TmsDispatchOrder> list = tmsDispatchOrderService.selectTmsDispatchOrderList(order);
    return getDataTable(list);
}

Frontend Permission Control

Checking Permissions in Components:

import { hasPermission } from "@/utils/permissionUtils";
import { computed } from "vue";

// In setup() or script setup
const permissionList = computed(() => ({
    addBtn: hasPermission(["tms:tmsDispatchOrder:add"]),
    editBtn: hasPermission(["tms:tmsDispatchOrder:edit"]),
    deleteBtn: hasPermission(["tms:tmsDispatchOrder:remove"]),
}));

Using Permission Directives:

<!-- Show button only if user has permission -->
<el-button v-hasPermi="['tms:tmsDispatchOrder:add']" @click="handleAdd">
  Add Order
</el-button>

<!-- Show element if user has role -->
<div v-hasRole="['admin']">Admin only content</div>

Code Patterns & Conventions

Backend Patterns

Service Layer:
- Located in tms/src/main/java/com/ruoyi/tms/service/
- Interface in service/ directory, implementation in service/impl/
- Inject mapper using @Autowired or constructor injection
- Use BaseServiceImpl<T, K> as base class for CRUD operations

Controller Layer:
- Located in tms/src/main/java/com/ruoyi/tms/controller/
- Extend BaseController for standard pagination/response handling
- Return AjaxResult for JSON responses
- Return TableDataInfo for paginated data tables

Mapper (Data Access):
- Located in tms/src/main/resources/mapper/tms/ (XML files)
- Interfaces in tms/src/main/java/com/ruoyi/tms/mapper/
- Use MyBatis dynamic SQL for flexible queries

Domain Models:
- Located in tms/src/main/java/com/ruoyi/tms/domain/
- Use Lombok @Data, @Builder for getters/setters
- Use @TableName annotation for MyBatis mapping
- VO (View Objects) for API responses in domain/vo/ subdirectory

Example Service Structure:
```java
// Interface
public interface TmsDispatchOrderService extends IBaseService<TmsDispatchOrder, Long> {
List selectTmsDispatchOrderList(TmsDispatchOrder order);
}

// Implementation
@Service
public class TmsDispatchOrderServiceImpl extends BaseServiceImpl<TmsDispatchOrderMapper, TmsDispatchOrder>
implements TmsDispatchOrderService {
@Override
public List selectTmsDispatchOrderList(TmsDispatchOrder order) {
return baseMapper.selectTmsDispatchOrderList(order);
}
}

// Controller
@RestController
@RequestMapping("/tms/tmsDispatchOrder")
public class TmsDispatchOrderController extends BaseController {
@Autowired
private TmsDispatchOrderService tmsDispatchOrderService;

@PreAuthorize("@ss.hasPermi('tms:tmsDispatchOrder:list')")
@GetMapping("/list")
public TableDataInfo list(TmsDispatchOrder order) {
    startPage();
    List<TmsDispatchOrder> list = tmsDispatchOrderService.selectTmsDispatchOrderList(order);
    return getDataTable(list);
}

}
```

Frontend Patterns

API Service Layer (src/api/tms/tmsDispatchOrder.ts):
```typescript
import request from "@/utils/request";

export interface TmsDispatchOrderI {
id?: string;
planCode?: string;
customerName?: string;
// ... other fields
}

export const listTmsDispatchOrder = (
data: TmsDispatchOrderI & any
): Promise => {
return request.get("/tms/tmsDispatchOrder/list", { params: data });
};

export const getTmsDispatchOrder = (id: string): Promise => {
return request.get("/tms/tmsDispatchOrder/" + id);
};

export const addTmsDispatchOrder = (data: TmsDispatchOrderI): Promise => {
return request.post("/tms/tmsDispatchOrder", data);
};

export const updateTmsDispatchOrder = (data: TmsDispatchOrderI): Promise => {
return request.put("/tms/tmsDispatchOrder", data);
};

export const delTmsDispatchOrder = (id: string): Promise => {
return request.delete("/tms/tmsDispatchOrder/" + id);
};
```

Avue CRUD Component (data-driven form configuration):
```vue


<avue-crud
:option="option"
:data="tableData"
:page="page"
:permission="permissionList"
v-model="form"
v-model:search="queryParams"
@row-save="rowSave"
@row-update="rowUpdate"
@row-del="rowDel"
@search-change="searchChange"
/>


**Pinia Store Pattern** (`src/store/modules/user.ts`):

import { defineStore } from "pinia";

export interface UserState {
token?: string;
roles: string[];
permissions: string[];
user?: { userName: string; [key: string]: any };
}

export const useUserStore = defineStore("user", {
state: (): UserState => ({
token: undefined,
roles: [],
permissions: [],
}),

getters: {
getToken(): string {
return this.token || "";
},
},

actions: {
// Get user info and set roles/permissions from backend
async GetInfo() {
const res = await getInfo();
this.roles = res.roles || [];
this.permissions = res.permissions || [];
return res;
},
},
});
```

Database Conventions

Naming Patterns

  • Tables: Snake case, prefixed by module (e.g., tms_dispatch_order, tms_quote_detail)
  • Columns: Snake case (e.g., customer_id, created_time)
  • Primary Key: Usually id (bigint)
  • Common Fields: create_by, create_time, update_by, update_time, remark, del_flag

Key Tables (TMS Module)

  • tms_dispatch_order - Main dispatch order entity
  • tms_plan_order - Transportation plan orders
  • tms_quote_detail - Quote details for routes
  • tms_customer_info - Customer information
  • tms_driver - Driver management
  • tms_vehicle - Vehicle/truck information
  • tms_service_provider - Third-party service providers

Key Files & Locations

Backend Configuration

  • admin/src/main/resources/application.yml - Main application configuration
  • admin/src/main/resources/application-custom.yml - Custom configurations (API keys, Aliyun)
  • admin/src/main/resources/application-{profile}.yml - Profile-specific configs

Frontend Configuration

  • ui/admin-ui3/vite.config.ts - Vite build configuration
  • ui/admin-ui3/.env.development - Development environment variables
  • ui/admin-ui3/src/settings.ts - App-wide settings (theme, layout)

Database & Migrations

  • sql/ - Database initialization and migration scripts
  • Scripts are typically named by date (e.g., tms_202501101.sql)

Common Development Tasks

Adding a New API Endpoint

  1. Backend:
    java @PostMapping("/smartDispatch") @PreAuthorize("@ss.hasPermi('tms:tmsDispatchOrder:smartDispatch')") public AjaxResult smartDispatch(@RequestParam("file") MultipartFile file) { // Implementation return success(result); }

  2. Permission Registration:

  • Add permission to sys_menu table: INSERT INTO sys_menu VALUES(..., 'tms:tmsDispatchOrder:smartDispatch', ...)
  • Assign to roles in sys_role_menu table
  1. Frontend API Service:
    typescript export const smartDispatchExtract = (file: File): Promise<any> => { const formData = new FormData(); formData.append("file", file); return request.post("/tms/tmsDispatchOrder/smartDispatch", formData); };

  2. Frontend Component:
    vue <el-button v-hasPermi="['tms:tmsDispatchOrder:smartDispatch']" @click="handleSmartDispatch"> Smart Dispatch </el-button>

Modifying Database Schema

  1. Create migration script in sql/ directory (e.g., tms_20260304.sql)
  2. Apply script to database: mysql -u root -p database_name < sql/tms_20260304.sql
  3. Update corresponding domain models and mappers in tms/ module
  4. Regenerate MyBatis mappers if using generation tool

Working with Avue CRUD Forms

Key properties for column configuration:
- label - Display label
- type - Input type (input, select, textarea, date, table, etc.)
- addDisplay - Show in add dialog
- editDisplay - Show in edit dialog
- viewDisplay - Show in view/detail page
- search - Searchable in filter bar
- hide - Hide from table display
- dicUrl - URL for dropdown options (e.g., /system/dict/data/type/order_type)
- rules - Validation rules
- children - Nested table configuration for 1-to-many relationships

Testing

  • Unit tests are currently skipped in Maven build (<skipTests>true</skipTests> in pom.xml)
  • To enable tests: mvn test -DskipTests=false
  • Frontend tests would require Jest/Vitest setup (currently not configured)

Deployment

Backend

  • Build: mvn clean package produces admin/target/admin.jar
  • Run: java -jar admin.jar or use Spring Boot deployment
  • Configuration: Set active profile via spring.profiles.active property

Frontend

  • Build: npm run build:prod generates optimized assets in dist/ directory
  • Serve: Copy dist/ contents to web server (Nginx, Apache) or serve via Spring Boot static resources

Important Notes

Security & Permissions

  • All API endpoints must have @PreAuthorize annotation with appropriate permission
  • Permission strings follow pattern: module:action:operation
  • Database-driven permission system - add new permissions via sys_menu table
  • Never hardcode permissions in code

Frontend State Management

  • Use Pinia stores for global state (user, app settings)
  • Use component-level reactive() or ref() for local state
  • Permissions are loaded from backend on login and stored in user store

Error Handling

  • Backend returns AjaxResult with code, msg, data fields
  • HTTP 401: Unauthorized (redirect to login)
  • HTTP 403: Forbidden (no permission)
  • HTTP 500: Server error
  • Frontend interceptor handles errors globally

Code Organization

  • Keep components focused and single-responsibility
  • Extract reusable logic into hooks (src/hooks/)
  • Put shared utilities in src/utils/
  • Organize views by feature module matching backend structure

Troubleshooting

Backend Won't Start:
- Check MySQL connection in application.yml
- Verify database exists and migrations are applied
- Check port 8080 is not in use (or change in config)
- Review logs in logs/ directory

Frontend Dev Server Issues:
- Delete node_modules/ and package-lock.json, then npm install
- Clear .vite/ cache directory
- Check Vite port 5173 is not in use

Permission Denied on Frontend:
- Verify user has proper role assigned in sys_user_role table
- Verify role is assigned permission in sys_role_menu table
- Check permission string format is correct
- Clear browser localStorage and re-login

Related Documentation

  • RuoYi Framework: Based on popular RuoYi open-source framework
  • Avue: Data-driven CRUD form framework - key for table operations
  • MyBatis: ORM framework for database access
  • Spring Security: Authentication and authorization framework
  • Vite: Frontend build tool and dev server
  • Pinia: Vue 3 state management library