Initial commit: Car Maintenance Management System
Author: Yang Lu School: Liaoning Institute of Science and Technology Major: Computer Science and Technology Class: BZ246 Tech Stack: - Backend: Spring Boot 2.7.18 + JPA + MySQL - Frontend: HTML5 + CSS3 + JavaScript Features: - User Management (Admin/Staff/Customer roles) - Vehicle Archive Management - Service Order Management - Parts Inventory Management - Online Appointment Service - Data Statistics and Analysis Generated with Claude Code Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
113
backend/pom.xml
Normal file
113
backend/pom.xml
Normal file
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.18</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.carmaintenance</groupId>
|
||||
<artifactId>car-maintenance-system</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>车管家4S店车辆维保管理系统</name>
|
||||
<description>基于Spring Boot的车辆维保管理系统后端服务</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot JPA -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL Driver -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.33</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Validation -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON处理 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.83</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons Lang -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot DevTools -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.carmaintenance;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
/**
|
||||
* 车管家4S店车辆维保管理系统 - 主应用程序
|
||||
* @author 杨璐
|
||||
* @date 2025-01-07
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableJpaAuditing
|
||||
public class CarMaintenanceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CarMaintenanceApplication.class, args);
|
||||
System.out.println("\n========================================");
|
||||
System.out.println("车管家4S店车辆维保管理系统启动成功!");
|
||||
System.out.println("访问地址: http://localhost:8080/api");
|
||||
System.out.println("========================================\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.carmaintenance.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Web配置 - CORS跨域配置
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
@Value("${cors.allowed-origins}")
|
||||
private String allowedOrigins;
|
||||
|
||||
@Value("${cors.allowed-methods}")
|
||||
private String allowedMethods;
|
||||
|
||||
@Value("${cors.allowed-headers}")
|
||||
private String allowedHeaders;
|
||||
|
||||
@Value("${cors.allow-credentials}")
|
||||
private boolean allowCredentials;
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOriginPatterns(allowedOrigins.split(","))
|
||||
.allowedMethods(allowedMethods.split(","))
|
||||
.allowedHeaders(allowedHeaders.split(","))
|
||||
.allowCredentials(allowCredentials)
|
||||
.maxAge(3600);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.carmaintenance.controller;
|
||||
|
||||
import com.carmaintenance.dto.Result;
|
||||
import com.carmaintenance.entity.Appointment;
|
||||
import com.carmaintenance.repository.AppointmentRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 预约管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/appointments")
|
||||
@CrossOrigin
|
||||
public class AppointmentController {
|
||||
|
||||
@Autowired
|
||||
private AppointmentRepository appointmentRepository;
|
||||
|
||||
/**
|
||||
* 获取所有预约
|
||||
*/
|
||||
@GetMapping
|
||||
public Result<List<Appointment>> getAllAppointments() {
|
||||
List<Appointment> appointments = appointmentRepository.findAll();
|
||||
return Result.success(appointments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取预约
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public Result<Appointment> getAppointmentById(@PathVariable Integer id) {
|
||||
Appointment appointment = appointmentRepository.findById(id).orElse(null);
|
||||
if (appointment == null) {
|
||||
return Result.notFound("预约不存在");
|
||||
}
|
||||
return Result.success(appointment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据客户ID获取预约列表
|
||||
*/
|
||||
@GetMapping("/customer/{customerId}")
|
||||
public Result<List<Appointment>> getAppointmentsByCustomerId(@PathVariable Integer customerId) {
|
||||
List<Appointment> appointments = appointmentRepository.findByCustomerId(customerId);
|
||||
return Result.success(appointments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据状态获取预约列表
|
||||
*/
|
||||
@GetMapping("/status/{status}")
|
||||
public Result<List<Appointment>> getAppointmentsByStatus(@PathVariable String status) {
|
||||
try {
|
||||
Appointment.AppointmentStatus appointmentStatus = Appointment.AppointmentStatus.valueOf(status);
|
||||
List<Appointment> appointments = appointmentRepository.findByStatus(appointmentStatus);
|
||||
return Result.success(appointments);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error("状态参数错误");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建预约
|
||||
*/
|
||||
@PostMapping
|
||||
public Result<Appointment> createAppointment(@RequestBody Appointment appointment) {
|
||||
appointment.setStatus(Appointment.AppointmentStatus.pending);
|
||||
Appointment savedAppointment = appointmentRepository.save(appointment);
|
||||
return Result.success("预约成功", savedAppointment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新预约
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public Result<Appointment> updateAppointment(@PathVariable Integer id, @RequestBody Appointment appointment) {
|
||||
Appointment existingAppointment = appointmentRepository.findById(id).orElse(null);
|
||||
if (existingAppointment == null) {
|
||||
return Result.notFound("预约不存在");
|
||||
}
|
||||
|
||||
if (appointment.getAppointmentTime() != null)
|
||||
existingAppointment.setAppointmentTime(appointment.getAppointmentTime());
|
||||
if (appointment.getContactPhone() != null)
|
||||
existingAppointment.setContactPhone(appointment.getContactPhone());
|
||||
if (appointment.getDescription() != null)
|
||||
existingAppointment.setDescription(appointment.getDescription());
|
||||
if (appointment.getStatus() != null)
|
||||
existingAppointment.setStatus(appointment.getStatus());
|
||||
if (appointment.getOrderId() != null)
|
||||
existingAppointment.setOrderId(appointment.getOrderId());
|
||||
|
||||
Appointment updatedAppointment = appointmentRepository.save(existingAppointment);
|
||||
return Result.success("更新成功", updatedAppointment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消预约
|
||||
*/
|
||||
@PutMapping("/{id}/cancel")
|
||||
public Result<Appointment> cancelAppointment(@PathVariable Integer id) {
|
||||
Appointment appointment = appointmentRepository.findById(id).orElse(null);
|
||||
if (appointment == null) {
|
||||
return Result.notFound("预约不存在");
|
||||
}
|
||||
|
||||
appointment.setStatus(Appointment.AppointmentStatus.cancelled);
|
||||
Appointment updatedAppointment = appointmentRepository.save(appointment);
|
||||
return Result.success("取消成功", updatedAppointment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除预约
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public Result<Void> deleteAppointment(@PathVariable Integer id) {
|
||||
if (!appointmentRepository.existsById(id)) {
|
||||
return Result.notFound("预约不存在");
|
||||
}
|
||||
appointmentRepository.deleteById(id);
|
||||
return Result.success("删除成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.carmaintenance.controller;
|
||||
|
||||
import com.carmaintenance.dto.LoginRequest;
|
||||
import com.carmaintenance.dto.LoginResponse;
|
||||
import com.carmaintenance.dto.Result;
|
||||
import com.carmaintenance.entity.User;
|
||||
import com.carmaintenance.repository.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 认证控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
@CrossOrigin
|
||||
public class AuthController {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public Result<LoginResponse> login(@RequestBody LoginRequest request) {
|
||||
if (request.getUsername() == null || request.getPassword() == null) {
|
||||
return Result.error("用户名和密码不能为空");
|
||||
}
|
||||
|
||||
User user = userRepository.findByUsernameAndPassword(
|
||||
request.getUsername(),
|
||||
request.getPassword()
|
||||
).orElse(null);
|
||||
|
||||
if (user == null) {
|
||||
return Result.error("用户名或密码错误");
|
||||
}
|
||||
|
||||
if (user.getStatus() != 1) {
|
||||
return Result.error("账号已被禁用");
|
||||
}
|
||||
|
||||
LoginResponse.UserInfo userInfo = new LoginResponse.UserInfo(
|
||||
user.getUserId(),
|
||||
user.getUsername(),
|
||||
user.getRealName(),
|
||||
user.getPhone(),
|
||||
user.getEmail(),
|
||||
user.getRole().name()
|
||||
);
|
||||
|
||||
String token = "TOKEN_" + user.getUserId() + "_" + System.currentTimeMillis();
|
||||
|
||||
LoginResponse response = new LoginResponse(token, userInfo);
|
||||
return Result.success("登录成功", response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public Result<User> register(@RequestBody User user) {
|
||||
if (userRepository.existsByUsername(user.getUsername())) {
|
||||
return Result.error("用户名已存在");
|
||||
}
|
||||
|
||||
if (userRepository.existsByPhone(user.getPhone())) {
|
||||
return Result.error("手机号已被注册");
|
||||
}
|
||||
|
||||
user.setRole(User.UserRole.customer);
|
||||
user.setStatus(1);
|
||||
User savedUser = userRepository.save(user);
|
||||
savedUser.setPassword(null);
|
||||
|
||||
return Result.success("注册成功", savedUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public Result<Void> logout() {
|
||||
return Result.success("退出成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.carmaintenance.controller;
|
||||
|
||||
import com.carmaintenance.dto.Result;
|
||||
import com.carmaintenance.entity.PartsInventory;
|
||||
import com.carmaintenance.repository.PartsInventoryRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 配件库存管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/parts")
|
||||
@CrossOrigin
|
||||
public class PartsInventoryController {
|
||||
|
||||
@Autowired
|
||||
private PartsInventoryRepository partsInventoryRepository;
|
||||
|
||||
/**
|
||||
* 获取所有配件
|
||||
*/
|
||||
@GetMapping
|
||||
public Result<List<PartsInventory>> getAllParts() {
|
||||
List<PartsInventory> parts = partsInventoryRepository.findAll();
|
||||
return Result.success(parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取配件
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public Result<PartsInventory> getPartById(@PathVariable Integer id) {
|
||||
PartsInventory part = partsInventoryRepository.findById(id).orElse(null);
|
||||
if (part == null) {
|
||||
return Result.notFound("配件不存在");
|
||||
}
|
||||
return Result.success(part);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类别获取配件列表
|
||||
*/
|
||||
@GetMapping("/category/{category}")
|
||||
public Result<List<PartsInventory>> getPartsByCategory(@PathVariable String category) {
|
||||
List<PartsInventory> parts = partsInventoryRepository.findByCategory(category);
|
||||
return Result.success(parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取库存预警配件
|
||||
*/
|
||||
@GetMapping("/low-stock")
|
||||
public Result<List<PartsInventory>> getLowStockParts() {
|
||||
List<PartsInventory> allParts = partsInventoryRepository.findAll();
|
||||
List<PartsInventory> lowStockParts = allParts.stream()
|
||||
.filter(part -> part.getStockQuantity() <= part.getMinStock())
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
return Result.success(lowStockParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建配件
|
||||
*/
|
||||
@PostMapping
|
||||
public Result<PartsInventory> createPart(@RequestBody PartsInventory part) {
|
||||
if (partsInventoryRepository.findByPartNo(part.getPartNo()).isPresent()) {
|
||||
return Result.error("配件编号已存在");
|
||||
}
|
||||
PartsInventory savedPart = partsInventoryRepository.save(part);
|
||||
return Result.success("创建成功", savedPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新配件
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public Result<PartsInventory> updatePart(@PathVariable Integer id, @RequestBody PartsInventory part) {
|
||||
PartsInventory existingPart = partsInventoryRepository.findById(id).orElse(null);
|
||||
if (existingPart == null) {
|
||||
return Result.notFound("配件不存在");
|
||||
}
|
||||
|
||||
if (part.getPartName() != null) existingPart.setPartName(part.getPartName());
|
||||
if (part.getCategory() != null) existingPart.setCategory(part.getCategory());
|
||||
if (part.getBrand() != null) existingPart.setBrand(part.getBrand());
|
||||
if (part.getModel() != null) existingPart.setModel(part.getModel());
|
||||
if (part.getUnit() != null) existingPart.setUnit(part.getUnit());
|
||||
if (part.getUnitPrice() != null) existingPart.setUnitPrice(part.getUnitPrice());
|
||||
if (part.getStockQuantity() != null) existingPart.setStockQuantity(part.getStockQuantity());
|
||||
if (part.getMinStock() != null) existingPart.setMinStock(part.getMinStock());
|
||||
if (part.getSupplier() != null) existingPart.setSupplier(part.getSupplier());
|
||||
if (part.getWarehouseLocation() != null) existingPart.setWarehouseLocation(part.getWarehouseLocation());
|
||||
if (part.getStatus() != null) existingPart.setStatus(part.getStatus());
|
||||
if (part.getRemark() != null) existingPart.setRemark(part.getRemark());
|
||||
|
||||
PartsInventory updatedPart = partsInventoryRepository.save(existingPart);
|
||||
return Result.success("更新成功", updatedPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除配件
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public Result<Void> deletePart(@PathVariable Integer id) {
|
||||
if (!partsInventoryRepository.existsById(id)) {
|
||||
return Result.notFound("配件不存在");
|
||||
}
|
||||
partsInventoryRepository.deleteById(id);
|
||||
return Result.success("删除成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.carmaintenance.controller;
|
||||
|
||||
import com.carmaintenance.dto.Result;
|
||||
import com.carmaintenance.entity.ServiceOrder;
|
||||
import com.carmaintenance.repository.ServiceOrderRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 维保工单管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/orders")
|
||||
@CrossOrigin
|
||||
public class ServiceOrderController {
|
||||
|
||||
@Autowired
|
||||
private ServiceOrderRepository serviceOrderRepository;
|
||||
|
||||
/**
|
||||
* 获取所有工单
|
||||
*/
|
||||
@GetMapping
|
||||
public Result<List<ServiceOrder>> getAllOrders() {
|
||||
List<ServiceOrder> orders = serviceOrderRepository.findAll();
|
||||
return Result.success(orders);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取工单
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public Result<ServiceOrder> getOrderById(@PathVariable Integer id) {
|
||||
ServiceOrder order = serviceOrderRepository.findById(id).orElse(null);
|
||||
if (order == null) {
|
||||
return Result.notFound("工单不存在");
|
||||
}
|
||||
return Result.success(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据客户ID获取工单列表
|
||||
*/
|
||||
@GetMapping("/customer/{customerId}")
|
||||
public Result<List<ServiceOrder>> getOrdersByCustomerId(@PathVariable Integer customerId) {
|
||||
List<ServiceOrder> orders = serviceOrderRepository.findByCustomerId(customerId);
|
||||
return Result.success(orders);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据车辆ID获取工单列表
|
||||
*/
|
||||
@GetMapping("/vehicle/{vehicleId}")
|
||||
public Result<List<ServiceOrder>> getOrdersByVehicleId(@PathVariable Integer vehicleId) {
|
||||
List<ServiceOrder> orders = serviceOrderRepository.findByVehicleId(vehicleId);
|
||||
return Result.success(orders);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据状态获取工单列表
|
||||
*/
|
||||
@GetMapping("/status/{status}")
|
||||
public Result<List<ServiceOrder>> getOrdersByStatus(@PathVariable String status) {
|
||||
try {
|
||||
ServiceOrder.OrderStatus orderStatus = ServiceOrder.OrderStatus.valueOf(status);
|
||||
List<ServiceOrder> orders = serviceOrderRepository.findByStatus(orderStatus);
|
||||
return Result.success(orders);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error("状态参数错误");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建工单
|
||||
*/
|
||||
@PostMapping
|
||||
public Result<ServiceOrder> createOrder(@RequestBody ServiceOrder order) {
|
||||
String orderNo = generateOrderNo();
|
||||
order.setOrderNo(orderNo);
|
||||
order.setStatus(ServiceOrder.OrderStatus.pending);
|
||||
order.setPaymentStatus(ServiceOrder.PaymentStatus.unpaid);
|
||||
|
||||
ServiceOrder savedOrder = serviceOrderRepository.save(order);
|
||||
return Result.success("工单创建成功", savedOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新工单
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public Result<ServiceOrder> updateOrder(@PathVariable Integer id, @RequestBody ServiceOrder order) {
|
||||
ServiceOrder existingOrder = serviceOrderRepository.findById(id).orElse(null);
|
||||
if (existingOrder == null) {
|
||||
return Result.notFound("工单不存在");
|
||||
}
|
||||
|
||||
if (order.getStaffId() != null) existingOrder.setStaffId(order.getStaffId());
|
||||
if (order.getArrivalTime() != null) existingOrder.setArrivalTime(order.getArrivalTime());
|
||||
if (order.getStartTime() != null) existingOrder.setStartTime(order.getStartTime());
|
||||
if (order.getCompleteTime() != null) existingOrder.setCompleteTime(order.getCompleteTime());
|
||||
if (order.getCurrentMileage() != null) existingOrder.setCurrentMileage(order.getCurrentMileage());
|
||||
if (order.getFaultDescription() != null) existingOrder.setFaultDescription(order.getFaultDescription());
|
||||
if (order.getDiagnosisResult() != null) existingOrder.setDiagnosisResult(order.getDiagnosisResult());
|
||||
if (order.getServiceItems() != null) existingOrder.setServiceItems(order.getServiceItems());
|
||||
if (order.getPartsCost() != null) existingOrder.setPartsCost(order.getPartsCost());
|
||||
if (order.getLaborCost() != null) existingOrder.setLaborCost(order.getLaborCost());
|
||||
if (order.getTotalCost() != null) existingOrder.setTotalCost(order.getTotalCost());
|
||||
if (order.getStatus() != null) existingOrder.setStatus(order.getStatus());
|
||||
if (order.getPaymentStatus() != null) existingOrder.setPaymentStatus(order.getPaymentStatus());
|
||||
if (order.getRemark() != null) existingOrder.setRemark(order.getRemark());
|
||||
|
||||
ServiceOrder updatedOrder = serviceOrderRepository.save(existingOrder);
|
||||
return Result.success("更新成功", updatedOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除工单
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public Result<Void> deleteOrder(@PathVariable Integer id) {
|
||||
if (!serviceOrderRepository.existsById(id)) {
|
||||
return Result.notFound("工单不存在");
|
||||
}
|
||||
serviceOrderRepository.deleteById(id);
|
||||
return Result.success("删除成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成工单编号
|
||||
*/
|
||||
private String generateOrderNo() {
|
||||
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||
long count = serviceOrderRepository.count() + 1;
|
||||
return "SO" + date + String.format("%04d", count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.carmaintenance.controller;
|
||||
|
||||
import com.carmaintenance.dto.Result;
|
||||
import com.carmaintenance.entity.User;
|
||||
import com.carmaintenance.repository.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
@CrossOrigin
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
/**
|
||||
* 获取所有用户
|
||||
*/
|
||||
@GetMapping
|
||||
public Result<List<User>> getAllUsers() {
|
||||
List<User> users = userRepository.findAll();
|
||||
users.forEach(user -> user.setPassword(null));
|
||||
return Result.success(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取用户
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public Result<User> getUserById(@PathVariable Integer id) {
|
||||
User user = userRepository.findById(id).orElse(null);
|
||||
if (user == null) {
|
||||
return Result.notFound("用户不存在");
|
||||
}
|
||||
user.setPassword(null);
|
||||
return Result.success(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色获取用户列表
|
||||
*/
|
||||
@GetMapping("/role/{role}")
|
||||
public Result<List<User>> getUsersByRole(@PathVariable String role) {
|
||||
try {
|
||||
User.UserRole userRole = User.UserRole.valueOf(role);
|
||||
List<User> users = userRepository.findByRole(userRole);
|
||||
users.forEach(user -> user.setPassword(null));
|
||||
return Result.success(users);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error("角色参数错误");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
@PostMapping
|
||||
public Result<User> createUser(@RequestBody User user) {
|
||||
if (userRepository.existsByUsername(user.getUsername())) {
|
||||
return Result.error("用户名已存在");
|
||||
}
|
||||
if (userRepository.existsByPhone(user.getPhone())) {
|
||||
return Result.error("手机号已被使用");
|
||||
}
|
||||
User savedUser = userRepository.save(user);
|
||||
savedUser.setPassword(null);
|
||||
return Result.success("创建成功", savedUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public Result<User> updateUser(@PathVariable Integer id, @RequestBody User user) {
|
||||
User existingUser = userRepository.findById(id).orElse(null);
|
||||
if (existingUser == null) {
|
||||
return Result.notFound("用户不存在");
|
||||
}
|
||||
|
||||
if (user.getRealName() != null) existingUser.setRealName(user.getRealName());
|
||||
if (user.getPhone() != null) existingUser.setPhone(user.getPhone());
|
||||
if (user.getEmail() != null) existingUser.setEmail(user.getEmail());
|
||||
if (user.getStatus() != null) existingUser.setStatus(user.getStatus());
|
||||
|
||||
User updatedUser = userRepository.save(existingUser);
|
||||
updatedUser.setPassword(null);
|
||||
return Result.success("更新成功", updatedUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public Result<Void> deleteUser(@PathVariable Integer id) {
|
||||
if (!userRepository.existsById(id)) {
|
||||
return Result.notFound("用户不存在");
|
||||
}
|
||||
userRepository.deleteById(id);
|
||||
return Result.success("删除成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
@PutMapping("/{id}/password")
|
||||
public Result<Void> changePassword(@PathVariable Integer id,
|
||||
@RequestParam String oldPassword,
|
||||
@RequestParam String newPassword) {
|
||||
User user = userRepository.findById(id).orElse(null);
|
||||
if (user == null) {
|
||||
return Result.notFound("用户不存在");
|
||||
}
|
||||
|
||||
if (!user.getPassword().equals(oldPassword)) {
|
||||
return Result.error("原密码错误");
|
||||
}
|
||||
|
||||
user.setPassword(newPassword);
|
||||
userRepository.save(user);
|
||||
return Result.success("密码修改成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.carmaintenance.controller;
|
||||
|
||||
import com.carmaintenance.dto.Result;
|
||||
import com.carmaintenance.entity.Vehicle;
|
||||
import com.carmaintenance.repository.VehicleRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 车辆管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/vehicles")
|
||||
@CrossOrigin
|
||||
public class VehicleController {
|
||||
|
||||
@Autowired
|
||||
private VehicleRepository vehicleRepository;
|
||||
|
||||
/**
|
||||
* 获取所有车辆
|
||||
*/
|
||||
@GetMapping
|
||||
public Result<List<Vehicle>> getAllVehicles() {
|
||||
List<Vehicle> vehicles = vehicleRepository.findAll();
|
||||
return Result.success(vehicles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取车辆
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public Result<Vehicle> getVehicleById(@PathVariable Integer id) {
|
||||
Vehicle vehicle = vehicleRepository.findById(id).orElse(null);
|
||||
if (vehicle == null) {
|
||||
return Result.notFound("车辆不存在");
|
||||
}
|
||||
return Result.success(vehicle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据客户ID获取车辆列表
|
||||
*/
|
||||
@GetMapping("/customer/{customerId}")
|
||||
public Result<List<Vehicle>> getVehiclesByCustomerId(@PathVariable Integer customerId) {
|
||||
List<Vehicle> vehicles = vehicleRepository.findByCustomerId(customerId);
|
||||
return Result.success(vehicles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据车牌号查询车辆
|
||||
*/
|
||||
@GetMapping("/plate/{licensePlate}")
|
||||
public Result<Vehicle> getVehicleByPlate(@PathVariable String licensePlate) {
|
||||
Vehicle vehicle = vehicleRepository.findByLicensePlate(licensePlate).orElse(null);
|
||||
if (vehicle == null) {
|
||||
return Result.notFound("车辆不存在");
|
||||
}
|
||||
return Result.success(vehicle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建车辆档案
|
||||
*/
|
||||
@PostMapping
|
||||
public Result<Vehicle> createVehicle(@RequestBody Vehicle vehicle) {
|
||||
if (vehicleRepository.findByLicensePlate(vehicle.getLicensePlate()).isPresent()) {
|
||||
return Result.error("车牌号已存在");
|
||||
}
|
||||
if (vehicle.getVin() != null && vehicleRepository.findByVin(vehicle.getVin()).isPresent()) {
|
||||
return Result.error("车架号已存在");
|
||||
}
|
||||
Vehicle savedVehicle = vehicleRepository.save(vehicle);
|
||||
return Result.success("创建成功", savedVehicle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新车辆信息
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public Result<Vehicle> updateVehicle(@PathVariable Integer id, @RequestBody Vehicle vehicle) {
|
||||
Vehicle existingVehicle = vehicleRepository.findById(id).orElse(null);
|
||||
if (existingVehicle == null) {
|
||||
return Result.notFound("车辆不存在");
|
||||
}
|
||||
|
||||
if (vehicle.getColor() != null) existingVehicle.setColor(vehicle.getColor());
|
||||
if (vehicle.getMileage() != null) existingVehicle.setMileage(vehicle.getMileage());
|
||||
if (vehicle.getLastMaintenanceDate() != null)
|
||||
existingVehicle.setLastMaintenanceDate(vehicle.getLastMaintenanceDate());
|
||||
if (vehicle.getNextMaintenanceDate() != null)
|
||||
existingVehicle.setNextMaintenanceDate(vehicle.getNextMaintenanceDate());
|
||||
if (vehicle.getStatus() != null) existingVehicle.setStatus(vehicle.getStatus());
|
||||
|
||||
Vehicle updatedVehicle = vehicleRepository.save(existingVehicle);
|
||||
return Result.success("更新成功", updatedVehicle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除车辆
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public Result<Void> deleteVehicle(@PathVariable Integer id) {
|
||||
if (!vehicleRepository.existsById(id)) {
|
||||
return Result.notFound("车辆不存在");
|
||||
}
|
||||
vehicleRepository.deleteById(id);
|
||||
return Result.success("删除成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.carmaintenance.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 登录请求DTO
|
||||
*/
|
||||
@Data
|
||||
public class LoginRequest {
|
||||
private String username;
|
||||
private String password;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.carmaintenance.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 登录响应DTO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginResponse {
|
||||
private String token;
|
||||
private UserInfo userInfo;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class UserInfo {
|
||||
private Integer userId;
|
||||
private String username;
|
||||
private String realName;
|
||||
private String phone;
|
||||
private String email;
|
||||
private String role;
|
||||
}
|
||||
}
|
||||
54
backend/src/main/java/com/carmaintenance/dto/Result.java
Normal file
54
backend/src/main/java/com/carmaintenance/dto/Result.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package com.carmaintenance.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 统一API响应结果
|
||||
*/
|
||||
@Data
|
||||
public class Result<T> {
|
||||
|
||||
private Integer code;
|
||||
private String message;
|
||||
private T data;
|
||||
|
||||
private Result() {}
|
||||
|
||||
private Result(Integer code, String message, T data) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static <T> Result<T> success() {
|
||||
return new Result<>(200, "操作成功", null);
|
||||
}
|
||||
|
||||
public static <T> Result<T> success(T data) {
|
||||
return new Result<>(200, "操作成功", data);
|
||||
}
|
||||
|
||||
public static <T> Result<T> success(String message, T data) {
|
||||
return new Result<>(200, message, data);
|
||||
}
|
||||
|
||||
public static <T> Result<T> error(String message) {
|
||||
return new Result<>(500, message, null);
|
||||
}
|
||||
|
||||
public static <T> Result<T> error(Integer code, String message) {
|
||||
return new Result<>(code, message, null);
|
||||
}
|
||||
|
||||
public static <T> Result<T> unauthorized(String message) {
|
||||
return new Result<>(401, message, null);
|
||||
}
|
||||
|
||||
public static <T> Result<T> forbidden(String message) {
|
||||
return new Result<>(403, message, null);
|
||||
}
|
||||
|
||||
public static <T> Result<T> notFound(String message) {
|
||||
return new Result<>(404, message, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.carmaintenance.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 预约记录实体
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "appointments")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class Appointment {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "appointment_id")
|
||||
private Integer appointmentId;
|
||||
|
||||
@Column(name = "customer_id", nullable = false)
|
||||
private Integer customerId;
|
||||
|
||||
@Column(name = "vehicle_id", nullable = false)
|
||||
private Integer vehicleId;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "service_type", nullable = false)
|
||||
private ServiceType serviceType;
|
||||
|
||||
@Column(name = "appointment_time", nullable = false)
|
||||
private LocalDateTime appointmentTime;
|
||||
|
||||
@Column(name = "contact_phone", nullable = false, length = 20)
|
||||
private String contactPhone;
|
||||
|
||||
@Column(name = "description", columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status")
|
||||
private AppointmentStatus status = AppointmentStatus.pending;
|
||||
|
||||
@Column(name = "order_id")
|
||||
private Integer orderId;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
public enum ServiceType {
|
||||
maintenance, repair, beauty, insurance
|
||||
}
|
||||
|
||||
public enum AppointmentStatus {
|
||||
pending, confirmed, completed, cancelled
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.carmaintenance.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 客户信息实体
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "customers")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class Customer {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "customer_id")
|
||||
private Integer customerId;
|
||||
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private Integer userId;
|
||||
|
||||
@Column(name = "customer_no", unique = true, length = 50)
|
||||
private String customerNo;
|
||||
|
||||
@Column(name = "id_card", length = 18)
|
||||
private String idCard;
|
||||
|
||||
@Column(name = "address", length = 200)
|
||||
private String address;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "gender")
|
||||
private Gender gender;
|
||||
|
||||
@Column(name = "birth_date")
|
||||
private LocalDate birthDate;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "membership_level")
|
||||
private MembershipLevel membershipLevel = MembershipLevel.normal;
|
||||
|
||||
@Column(name = "points")
|
||||
private Integer points = 0;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
public enum Gender {
|
||||
male, female, other
|
||||
}
|
||||
|
||||
public enum MembershipLevel {
|
||||
normal, silver, gold, platinum
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.carmaintenance.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 配件库存实体
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "parts_inventory")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class PartsInventory {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "part_id")
|
||||
private Integer partId;
|
||||
|
||||
@Column(name = "part_no", nullable = false, unique = true, length = 50)
|
||||
private String partNo;
|
||||
|
||||
@Column(name = "part_name", nullable = false, length = 100)
|
||||
private String partName;
|
||||
|
||||
@Column(name = "category", length = 50)
|
||||
private String category;
|
||||
|
||||
@Column(name = "brand", length = 50)
|
||||
private String brand;
|
||||
|
||||
@Column(name = "model", length = 100)
|
||||
private String model;
|
||||
|
||||
@Column(name = "unit", length = 20)
|
||||
private String unit = "个";
|
||||
|
||||
@Column(name = "unit_price", nullable = false, precision = 10, scale = 2)
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
@Column(name = "stock_quantity")
|
||||
private Integer stockQuantity = 0;
|
||||
|
||||
@Column(name = "min_stock")
|
||||
private Integer minStock = 10;
|
||||
|
||||
@Column(name = "supplier", length = 100)
|
||||
private String supplier;
|
||||
|
||||
@Column(name = "warehouse_location", length = 50)
|
||||
private String warehouseLocation;
|
||||
|
||||
@Column(name = "status")
|
||||
private Integer status = 1;
|
||||
|
||||
@Column(name = "remark", columnDefinition = "TEXT")
|
||||
private String remark;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.carmaintenance.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 服务项目实体
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "service_items")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class ServiceItem {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "item_id")
|
||||
private Integer itemId;
|
||||
|
||||
@Column(name = "item_code", nullable = false, unique = true, length = 50)
|
||||
private String itemCode;
|
||||
|
||||
@Column(name = "item_name", nullable = false, length = 100)
|
||||
private String itemName;
|
||||
|
||||
@Column(name = "category", length = 50)
|
||||
private String category;
|
||||
|
||||
@Column(name = "standard_price", nullable = false, precision = 10, scale = 2)
|
||||
private BigDecimal standardPrice;
|
||||
|
||||
@Column(name = "duration")
|
||||
private Integer duration;
|
||||
|
||||
@Column(name = "description", columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
@Column(name = "status")
|
||||
private Integer status = 1;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.carmaintenance.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 维保工单实体
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "service_orders")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class ServiceOrder {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "order_id")
|
||||
private Integer orderId;
|
||||
|
||||
@Column(name = "order_no", nullable = false, unique = true, length = 50)
|
||||
private String orderNo;
|
||||
|
||||
@Column(name = "vehicle_id", nullable = false)
|
||||
private Integer vehicleId;
|
||||
|
||||
@Column(name = "customer_id", nullable = false)
|
||||
private Integer customerId;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "service_type", nullable = false)
|
||||
private ServiceType serviceType;
|
||||
|
||||
@Column(name = "appointment_time")
|
||||
private LocalDateTime appointmentTime;
|
||||
|
||||
@Column(name = "arrival_time")
|
||||
private LocalDateTime arrivalTime;
|
||||
|
||||
@Column(name = "start_time")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
@Column(name = "complete_time")
|
||||
private LocalDateTime completeTime;
|
||||
|
||||
@Column(name = "staff_id")
|
||||
private Integer staffId;
|
||||
|
||||
@Column(name = "current_mileage", precision = 10, scale = 2)
|
||||
private BigDecimal currentMileage;
|
||||
|
||||
@Column(name = "fault_description", columnDefinition = "TEXT")
|
||||
private String faultDescription;
|
||||
|
||||
@Column(name = "diagnosis_result", columnDefinition = "TEXT")
|
||||
private String diagnosisResult;
|
||||
|
||||
@Column(name = "service_items", columnDefinition = "TEXT")
|
||||
private String serviceItems;
|
||||
|
||||
@Column(name = "parts_cost", precision = 10, scale = 2)
|
||||
private BigDecimal partsCost = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "labor_cost", precision = 10, scale = 2)
|
||||
private BigDecimal laborCost = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "total_cost", precision = 10, scale = 2)
|
||||
private BigDecimal totalCost = BigDecimal.ZERO;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status")
|
||||
private OrderStatus status = OrderStatus.pending;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "payment_status")
|
||||
private PaymentStatus paymentStatus = PaymentStatus.unpaid;
|
||||
|
||||
@Column(name = "remark", columnDefinition = "TEXT")
|
||||
private String remark;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
public enum ServiceType {
|
||||
maintenance, repair, beauty, insurance
|
||||
}
|
||||
|
||||
public enum OrderStatus {
|
||||
pending, appointed, in_progress, completed, cancelled
|
||||
}
|
||||
|
||||
public enum PaymentStatus {
|
||||
unpaid, paid, refunded
|
||||
}
|
||||
}
|
||||
58
backend/src/main/java/com/carmaintenance/entity/User.java
Normal file
58
backend/src/main/java/com/carmaintenance/entity/User.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package com.carmaintenance.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户实体
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "user_id")
|
||||
private Integer userId;
|
||||
|
||||
@Column(name = "username", nullable = false, unique = true, length = 50)
|
||||
private String username;
|
||||
|
||||
@Column(name = "password", nullable = false)
|
||||
private String password;
|
||||
|
||||
@Column(name = "real_name", nullable = false, length = 50)
|
||||
private String realName;
|
||||
|
||||
@Column(name = "phone", nullable = false, length = 20)
|
||||
private String phone;
|
||||
|
||||
@Column(name = "email", length = 100)
|
||||
private String email;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "role", nullable = false)
|
||||
private UserRole role;
|
||||
|
||||
@Column(name = "status")
|
||||
private Integer status = 1;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
public enum UserRole {
|
||||
admin, staff, customer
|
||||
}
|
||||
}
|
||||
75
backend/src/main/java/com/carmaintenance/entity/Vehicle.java
Normal file
75
backend/src/main/java/com/carmaintenance/entity/Vehicle.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package com.carmaintenance.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 车辆档案实体
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "vehicles")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class Vehicle {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "vehicle_id")
|
||||
private Integer vehicleId;
|
||||
|
||||
@Column(name = "customer_id", nullable = false)
|
||||
private Integer customerId;
|
||||
|
||||
@Column(name = "license_plate", nullable = false, unique = true, length = 20)
|
||||
private String licensePlate;
|
||||
|
||||
@Column(name = "brand", nullable = false, length = 50)
|
||||
private String brand;
|
||||
|
||||
@Column(name = "model", nullable = false, length = 50)
|
||||
private String model;
|
||||
|
||||
@Column(name = "color", length = 20)
|
||||
private String color;
|
||||
|
||||
@Column(name = "vin", unique = true, length = 17)
|
||||
private String vin;
|
||||
|
||||
@Column(name = "engine_no", length = 50)
|
||||
private String engineNo;
|
||||
|
||||
@Column(name = "purchase_date")
|
||||
private LocalDate purchaseDate;
|
||||
|
||||
@Column(name = "mileage", precision = 10, scale = 2)
|
||||
private BigDecimal mileage = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "last_maintenance_date")
|
||||
private LocalDate lastMaintenanceDate;
|
||||
|
||||
@Column(name = "next_maintenance_date")
|
||||
private LocalDate nextMaintenanceDate;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status")
|
||||
private VehicleStatus status = VehicleStatus.normal;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
public enum VehicleStatus {
|
||||
normal, in_service, completed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.carmaintenance.repository;
|
||||
|
||||
import com.carmaintenance.entity.Appointment;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 预约记录Repository
|
||||
*/
|
||||
@Repository
|
||||
public interface AppointmentRepository extends JpaRepository<Appointment, Integer> {
|
||||
|
||||
List<Appointment> findByCustomerId(Integer customerId);
|
||||
|
||||
List<Appointment> findByVehicleId(Integer vehicleId);
|
||||
|
||||
List<Appointment> findByStatus(Appointment.AppointmentStatus status);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.carmaintenance.repository;
|
||||
|
||||
import com.carmaintenance.entity.Customer;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 客户Repository
|
||||
*/
|
||||
@Repository
|
||||
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
|
||||
|
||||
Optional<Customer> findByUserId(Integer userId);
|
||||
|
||||
Optional<Customer> findByCustomerNo(String customerNo);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.carmaintenance.repository;
|
||||
|
||||
import com.carmaintenance.entity.PartsInventory;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 配件库存Repository
|
||||
*/
|
||||
@Repository
|
||||
public interface PartsInventoryRepository extends JpaRepository<PartsInventory, Integer> {
|
||||
|
||||
Optional<PartsInventory> findByPartNo(String partNo);
|
||||
|
||||
List<PartsInventory> findByCategory(String category);
|
||||
|
||||
List<PartsInventory> findByStatus(Integer status);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.carmaintenance.repository;
|
||||
|
||||
import com.carmaintenance.entity.ServiceItem;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 服务项目Repository
|
||||
*/
|
||||
@Repository
|
||||
public interface ServiceItemRepository extends JpaRepository<ServiceItem, Integer> {
|
||||
|
||||
Optional<ServiceItem> findByItemCode(String itemCode);
|
||||
|
||||
List<ServiceItem> findByCategory(String category);
|
||||
|
||||
List<ServiceItem> findByStatus(Integer status);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.carmaintenance.repository;
|
||||
|
||||
import com.carmaintenance.entity.ServiceOrder;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 维保工单Repository
|
||||
*/
|
||||
@Repository
|
||||
public interface ServiceOrderRepository extends JpaRepository<ServiceOrder, Integer> {
|
||||
|
||||
Optional<ServiceOrder> findByOrderNo(String orderNo);
|
||||
|
||||
List<ServiceOrder> findByCustomerId(Integer customerId);
|
||||
|
||||
List<ServiceOrder> findByVehicleId(Integer vehicleId);
|
||||
|
||||
List<ServiceOrder> findByStaffId(Integer staffId);
|
||||
|
||||
List<ServiceOrder> findByStatus(ServiceOrder.OrderStatus status);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.carmaintenance.repository;
|
||||
|
||||
import com.carmaintenance.entity.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 用户Repository
|
||||
*/
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, Integer> {
|
||||
|
||||
Optional<User> findByUsername(String username);
|
||||
|
||||
Optional<User> findByUsernameAndPassword(String username, String password);
|
||||
|
||||
List<User> findByRole(User.UserRole role);
|
||||
|
||||
boolean existsByUsername(String username);
|
||||
|
||||
boolean existsByPhone(String phone);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.carmaintenance.repository;
|
||||
|
||||
import com.carmaintenance.entity.Vehicle;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 车辆Repository
|
||||
*/
|
||||
@Repository
|
||||
public interface VehicleRepository extends JpaRepository<Vehicle, Integer> {
|
||||
|
||||
List<Vehicle> findByCustomerId(Integer customerId);
|
||||
|
||||
Optional<Vehicle> findByLicensePlate(String licensePlate);
|
||||
|
||||
Optional<Vehicle> findByVin(String vin);
|
||||
}
|
||||
43
backend/src/main/resources/application.properties
Normal file
43
backend/src/main/resources/application.properties
Normal file
@@ -0,0 +1,43 @@
|
||||
# 应用配置
|
||||
spring.application.name=car-maintenance-system
|
||||
server.port=8080
|
||||
server.servlet.context-path=/api
|
||||
|
||||
# 数据库配置
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/car_maintenance_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=123456
|
||||
|
||||
# JPA配置
|
||||
spring.jpa.database=mysql
|
||||
spring.jpa.show-sql=true
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
|
||||
spring.jpa.properties.hibernate.format_sql=true
|
||||
|
||||
# 日志配置
|
||||
logging.level.root=INFO
|
||||
logging.level.com.carmaintenance=DEBUG
|
||||
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
|
||||
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
|
||||
|
||||
# 文件上传配置
|
||||
spring.servlet.multipart.enabled=true
|
||||
spring.servlet.multipart.max-file-size=10MB
|
||||
spring.servlet.multipart.max-request-size=10MB
|
||||
|
||||
# Jackson配置
|
||||
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
|
||||
spring.jackson.time-zone=GMT+8
|
||||
spring.jackson.serialization.write-dates-as-timestamps=false
|
||||
|
||||
# JWT配置
|
||||
jwt.secret=carMaintenanceSystemSecretKey2025
|
||||
jwt.expiration=86400000
|
||||
|
||||
# CORS跨域配置
|
||||
cors.allowed-origins=http://localhost:3000,http://localhost:5500,http://127.0.0.1:5500
|
||||
cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
|
||||
cors.allowed-headers=*
|
||||
cors.allow-credentials=true
|
||||
Reference in New Issue
Block a user