Java全栈项目 - 汽车维修服务管理平台

项目介绍

汽车维修服务管理平台是一个面向汽修店的综合业务管理系统。该平台帮助汽修店实现维修预约、工单管理、库存管理、客户管理等核心业务流程的数字化,提升运营效率。

技术架构

后端技术栈

  • Spring Boot 2.x:应用开发框架
  • Spring Security:认证和权限控制
  • MyBatis Plus:ORM框架
  • MySQL:关系型数据库
  • Redis:缓存数据库
  • JWT:用户会话管理
  • Maven:项目构建工具

前端技术栈

  • Vue.js:前端框架
  • Element UI:组件库
  • Axios:HTTP 请求
  • Vuex:状态管理
  • Vue Router:路由管理

核心功能模块

1. 维修预约管理

  • 在线预约
  • 预约时间段管理
  • 预约状态跟踪
  • 短信通知提醒

2. 工单管理

  • 维修工单创建
  • 维修进度跟踪
  • 维修项目管理
  • 维修费用计算
  • 工单状态变更

3. 库存管理

  • 配件入库登记
  • 库存预警提醒
  • 配件使用记录
  • 库存盘点统计

4. 客户管理

  • 客户信息管理
  • 车辆信息管理
  • 维修记录查询
  • 会员积分管理

5. 员工管理

  • 员工信息管理
  • 工种分类管理
  • 工作量统计
  • 绩效考核

6. 财务管理

  • 收支明细记录
  • 营收报表统计
  • 成本分析
  • 利润核算

系统特点

  1. 全流程数字化
  • 从预约到结算的完整业务闭环
  • 减少人工操作环节
  • 提高工作效率
  1. 数据可视化
  • 直观的数据展示
  • 多维度统计分析
  • 辅助经营决策
  1. 用户体验
  • 简洁清晰的界面设计
  • 便捷的操作流程
  • 完善的提示信息
  1. 安全可靠
  • 严格的权限控制
  • 敏感数据加密
  • 操作日志记录

项目亮点

  1. 微服务架构
  • 模块解耦,独立部署
  • 服务高可用
  • 便于扩展维护
  1. 性能优化
  • Redis缓存机制
  • SQL语句优化
  • 前端资源压缩
  1. 工单智能派单
  • 考虑技师专长
  • 工作量均衡分配
  • 提高维修效率
  1. 数据分析功能
  • 客户消费分析
  • 配件使用分析
  • 维修项目分析
  • 营收趋势分析

项目收获

  1. 掌握了完整的Java全栈开发技术栈
  2. 深入理解了微服务架构设计思想
  3. 提升了项目开发和管理能力
  4. 积累了丰富的业务领域经验

项目展望

  1. 引入人工智能技术,实现故障智能诊断
  2. 开发移动端应用,提供更便捷的服务
  3. 对接物联网设备,实现智能化管理
  4. 扩展更多增值服务功能

总结

本项目采用主流的Java全栈技术,实现了汽修行业核心业务的信息化管理。通过该项目的开发,不仅提升了技术能力,也深入理解了业务需求分析和系统架构设计的重要性。项目具有较强的实用价值,为汽修企业提供了完善的管理解决方案。

维修预约管理模块的核心代码实现

1. 数据库设计

sql 复制代码
-- 预约表
CREATE TABLE appointment (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    customer_id BIGINT NOT NULL COMMENT '客户ID',
    vehicle_id BIGINT NOT NULL COMMENT '车辆ID',
    service_type VARCHAR(50) NOT NULL COMMENT '服务类型',
    appointment_time DATETIME NOT NULL COMMENT '预约时间',
    time_slot VARCHAR(20) NOT NULL COMMENT '预约时段',
    status VARCHAR(20) NOT NULL COMMENT '预约状态',
    description TEXT COMMENT '维修描述',
    contact_name VARCHAR(50) NOT NULL COMMENT '联系人',
    contact_phone VARCHAR(20) NOT NULL COMMENT '联系电话',
    photos TEXT COMMENT '车辆照片URLs',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES customer(id),
    FOREIGN KEY (vehicle_id) REFERENCES vehicle(id)
);

-- 预约时段配置表
CREATE TABLE time_slot_config (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    slot_time VARCHAR(20) NOT NULL COMMENT '时间段',
    max_capacity INT NOT NULL COMMENT '最大预约数',
    current_capacity INT NOT NULL DEFAULT 0 COMMENT '当前预约数',
    is_available BOOLEAN NOT NULL DEFAULT true COMMENT '是否可用',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 预约状态变更记录表
CREATE TABLE appointment_status_log (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    appointment_id BIGINT NOT NULL,
    old_status VARCHAR(20) COMMENT '原状态',
    new_status VARCHAR(20) NOT NULL COMMENT '新状态',
    operator_id BIGINT NOT NULL COMMENT '操作人',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (appointment_id) REFERENCES appointment(id)
);

2. 实体类设计

java 复制代码
@Data
@Entity
@Table(name = "appointment")
public class Appointment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private Long customerId;
    private Long vehicleId;
    private String serviceType;
    private LocalDateTime appointmentTime;
    private String timeSlot;
    
    @Enumerated(EnumType.STRING)
    private AppointmentStatus status;
    
    private String description;
    private String contactName;
    private String contactPhone;
    private String photos;
    private LocalDateTime createdTime;
    private LocalDateTime updatedTime;
}

@Data
@Entity
@Table(name = "time_slot_config")
public class TimeSlotConfig {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String slotTime;
    private Integer maxCapacity;
    private Integer currentCapacity;
    private Boolean isAvailable;
    private LocalDateTime createdTime;
    private LocalDateTime updatedTime;
}

3. 枚举定义

java 复制代码
public enum AppointmentStatus {
    PENDING("待确认"),
    CONFIRMED("已确认"),
    WAITING("待到店"),
    ARRIVED("已到店"),
    COMPLETED("已完成"),
    CANCELLED("已取消");
    
    private String description;
    
    AppointmentStatus(String description) {
        this.description = description;
    }
}

public enum ServiceType {
    REGULAR_MAINTENANCE("常规保养"),
    REPAIR("故障维修"),
    INSPECTION("年检服务"),
    CUSTOM("其他服务");
    
    private String description;
    
    ServiceType(String description) {
        this.description = description;
    }
}

4. DTO对象

java 复制代码
@Data
public class AppointmentDTO {
    private Long customerId;
    private Long vehicleId;
    private String serviceType;
    private String appointmentDate;
    private String timeSlot;
    private String description;
    private String contactName;
    private String contactPhone;
    private List<String> photos;
}

@Data
public class TimeSlotDTO {
    private String date;
    private List<TimeSlotInfo> availableSlots;
    
    @Data
    public static class TimeSlotInfo {
        private String slotTime;
        private Integer availableCapacity;
        private Boolean isAvailable;
    }
}

5. Service层实现

java 复制代码
@Service
@Transactional
public class AppointmentService {
    
    @Autowired
    private AppointmentRepository appointmentRepository;
    
    @Autowired
    private TimeSlotConfigRepository timeSlotConfigRepository;
    
    @Autowired
    private NotificationService notificationService;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    public AppointmentResponse createAppointment(AppointmentDTO dto) {
        // 1. 验证时间段是否可预约
        validateTimeSlot(dto.getAppointmentDate(), dto.getTimeSlot());
        
        // 2. 创建预约记录
        Appointment appointment = new Appointment();
        BeanUtils.copyProperties(dto, appointment);
        appointment.setStatus(AppointmentStatus.PENDING);
        
        // 3. 更新时间段容量
        updateTimeSlotCapacity(dto.getAppointmentDate(), dto.getTimeSlot());
        
        // 4. 保存预约信息
        appointment = appointmentRepository.save(appointment);
        
        // 5. 发送通知
        notificationService.sendAppointmentNotification(appointment);
        
        return buildResponse(appointment);
    }
    
    @Cacheable(value = "timeSlots", key = "#date")
    public List<TimeSlotDTO> getAvailableTimeSlots(String date) {
        List<TimeSlotConfig> configs = timeSlotConfigRepository.findByDateAndIsAvailable(date, true);
        return convertToDTO(configs);
    }
    
    public void updateAppointmentStatus(Long appointmentId, AppointmentStatus newStatus) {
        Appointment appointment = appointmentRepository.findById(appointmentId)
            .orElseThrow(() -> new BusinessException("预约不存在"));
            
        // 记录状态变更
        logStatusChange(appointment, newStatus);
        
        // 更新状态
        appointment.setStatus(newStatus);
        appointmentRepository.save(appointment);
        
        // 发送状态变更通知
        notificationService.sendStatusChangeNotification(appointment);
    }
    
    private void validateTimeSlot(String date, String timeSlot) {
        String cacheKey = "timeSlot:" + date + ":" + timeSlot;
        TimeSlotConfig config = (TimeSlotConfig) redisTemplate.opsForValue().get(cacheKey);
        
        if (config == null) {
            config = timeSlotConfigRepository.findByDateAndSlotTime(date, timeSlot)
                .orElseThrow(() -> new BusinessException("无效的时间段"));
        }
        
        if (!config.getIsAvailable() || config.getCurrentCapacity() >= config.getMaxCapacity()) {
            throw new BusinessException("该时间段已约满");
        }
    }
    
    private void updateTimeSlotCapacity(String date, String timeSlot) {
        timeSlotConfigRepository.incrementCurrentCapacity(date, timeSlot);
        // 更新缓存
        String cacheKey = "timeSlot:" + date + ":" + timeSlot;
        redisTemplate.delete(cacheKey);
    }
}

6. Controller层实现

java 复制代码
@RestController
@RequestMapping("/api/appointments")
public class AppointmentController {
    
    @Autowired
    private AppointmentService appointmentService;
    
    @PostMapping
    public Result<AppointmentResponse> createAppointment(@RequestBody @Valid AppointmentDTO dto) {
        try {
            AppointmentResponse response = appointmentService.createAppointment(dto);
            return Result.success(response);
        } catch (BusinessException e) {
            return Result.failure(e.getMessage());
        }
    }
    
    @GetMapping("/time-slots")
    public Result<List<TimeSlotDTO>> getAvailableTimeSlots(
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") String date) {
        List<TimeSlotDTO> slots = appointmentService.getAvailableTimeSlots(date);
        return Result.success(slots);
    }
    
    @PutMapping("/{id}/status")
    public Result<Void> updateStatus(
            @PathVariable Long id,
            @RequestParam AppointmentStatus status) {
        appointmentService.updateAppointmentStatus(id, status);
        return Result.success();
    }
    
    @GetMapping("/{id}")
    public Result<AppointmentResponse> getAppointment(@PathVariable Long id) {
        AppointmentResponse appointment = appointmentService.getAppointmentById(id);
        return Result.success(appointment);
    }
}

7. 通知服务实现

java 复制代码
@Service
public class NotificationService {
    
    @Autowired
    private SMSProvider smsProvider;
    
    @Autowired
    private NotificationTemplateService templateService;
    
    @Async
    public void sendAppointmentNotification(Appointment appointment) {
        try {
            String template = templateService.getTemplate("APPOINTMENT_CREATED");
            String content = buildNotificationContent(template, appointment);
            
            SMSRequest request = SMSRequest.builder()
                .mobile(appointment.getContactPhone())
                .content(content)
                .build();
                
            smsProvider.send(request);
        } catch (Exception e) {
            log.error("发送预约通知失败", e);
            // 添加重试机制
            retryNotification(appointment);
        }
    }
    
    @Async
    public void sendStatusChangeNotification(Appointment appointment) {
        String template = templateService.getTemplate("STATUS_CHANGED");
        String content = buildNotificationContent(template, appointment);
        
        SMSRequest request = SMSRequest.builder()
            .mobile(appointment.getContactPhone())
            .content(content)
            .build();
            
        smsProvider.send(request);
    }
    
    private void retryNotification(Appointment appointment) {
        // 使用重试策略(如:exponential backoff)
    }
}

8. 缓存配置

java 复制代码
@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        
        // 设置key的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        
        // 设置value的序列化方式
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        template.setValueSerializer(serializer);
        
        return template;
    }
    
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofHours(1))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
            
        return RedisCacheManager.builder(factory)
            .cacheDefaults(config)
            .build();
    }
}

9. 异常处理

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        return Result.failure(e.getMessage());
    }
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleValidationException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
            .map(FieldError::getDefaultMessage)
            .collect(Collectors.joining(", "));
        return Result.failure(message);
    }
    
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return Result.failure("系统繁忙,请稍后重试");
    }
}

这些代码实现了预约管理的核心功能,包括:

  1. 预约创建和管理
  2. 时间段容量控制
  3. 状态跟踪和变更
  4. 短信通知
  5. 缓存优化
  6. 异常处理

关键特点:

  • 使用Redis缓存热点数据(时间段信息)
  • 异步处理通知发送
  • 完善的异常处理机制
  • 状态变更日志记录
  • 预约容量控制

工单管理模块的核心代码实现

1. 数据库设计

sql 复制代码
-- 工单主表
CREATE TABLE work_order (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    order_no VARCHAR(32) UNIQUE NOT NULL COMMENT '工单编号',
    appointment_id BIGINT COMMENT '关联预约ID',
    customer_id BIGINT NOT NULL COMMENT '客户ID',
    vehicle_id BIGINT NOT NULL COMMENT '车辆ID',
    technician_id BIGINT COMMENT '主责技师ID',
    status VARCHAR(20) NOT NULL COMMENT '工单状态',
    estimated_completion_time DATETIME COMMENT '预计完工时间',
    actual_completion_time DATETIME COMMENT '实际完工时间',
    total_amount DECIMAL(10,2) DEFAULT 0 COMMENT '总金额',
    labor_cost DECIMAL(10,2) DEFAULT 0 COMMENT '工时费',
    parts_cost DECIMAL(10,2) DEFAULT 0 COMMENT '配件费',
    description TEXT COMMENT '维修描述',
    diagnosis_result TEXT COMMENT '检查结果',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 工单项目明细表
CREATE TABLE work_order_item (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    work_order_id BIGINT NOT NULL COMMENT '工单ID',
    service_item_id BIGINT NOT NULL COMMENT '服务项目ID',
    technician_id BIGINT COMMENT '技师ID',
    status VARCHAR(20) NOT NULL COMMENT '项目状态',
    estimated_hours DECIMAL(4,1) COMMENT '预计工时',
    actual_hours DECIMAL(4,1) COMMENT '实际工时',
    amount DECIMAL(10,2) COMMENT '项目金额',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (work_order_id) REFERENCES work_order(id)
);

-- 工单配件使用记录表
CREATE TABLE work_order_part (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    work_order_id BIGINT NOT NULL COMMENT '工单ID',
    part_id BIGINT NOT NULL COMMENT '配件ID',
    quantity INT NOT NULL COMMENT '使用数量',
    unit_price DECIMAL(10,2) NOT NULL COMMENT '单价',
    amount DECIMAL(10,2) NOT NULL COMMENT '金额',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (work_order_id) REFERENCES work_order(id)
);

-- 工单进度记录表
CREATE TABLE work_order_progress (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    work_order_id BIGINT NOT NULL COMMENT '工单ID',
    status VARCHAR(20) NOT NULL COMMENT '状态',
    operator_id BIGINT NOT NULL COMMENT '操作人',
    remark TEXT COMMENT '备注',
    photos TEXT COMMENT '照片URLs',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (work_order_id) REFERENCES work_order(id)
);

2. 实体类设计

java 复制代码
@Data
@Entity
@Table(name = "work_order")
public class WorkOrder {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String orderNo;
    private Long appointmentId;
    private Long customerId;
    private Long vehicleId;
    private Long technicianId;
    
    @Enumerated(EnumType.STRING)
    private WorkOrderStatus status;
    
    private LocalDateTime estimatedCompletionTime;
    private LocalDateTime actualCompletionTime;
    private BigDecimal totalAmount;
    private BigDecimal laborCost;
    private BigDecimal partsCost;
    private String description;
    private String diagnosisResult;
    
    @OneToMany(mappedBy = "workOrder", cascade = CascadeType.ALL)
    private List<WorkOrderItem> items;
    
    @OneToMany(mappedBy = "workOrder", cascade = CascadeType.ALL)
    private List<WorkOrderPart> parts;
}

@Data
@Entity
@Table(name = "work_order_item")
public class WorkOrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "work_order_id")
    private WorkOrder workOrder;
    
    private Long serviceItemId;
    private Long technicianId;
    
    @Enumerated(EnumType.STRING)
    private ItemStatus status;
    
    private BigDecimal estimatedHours;
    private BigDecimal actualHours;
    private BigDecimal amount;
    private String remark;
}

3. 枚举定义

java 复制代码
public enum WorkOrderStatus {
    CREATED("已创建"),
    INSPECTING("检查中"),
    REPAIRING("维修中"),
    QUALITY_CHECK("质检中"),
    COMPLETED("已完成"),
    CANCELLED("已取消");
    
    private String description;
    
    WorkOrderStatus(String description) {
        this.description = description;
    }
}

public enum ItemStatus {
    PENDING("待处理"),
    IN_PROGRESS("进行中"),
    COMPLETED("已完成"),
    CANCELLED("已取消");
    
    private String description;
}

4. Service层实现

java 复制代码
@Service
@Transactional
public class WorkOrderService {
    
    @Autowired
    private WorkOrderRepository workOrderRepository;
    
    @Autowired
    private WorkOrderItemRepository itemRepository;
    
    @Autowired
    private PartInventoryService partInventoryService;
    
    @Autowired
    private NotificationService notificationService;
    
    public WorkOrderResponse createWorkOrder(WorkOrderDTO dto) {
        // 1. 生成工单编号
        String orderNo = generateOrderNo();
        
        // 2. 创建工单
        WorkOrder workOrder = new WorkOrder();
        BeanUtils.copyProperties(dto, workOrder);
        workOrder.setOrderNo(orderNo);
        workOrder.setStatus(WorkOrderStatus.CREATED);
        
        // 3. 创建工单项目
        List<WorkOrderItem> items = createWorkOrderItems(dto.getItems(), workOrder);
        workOrder.setItems(items);
        
        // 4. 计算预估金额
        calculateEstimatedAmount(workOrder);
        
        // 5. 保存工单
        workOrder = workOrderRepository.save(workOrder);
        
        // 6. 发送通知
        notificationService.sendWorkOrderCreatedNotification(workOrder);
        
        return buildResponse(workOrder);
    }
    
    public void updateWorkOrderStatus(Long id, WorkOrderStatus newStatus, String remark) {
        WorkOrder workOrder = workOrderRepository.findById(id)
            .orElseThrow(() -> new BusinessException("工单不存在"));
            
        // 1. 验证状态变更是否合法
        validateStatusTransition(workOrder.getStatus(), newStatus);
        
        // 2. 更新状态
        workOrder.setStatus(newStatus);
        
        // 3. 记录进度
        saveProgress(workOrder, newStatus, remark);
        
        // 4. 特殊状态处理
        handleSpecialStatus(workOrder, newStatus);
        
        // 5. 保存更新
        workOrderRepository.save(workOrder);
        
        // 6. 发送通知
        notificationService.sendStatusChangeNotification(workOrder);
    }
    
    public void addWorkOrderPart(Long workOrderId, WorkOrderPartDTO dto) {
        WorkOrder workOrder = workOrderRepository.findById(workOrderId)
            .orElseThrow(() -> new BusinessException("工单不存在"));
            
        // 1. 检查库存
        partInventoryService.checkInventory(dto.getPartId(), dto.getQuantity());
        
        // 2. 创建配件使用记录
        WorkOrderPart part = new WorkOrderPart();
        BeanUtils.copyProperties(dto, part);
        part.setWorkOrder(workOrder);
        
        // 3. 计算金额
        calculatePartAmount(part);
        
        // 4. 更新工单金额
        updateWorkOrderAmount(workOrder, part.getAmount());
        
        // 5. 扣减库存
        partInventoryService.deductInventory(dto.getPartId(), dto.getQuantity());
        
        // 6. 保存记录
        workOrderPartRepository.save(part);
    }
    
    public void updateWorkOrderProgress(Long id, ProgressUpdateDTO dto) {
        WorkOrder workOrder = workOrderRepository.findById(id)
            .orElseThrow(() -> new BusinessException("工单不存在"));
            
        // 1. 更新项目进度
        updateItemsProgress(workOrder, dto.getItemProgresses());
        
        // 2. 更新工时
        updateLaborHours(workOrder, dto.getItemProgresses());
        
        // 3. 重新计算费用
        recalculateAmount(workOrder);
        
        // 4. 保存更新
        workOrderRepository.save(workOrder);
        
        // 5. 记录进度
        saveProgress(workOrder, dto.getRemark(), dto.getPhotos());
    }
    
    private void calculateEstimatedAmount(WorkOrder workOrder) {
        BigDecimal laborCost = calculateLaborCost(workOrder.getItems());
        BigDecimal partsCost = calculatePartsCost(workOrder.getParts());
        workOrder.setLaborCost(laborCost);
        workOrder.setPartsCost(partsCost);
        workOrder.setTotalAmount(laborCost.add(partsCost));
    }
    
    private void handleSpecialStatus(WorkOrder workOrder, WorkOrderStatus status) {
        switch (status) {
            case COMPLETED:
                workOrder.setActualCompletionTime(LocalDateTime.now());
                break;
            case QUALITY_CHECK:
                validateAllItemsCompleted(workOrder);
                break;
        }
    }
}

5. Controller层实现

java 复制代码
@RestController
@RequestMapping("/api/work-orders")
public class WorkOrderController {
    
    @Autowired
    private WorkOrderService workOrderService;
    
    @PostMapping
    public Result<WorkOrderResponse> createWorkOrder(@RequestBody @Valid WorkOrderDTO dto) {
        WorkOrderResponse response = workOrderService.createWorkOrder(dto);
        return Result.success(response);
    }
    
    @PutMapping("/{id}/status")
    public Result<Void> updateStatus(
            @PathVariable Long id,
            @RequestParam WorkOrderStatus status,
            @RequestParam(required = false) String remark) {
        workOrderService.updateWorkOrderStatus(id, status, remark);
        return Result.success();
    }
    
    @PostMapping("/{id}/parts")
    public Result<Void> addPart(
            @PathVariable Long id,
            @RequestBody @Valid WorkOrderPartDTO dto) {
        workOrderService.addWorkOrderPart(id, dto);
        return Result.success();
    }
    
    @PutMapping("/{id}/progress")
    public Result<Void> updateProgress(
            @PathVariable Long id,
            @RequestBody @Valid ProgressUpdateDTO dto) {
        workOrderService.updateWorkOrderProgress(id, dto);
        return Result.success();
    }
    
    @GetMapping("/{id}")
    public Result<WorkOrderDetailResponse> getWorkOrder(@PathVariable Long id) {
        WorkOrderDetailResponse detail = workOrderService.getWorkOrderDetail(id);
        return Result.success(detail);
    }
}

6. 费用计算服务

java 复制代码
@Service
public class CostCalculationService {
    
    @Autowired
    private ServiceItemRepository serviceItemRepository;
    
    @Autowired
    private PartRepository partRepository;
    
    public BigDecimal calculateLaborCost(List<WorkOrderItem> items) {
        return items.stream()
            .map(this::calculateItemLaborCost)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    public BigDecimal calculatePartsCost(List<WorkOrderPart> parts) {
        return parts.stream()
            .map(this::calculatePartCost)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    private BigDecimal calculateItemLaborCost(WorkOrderItem item) {
        ServiceItem serviceItem = serviceItemRepository.findById(item.getServiceItemId())
            .orElseThrow(() -> new BusinessException("服务项目不存在"));
            
        return serviceItem.getHourlyRate()
            .multiply(item.getActualHours() != null ? 
                item.getActualHours() : item.getEstimatedHours());
    }
    
    private BigDecimal calculatePartCost(WorkOrderPart part) {
        return part.getUnitPrice().multiply(BigDecimal.valueOf(part.getQuantity()));
    }
}

7. 状态机实现

java 复制代码
@Component
public class WorkOrderStateMachine {
    
    private static final Map<WorkOrderStatus, Set<WorkOrderStatus>> VALID_TRANSITIONS;
    
    static {
        VALID_TRANSITIONS = new HashMap<>();
        VALID_TRANSITIONS.put(WorkOrderStatus.CREATED, 
            Set.of(WorkOrderStatus.INSPECTING, WorkOrderStatus.CANCELLED));
        VALID_TRANSITIONS.put(WorkOrderStatus.INSPECTING, 
            Set.of(WorkOrderStatus.REPAIRING, WorkOrderStatus.CANCELLED));
        VALID_TRANSITIONS.put(WorkOrderStatus.REPAIRING, 
            Set.of(WorkOrderStatus.QUALITY_CHECK, WorkOrderStatus.CANCELLED));
        VALID_TRANSITIONS.put(WorkOrderStatus.QUALITY_CHECK, 
            Set.of(WorkOrderStatus.COMPLETED, WorkOrderStatus.REPAIRING));
    }
    
    public boolean canTransit(WorkOrderStatus current, WorkOrderStatus target) {
        Set<WorkOrderStatus> validTargets = VALID_TRANSITIONS.get(current);
        return validTargets != null && validTargets.contains(target);
    }
    
    public void validateTransition(WorkOrderStatus current, WorkOrderStatus target) {
        if (!canTransit(current, target)) {
            throw new BusinessException(
                String.format("不允许从%s状态变更为%s状态", 
                    current.getDescription(), 
                    target.getDescription())
            );
        }
    }
}

8. 进度跟踪实现

java 复制代码
@Service
public class ProgressTrackingService {
    
    @Autowired
    private WorkOrderProgressRepository progressRepository;
    
    @Autowired
    private FileService fileService;
    
    public void saveProgress(WorkOrder workOrder, String remark, List<MultipartFile> photos) {
        // 1. 保存照片
        List<String> photoUrls = new ArrayList<>();
        if (photos != null && !photos.isEmpty()) {
            photoUrls = photos.stream()
                .map(photo -> fileService.uploadFile(photo))
                .collect(Collectors.toList());
        }
        
        // 2. 创建进度记录
        WorkOrderProgress progress = new WorkOrderProgress();
        progress.setWorkOrderId(workOrder.getId());
        progress.setStatus(workOrder.getStatus());
        progress.setRemark(remark);
        progress.setPhotos(String.join(",", photoUrls));
        progress.setOperatorId(SecurityUtils.getCurrentUserId());
        
        // 3. 保存记录
        progressRepository.save(progress);
    }
    
    public List<ProgressResponse> getProgressHistory(Long workOrderId) {
        List<WorkOrderProgress> progressList = progressRepository
            .findByWorkOrderIdOrderByCreatedTimeDesc(workOrderId);
            
        return progressList.stream()
            .map(this::convertToResponse)
            .collect(Collectors.toList());
    }
    
    private ProgressResponse convertToResponse(WorkOrderProgress progress) {
        ProgressResponse response = new ProgressResponse();
        BeanUtils.copyProperties(progress, response);
        
        // 设置操作人信息
        User operator = userService.getUser(progress.getOperatorId());
        response.setOperatorName(operator.getName());
        
        // 处理照片URL
        if (StringUtils.hasText(progress.getPhotos())) {
            response.setPhotoUrls(Arrays.asList(progress.getPhotos().split(",")));
        }
        
        return response;
    }
}

9. 工单查询服务

java 复制代码
@Service
public class WorkOrderQueryService {
    
    @Autowired
    private WorkOrderRepository workOrderRepository;
    
    public Page<WorkOrderResponse> queryWorkOrders(WorkOrderQueryDTO query) {
        // 1. 构建查询条件
        Specification<WorkOrder> spec = buildSpecification(query);
        
        // 2. 创建分页对象
        PageRequest pageRequest = PageRequest.of(
            query.getPageNum(), 
            query.getPageSize(),
            Sort.by(Sort.Direction.DESC, "createdTime")
        );
        
        // 3. 执行查询
        Page<WorkOrder> page = workOrderRepository.findAll(spec, pageRequest);
        
        // 4. 转换响应
        return page.map(this::convertToResponse);
    }
    
    private Specification<WorkOrder> buildSpecification(WorkOrderQueryDTO query) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 工单号
            if (StringUtils.hasText(query.getOrderNo())) {
                predicates.add(criteriaBuilder.like(
                    root.get("orderNo"), 
                    "%" + query.getOrderNo() + "%"
                ));
            }
            
            // 状态
            if (query.getStatus() != null) {
                predicates.add(criteriaBuilder.equal(
                    root.get("status"), 
                    query.getStatus()
                ));
            }
            
            // 时间范围
            if (query.getStartTime() != null) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(
                    root.get("createdTime"), 
                    query.getStartTime()
                ));
            }
            
            if (query.getEndTime() != null) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(
                    root.get("createdTime"), 
                    query.getEndTime()
                ));
            }
            
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
    }
}

这些代码实现了工单管理的核心功能,包括:

  1. 工单创建和管理
  2. 维修项目跟踪
  3. 配件使用管理
  4. 费用计算
  5. 状态流转控制
  6. 进度记录跟踪

关键特点:

  • 完整的状态机实现
  • 细粒度的费用计算
  • 详细的进度跟踪
  • 灵活的查询功能
  • 完善的数据验证

库存管理模块的核心代码实现

1. 数据库设计

sql 复制代码
-- 配件信息表
CREATE TABLE part (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    code VARCHAR(32) UNIQUE NOT NULL COMMENT '配件编号',
    name VARCHAR(100) NOT NULL COMMENT '配件名称',
    category_id BIGINT NOT NULL COMMENT '分类ID',
    brand VARCHAR(50) COMMENT '品牌',
    model VARCHAR(50) COMMENT '型号',
    unit VARCHAR(20) NOT NULL COMMENT '单位',
    price DECIMAL(10,2) NOT NULL COMMENT '单价',
    min_stock INT NOT NULL COMMENT '最低库存',
    max_stock INT NOT NULL COMMENT '最高库存',
    shelf_life INT COMMENT '保质期(天)',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态: 0-停用 1-启用',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 库存记录表
CREATE TABLE inventory (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    part_id BIGINT NOT NULL COMMENT '配件ID',
    warehouse_id BIGINT NOT NULL COMMENT '仓库ID',
    quantity INT NOT NULL DEFAULT 0 COMMENT '当前库存量',
    locked_quantity INT NOT NULL DEFAULT 0 COMMENT '锁定数量',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY `uk_part_warehouse` (`part_id`, `warehouse_id`)
);

-- 入库记录表
CREATE TABLE stock_in (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    order_no VARCHAR(32) UNIQUE NOT NULL COMMENT '入库单号',
    warehouse_id BIGINT NOT NULL COMMENT '仓库ID',
    supplier_id BIGINT NOT NULL COMMENT '供应商ID',
    type VARCHAR(20) NOT NULL COMMENT '入库类型',
    status VARCHAR(20) NOT NULL COMMENT '状态',
    total_amount DECIMAL(10,2) NOT NULL COMMENT '总金额',
    operator_id BIGINT NOT NULL COMMENT '操作人',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 入库明细表
CREATE TABLE stock_in_item (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    stock_in_id BIGINT NOT NULL COMMENT '入库单ID',
    part_id BIGINT NOT NULL COMMENT '配件ID',
    quantity INT NOT NULL COMMENT '数量',
    unit_price DECIMAL(10,2) NOT NULL COMMENT '单价',
    amount DECIMAL(10,2) NOT NULL COMMENT '金额',
    batch_no VARCHAR(50) COMMENT '批次号',
    production_date DATE COMMENT '生产日期',
    expiry_date DATE COMMENT '过期日期',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (stock_in_id) REFERENCES stock_in(id)
);

-- 库存变动记录表
CREATE TABLE inventory_transaction (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    part_id BIGINT NOT NULL COMMENT '配件ID',
    warehouse_id BIGINT NOT NULL COMMENT '仓库ID',
    type VARCHAR(20) NOT NULL COMMENT '变动类型',
    quantity INT NOT NULL COMMENT '变动数量',
    before_quantity INT NOT NULL COMMENT '变动前数量',
    after_quantity INT NOT NULL COMMENT '变动后数量',
    reference_no VARCHAR(32) COMMENT '关联单号',
    operator_id BIGINT NOT NULL COMMENT '操作人',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 库存盘点表
CREATE TABLE inventory_check (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    check_no VARCHAR(32) UNIQUE NOT NULL COMMENT '盘点单号',
    warehouse_id BIGINT NOT NULL COMMENT '仓库ID',
    status VARCHAR(20) NOT NULL COMMENT '状态',
    start_time DATETIME NOT NULL COMMENT '开始时间',
    end_time DATETIME COMMENT '结束时间',
    operator_id BIGINT NOT NULL COMMENT '操作人',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 盘点明细表
CREATE TABLE inventory_check_item (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    check_id BIGINT NOT NULL COMMENT '盘点单ID',
    part_id BIGINT NOT NULL COMMENT '配件ID',
    system_quantity INT NOT NULL COMMENT '系统数量',
    actual_quantity INT NOT NULL COMMENT '实际数量',
    difference INT NOT NULL COMMENT '差异数量',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (check_id) REFERENCES inventory_check(id)
);

2. 实体类设计

java 复制代码
@Data
@Entity
@Table(name = "part")
public class Part {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String code;
    private String name;
    private Long categoryId;
    private String brand;
    private String model;
    private String unit;
    private BigDecimal price;
    private Integer minStock;
    private Integer maxStock;
    private Integer shelfLife;
    private Integer status;
    private String remark;
    private LocalDateTime createdTime;
    private LocalDateTime updatedTime;
}

@Data
@Entity
@Table(name = "inventory")
public class Inventory {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private Long partId;
    private Long warehouseId;
    private Integer quantity;
    private Integer lockedQuantity;
    private LocalDateTime createdTime;
    private LocalDateTime updatedTime;
    
    @Version
    private Integer version;  // 乐观锁版本号
}

@Data
@Entity
@Table(name = "stock_in")
public class StockIn {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String orderNo;
    private Long warehouseId;
    private Long supplierId;
    
    @Enumerated(EnumType.STRING)
    private StockInType type;
    
    @Enumerated(EnumType.STRING)
    private StockInStatus status;
    
    private BigDecimal totalAmount;
    private Long operatorId;
    private String remark;
    private LocalDateTime createdTime;
    
    @OneToMany(mappedBy = "stockIn", cascade = CascadeType.ALL)
    private List<StockInItem> items;
}

3. 入库服务实现

java 复制代码
@Service
@Transactional
public class StockInService {
    
    @Autowired
    private StockInRepository stockInRepository;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Autowired
    private SequenceGenerator sequenceGenerator;
    
    public StockInResponse createStockIn(StockInDTO dto) {
        // 1. 生成入库单号
        String orderNo = sequenceGenerator.generateStockInNo();
        
        // 2. 创建入库单
        StockIn stockIn = new StockIn();
        BeanUtils.copyProperties(dto, stockIn);
        stockIn.setOrderNo(orderNo);
        stockIn.setStatus(StockInStatus.PENDING);
        
        // 3. 创建入库明细
        List<StockInItem> items = createStockInItems(dto.getItems(), stockIn);
        stockIn.setItems(items);
        
        // 4. 计算总金额
        BigDecimal totalAmount = calculateTotalAmount(items);
        stockIn.setTotalAmount(totalAmount);
        
        // 5. 保存入库单
        stockIn = stockInRepository.save(stockIn);
        
        return buildResponse(stockIn);
    }
    
    public void confirmStockIn(Long id) {
        StockIn stockIn = stockInRepository.findById(id)
            .orElseThrow(() -> new BusinessException("入库单不存在"));
            
        // 1. 验证状态
        if (stockIn.getStatus() != StockInStatus.PENDING) {
            throw new BusinessException("入库单状态不正确");
        }
        
        // 2. 更新库存
        for (StockInItem item : stockIn.getItems()) {
            inventoryService.increaseStock(
                item.getPartId(),
                stockIn.getWarehouseId(),
                item.getQuantity(),
                stockIn.getOrderNo()
            );
        }
        
        // 3. 更新入库单状态
        stockIn.setStatus(StockInStatus.COMPLETED);
        stockInRepository.save(stockIn);
    }
}

4. 库存服务实现

java 复制代码
@Service
@Transactional
public class InventoryService {
    
    @Autowired
    private InventoryRepository inventoryRepository;
    
    @Autowired
    private InventoryTransactionRepository transactionRepository;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    public void increaseStock(Long partId, Long warehouseId, Integer quantity, String referenceNo) {
        // 1. 获取或创建库存记录
        Inventory inventory = getOrCreateInventory(partId, warehouseId);
        
        // 2. 更新库存(使用乐观锁)
        int retryCount = 0;
        while (retryCount < 3) {
            try {
                inventory.setQuantity(inventory.getQuantity() + quantity);
                inventoryRepository.save(inventory);
                break;
            } catch (OptimisticLockingFailureException e) {
                if (++retryCount == 3) {
                    throw new BusinessException("更新库存失败,请重试");
                }
                inventory = inventoryRepository.findByPartIdAndWarehouseId(partId, warehouseId)
                    .orElseThrow();
            }
        }
        
        // 3. 记录库存变动
        saveInventoryTransaction(
            inventory, 
            TransactionType.STOCK_IN, 
            quantity, 
            referenceNo
        );
        
        // 4. 检查库存预警
        checkStockWarning(inventory);
    }
    
    public void decreaseStock(Long partId, Long warehouseId, Integer quantity, String referenceNo) {
        // 1. 获取库存记录
        Inventory inventory = inventoryRepository.findByPartIdAndWarehouseId(partId, warehouseId)
            .orElseThrow(() -> new BusinessException("库存记录不存在"));
            
        // 2. 检查库存是否足够
        if (inventory.getQuantity() - inventory.getLockedQuantity() < quantity) {
            throw new BusinessException("可用库存不足");
        }
        
        // 3. 更新库存(使用乐观锁)
        int retryCount = 0;
        while (retryCount < 3) {
            try {
                inventory.setQuantity(inventory.getQuantity() - quantity);
                inventoryRepository.save(inventory);
                break;
            } catch (OptimisticLockingFailureException e) {
                if (++retryCount == 3) {
                    throw new BusinessException("更新库存失败,请重试");
                }
                inventory = inventoryRepository.findByPartIdAndWarehouseId(partId, warehouseId)
                    .orElseThrow();
            }
        }
        
        // 4. 记录库存变动
        saveInventoryTransaction(
            inventory, 
            TransactionType.STOCK_OUT, 
            -quantity, 
            referenceNo
        );
        
        // 5. 检查库存预警
        checkStockWarning(inventory);
    }
    
    private void checkStockWarning(Inventory inventory) {
        Part part = partRepository.findById(inventory.getPartId())
            .orElseThrow();
            
        // 检查是否低于最低库存
        if (inventory.getQuantity() <= part.getMinStock()) {
            // 发送库存预警
            sendStockWarning(inventory, part);
            
            // 缓存预警信息
            cacheStockWarning(inventory, part);
        }
    }
}

5. 库存盘点服务实现

java 复制代码
@Service
@Transactional
public class InventoryCheckService {
    
    @Autowired
    private InventoryCheckRepository checkRepository;
    
    @Autowired
    private InventoryService inventoryService;
    
    public InventoryCheckResponse createCheck(InventoryCheckDTO dto) {
        // 1. 生成盘点单号
        String checkNo = sequenceGenerator.generateCheckNo();
        
        // 2. 创建盘点单
        InventoryCheck check = new InventoryCheck();
        BeanUtils.copyProperties(dto, check);
        check.setCheckNo(checkNo);
        check.setStatus(CheckStatus.IN_PROGRESS);
        check.setStartTime(LocalDateTime.now());
        
        // 3. 获取系统库存数据
        List<InventoryCheckItem> items = generateCheckItems(dto.getWarehouseId());
        check.setItems(items);
        
        // 4. 保存盘点单
        check = checkRepository.save(check);
        
        return buildResponse(check);
    }
    
    public void completeCheck(Long id, List<CheckItemDTO> items) {
        InventoryCheck check = checkRepository.findById(id)
            .orElseThrow(() -> new BusinessException("盘点单不存在"));
            
        // 1. 验证状态
        if (check.getStatus() != CheckStatus.IN_PROGRESS) {
            throw new BusinessException("盘点单状态不正确");
        }
        
        // 2. 更新盘点结果
        updateCheckItems(check, items);
        
        // 3. 处理盘盈盘亏
        handleInventoryDifference(check);
        
        // 4. 完成盘点
        check.setStatus(CheckStatus.COMPLETED);
        check.setEndTime(LocalDateTime.now());
        checkRepository.save(check);
    }
    
    private void handleInventoryDifference(InventoryCheck check) {
        for (InventoryCheckItem item : check.getItems()) {
            if (item.getDifference() != 0) {
                // 记录库存调整
                inventoryService.adjustStock(
                    item.getPartId(),
                    check.getWarehouseId(),
                    item.getDifference(),
                    check.getCheckNo()
                );
            }
        }
    }
}

6. 库存预警服务实现

java 复制代码
@Service
public class StockWarningService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private NotificationService notificationService;
    
    private static final String WARNING_KEY_PREFIX = "stock:warning:";
    
    public void sendStockWarning(Inventory inventory, Part part) {
        StockWarningMessage message = StockWarningMessage.builder()
            .partCode(part.getCode())
            .partName(part.getName())
            .currentStock(inventory.getQuantity())
            .minStock(part.getMinStock())
            .warehouseId(inventory.getWarehouseId())
            .build();
            
        // 1. 发送消息通知
        notificationService.sendStockWarning(message);
        
        // 2. 缓存预警信息
        cacheWarningInfo(inventory.getPartId(), message);
    }
    
    public List<StockWarningMessage> getWarningList() {
        Set<String> keys = redisTemplate.keys(WARNING_KEY_PREFIX + "*");
        if (keys == null || keys.isEmpty()) {
            return Collections.emptyList();
        }
        
        return keys.stream()
            .map(key -> (StockWarningMessage) redisTemplate.opsForValue().get(key))
            .collect(Collectors.toList());
    }
    
    private void cacheWarningInfo(Long partId, StockWarningMessage message) {
        String key = WARNING_KEY_PREFIX + partId;
        redisTemplate.opsForValue().set(key, message, 24, TimeUnit.HOURS);
    }
}

7. 库存统计服务实现

java 复制代码
@Service
public class InventoryStatisticsService {
    
    @Autowired
    private InventoryRepository inventoryRepository;
    
    @Autowired
    private InventoryTransactionRepository transactionRepository;
    
    public InventoryStatisticsResponse getStatistics(StatisticsQueryDTO query) {
        // 1. 库存总量统计
        InventoryTotalVO total = calculateInventoryTotal(query);
        
        // 2. 库存金额统计
        InventoryAmountVO amount = calculateInventoryAmount(query);
        
        // 3. 库存周转率统计
        TurnoverRateVO turnover = calculateTurnoverRate(query);
        
        // 4. 库存预警统计
        WarningStatisticsVO warning = calculateWarningStatistics(query);
        
        return InventoryStatisticsResponse.builder()
            .total(total)
            .amount(amount)
            .turnover(turnover)
            .warning(warning)
            .build();
    }
    
    public List<InventoryTransactionVO> getTransactionHistory(
            Long partId, LocalDateTime startTime, LocalDateTime endTime) {
        List<InventoryTransaction> transactions = 
            transactionRepository.findByPartIdAndCreatedTimeBetween(
                partId, startTime, endTime);
                
        return transactions.stream()
            .map(this::convertToVO)
            .collect(Collectors.toList());
    }
    
    private TurnoverRateVO calculateTurnoverRate(StatisticsQueryDTO query) {
        // 1. 获取期初库存
        BigDecimal beginningInventory = getBeginningInventory(query);
        
        // 2. 获取期末库存
        BigDecimal endingInventory = getEndingInventory(query);
        
        // 3. 获取期间出库数量
        BigDecimal outboundQuantity = getOutboundQuantity(query);
        
        // 4. 计算平均库存
        BigDecimal averageInventory = beginningInventory.add(endingInventory)
            .divide(BigDecimal.valueOf(2), 2, RoundingMode.HALF_UP);
            
        // 5. 计算周转率
        BigDecimal turnoverRate = BigDecimal.ZERO;
        if (averageInventory.compareTo(BigDecimal.ZERO) > 0) {
            turnoverRate = outboundQuantity.divide(averageInventory, 2, RoundingMode.HALF_UP);
        }
        
        return new TurnoverRateVO(turnoverRate);
    }
}

8. 库存查询接口实现

java 复制代码
@RestController
@RequestMapping("/api/inventory")
public class InventoryController {
    
    @Autowired
    private InventoryService inventoryService;
    
    @Autowired
    private InventoryStatisticsService statisticsService;
    
    @GetMapping("/stock")
    public Result<Page<InventoryVO>> queryStock(InventoryQueryDTO query) {
        Page<InventoryVO> page = inventoryService.queryStock(query);
        return Result.success(page);
    }
    
    @GetMapping("/warning")
    public Result<List<StockWarningMessage>> getWarningList() {
        List<StockWarningMessage> warnings = inventoryService.getWarningList();
        return Result.success(warnings);
    }
    
    @GetMapping("/statistics")
    public Result<InventoryStatisticsResponse> getStatistics(StatisticsQueryDTO query) {
        InventoryStatisticsResponse statistics = statisticsService.getStatistics(query);
        return Result.success(statistics);
    }
    
    @GetMapping("/transaction-history")
    public Result<List<InventoryTransactionVO>> getTransactionHistory(
            @RequestParam Long partId,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
        List<InventoryTransactionVO> history = 
            statisticsService.getTransactionHistory(partId, startTime, endTime);
        return Result.success(history);
    }
}

这些代码实现了库存管理的核心功能,包括:

  1. 配件入库管理
  2. 库存变动控制
  3. 库存预警机制
  4. 库存盘点处理
  5. 库存统计分析

关键特点:

  • 使用乐观锁控制并发
  • Redis缓存预警信息
  • 完整的库存变动追踪
  • 详细的统计分析功能
  • 支持库存盘点处理

客户管理模块的核心代码实现

1. 数据库设计

sql 复制代码
-- 客户信息表
CREATE TABLE customer (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    code VARCHAR(32) UNIQUE NOT NULL COMMENT '客户编号',
    name VARCHAR(100) NOT NULL COMMENT '客户姓名',
    phone VARCHAR(20) NOT NULL COMMENT '联系电话',
    id_card VARCHAR(18) COMMENT '身份证号',
    gender TINYINT COMMENT '性别: 0-女 1-男',
    birthday DATE COMMENT '生日',
    email VARCHAR(100) COMMENT '邮箱',
    address TEXT COMMENT '地址',
    source VARCHAR(50) COMMENT '客户来源',
    level VARCHAR(20) NOT NULL DEFAULT 'NORMAL' COMMENT '客户等级',
    points INT NOT NULL DEFAULT 0 COMMENT '积分',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态: 0-禁用 1-启用',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 车辆信息表
CREATE TABLE vehicle (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    customer_id BIGINT NOT NULL COMMENT '客户ID',
    plate_number VARCHAR(20) NOT NULL COMMENT '车牌号',
    brand VARCHAR(50) NOT NULL COMMENT '品牌',
    model VARCHAR(50) NOT NULL COMMENT '型号',
    vin VARCHAR(50) UNIQUE COMMENT '车架号',
    engine_number VARCHAR(50) COMMENT '发动机号',
    color VARCHAR(20) COMMENT '颜色',
    mileage INT COMMENT '行驶里程',
    purchase_date DATE COMMENT '购买日期',
    insurance_expiry DATE COMMENT '保险到期日',
    last_service_date DATE COMMENT '最后保养日期',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES customer(id)
);

-- 维修记录表
CREATE TABLE service_record (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    work_order_id BIGINT NOT NULL COMMENT '工单ID',
    customer_id BIGINT NOT NULL COMMENT '客户ID',
    vehicle_id BIGINT NOT NULL COMMENT '车辆ID',
    service_type VARCHAR(50) NOT NULL COMMENT '服务类型',
    service_items TEXT COMMENT '服务项目',
    total_amount DECIMAL(10,2) NOT NULL COMMENT '总金额',
    service_date DATE NOT NULL COMMENT '服务日期',
    mileage INT COMMENT '服务时里程',
    technician_id BIGINT COMMENT '技师ID',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES customer(id),
    FOREIGN KEY (vehicle_id) REFERENCES vehicle(id)
);

-- 积分变动记录表
CREATE TABLE points_transaction (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    customer_id BIGINT NOT NULL COMMENT '客户ID',
    type VARCHAR(20) NOT NULL COMMENT '变动类型',
    points INT NOT NULL COMMENT '变动积分',
    before_points INT NOT NULL COMMENT '变动前积分',
    after_points INT NOT NULL COMMENT '变动后积分',
    reference_no VARCHAR(32) COMMENT '关联单号',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES customer(id)
);

2. 实体类设计

java 复制代码
@Data
@Entity
@Table(name = "customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String code;
    private String name;
    private String phone;
    private String idCard;
    private Integer gender;
    private LocalDate birthday;
    private String email;
    private String address;
    private String source;
    
    @Enumerated(EnumType.STRING)
    private CustomerLevel level;
    
    private Integer points;
    private Integer status;
    private String remark;
    private LocalDateTime createdTime;
    private LocalDateTime updatedTime;
    
    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
    private List<Vehicle> vehicles;
}

@Data
@Entity
@Table(name = "vehicle")
public class Vehicle {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;
    
    private String plateNumber;
    private String brand;
    private String model;
    private String vin;
    private String engineNumber;
    private String color;
    private Integer mileage;
    private LocalDate purchaseDate;
    private LocalDate insuranceExpiry;
    private LocalDate lastServiceDate;
    private Integer status;
}

3. 客户服务实现

java 复制代码
@Service
@Transactional
public class CustomerService {
    
    @Autowired
    private CustomerRepository customerRepository;
    
    @Autowired
    private SequenceGenerator sequenceGenerator;
    
    @Autowired
    private PointsService pointsService;
    
    public CustomerResponse createCustomer(CustomerDTO dto) {
        // 1. 验证手机号是否已存在
        validatePhone(dto.getPhone());
        
        // 2. 生成客户编号
        String code = sequenceGenerator.generateCustomerCode();
        
        // 3. 创建客户信息
        Customer customer = new Customer();
        BeanUtils.copyProperties(dto, customer);
        customer.setCode(code);
        customer.setLevel(CustomerLevel.NORMAL);
        customer.setPoints(0);
        customer.setStatus(1);
        
        // 4. 保存客户信息
        customer = customerRepository.save(customer);
        
        // 5. 处理车辆信息
        if (dto.getVehicles() != null && !dto.getVehicles().isEmpty()) {
            List<Vehicle> vehicles = createVehicles(dto.getVehicles(), customer);
            customer.setVehicles(vehicles);
        }
        
        return buildResponse(customer);
    }
    
    public void updateCustomer(Long id, CustomerUpdateDTO dto) {
        Customer customer = customerRepository.findById(id)
            .orElseThrow(() -> new BusinessException("客户不存在"));
            
        // 1. 如果修改手机号,需要验证唯一性
        if (!customer.getPhone().equals(dto.getPhone())) {
            validatePhone(dto.getPhone());
        }
        
        // 2. 更新客户信息
        BeanUtils.copyProperties(dto, customer);
        customerRepository.save(customer);
    }
    
    public CustomerDetailResponse getCustomerDetail(Long id) {
        Customer customer = customerRepository.findById(id)
            .orElseThrow(() -> new BusinessException("客户不存在"));
            
        // 1. 获取客户基本信息
        CustomerDetailResponse response = buildDetailResponse(customer);
        
        // 2. 获取车辆信息
        List<VehicleVO> vehicles = getCustomerVehicles(id);
        response.setVehicles(vehicles);
        
        // 3. 获取最近维修记录
        List<ServiceRecordVO> serviceRecords = getRecentServiceRecords(id);
        response.setServiceRecords(serviceRecords);
        
        // 4. 获取积分明细
        List<PointsTransactionVO> pointsHistory = getPointsHistory(id);
        response.setPointsHistory(pointsHistory);
        
        return response;
    }
    
    @Cacheable(value = "customerLevel", key = "#customerId")
    public CustomerLevel calculateCustomerLevel(Long customerId) {
        // 1. 获取消费总额
        BigDecimal totalAmount = serviceRecordRepository
            .calculateTotalAmount(customerId);
            
        // 2. 计算客户等级
        return CustomerLevel.calculateLevel(totalAmount);
    }
}

4. 车辆服务实现

java 复制代码
@Service
@Transactional
public class VehicleService {
    
    @Autowired
    private VehicleRepository vehicleRepository;
    
    @Autowired
    private ServiceRecordRepository serviceRecordRepository;
    
    public VehicleResponse addVehicle(VehicleDTO dto) {
        // 1. 验证车牌号是否已存在
        validatePlateNumber(dto.getPlateNumber());
        
        // 2. 创建车辆信息
        Vehicle vehicle = new Vehicle();
        BeanUtils.copyProperties(dto, vehicle);
        
        // 3. 保存车辆信息
        vehicle = vehicleRepository.save(vehicle);
        
        return buildResponse(vehicle);
    }
    
    public void updateVehicle(Long id, VehicleUpdateDTO dto) {
        Vehicle vehicle = vehicleRepository.findById(id)
            .orElseThrow(() -> new BusinessException("车辆不存在"));
            
        // 1. 如果修改车牌号,需要验证唯一性
        if (!vehicle.getPlateNumber().equals(dto.getPlateNumber())) {
            validatePlateNumber(dto.getPlateNumber());
        }
        
        // 2. 更新车辆信息
        BeanUtils.copyProperties(dto, vehicle);
        vehicleRepository.save(vehicle);
    }
    
    public VehicleDetailResponse getVehicleDetail(Long id) {
        Vehicle vehicle = vehicleRepository.findById(id)
            .orElseThrow(() -> new BusinessException("车辆不存在"));
            
        // 1. 获取车辆基本信息
        VehicleDetailResponse response = buildDetailResponse(vehicle);
        
        // 2. 获取维修记录
        List<ServiceRecordVO> serviceRecords = getServiceRecords(id);
        response.setServiceRecords(serviceRecords);
        
        // 3. 获取保养提醒
        List<MaintenanceReminderVO> reminders = calculateMaintenanceReminders(vehicle);
        response.setMaintenanceReminders(reminders);
        
        return response;
    }
    
    private List<MaintenanceReminderVO> calculateMaintenanceReminders(Vehicle vehicle) {
        List<MaintenanceReminderVO> reminders = new ArrayList<>();
        
        // 1. 常规保养提醒(按里程)
        if (vehicle.getMileage() != null) {
            int nextServiceMileage = calculateNextServiceMileage(vehicle.getMileage());
            reminders.add(new MaintenanceReminderVO(
                "常规保养",
                "行驶里程达到" + nextServiceMileage + "公里时建议进行保养"
            ));
        }
        
        // 2. 保险到期提醒
        if (vehicle.getInsuranceExpiry() != null) {
            LocalDate today = LocalDate.now();
            long daysUntilExpiry = ChronoUnit.DAYS.between(today, vehicle.getInsuranceExpiry());
            
            if (daysUntilExpiry <= 30) {
                reminders.add(new MaintenanceReminderVO(
                    "保险到期提醒",
                    "保险将在" + daysUntilExpiry + "天后到期"
                ));
            }
        }
        
        return reminders;
    }
}

5. 积分服务实现

java 复制代码
@Service
@Transactional
public class PointsService {
    
    @Autowired
    private CustomerRepository customerRepository;
    
    @Autowired
    private PointsTransactionRepository transactionRepository;
    
    public void addPoints(PointsAddDTO dto) {
        Customer customer = customerRepository.findById(dto.getCustomerId())
            .orElseThrow(() -> new BusinessException("客户不存在"));
            
        // 1. 计算积分变动
        int beforePoints = customer.getPoints();
        int afterPoints = beforePoints + dto.getPoints();
        
        // 2. 更新客户积分
        customer.setPoints(afterPoints);
        customerRepository.save(customer);
        
        // 3. 记录积分变动
        savePointsTransaction(
            customer.getId(),
            PointsTransactionType.EARN,
            dto.getPoints(),
            beforePoints,
            afterPoints,
            dto.getReferenceNo(),
            dto.getRemark()
        );
        
        // 4. 检查等级变更
        checkAndUpdateLevel(customer);
    }
    
    public void deductPoints(PointsDeductDTO dto) {
        Customer customer = customerRepository.findById(dto.getCustomerId())
            .orElseThrow(() -> new BusinessException("客户不存在"));
            
        // 1. 验证积分是否足够
        if (customer.getPoints() < dto.getPoints()) {
            throw new BusinessException("积分不足");
        }
        
        // 2. 计算积分变动
        int beforePoints = customer.getPoints();
        int afterPoints = beforePoints - dto.getPoints();
        
        // 3. 更新客户积分
        customer.setPoints(afterPoints);
        customerRepository.save(customer);
        
        // 4. 记录积分变动
        savePointsTransaction(
            customer.getId(),
            PointsTransactionType.CONSUME,
            -dto.getPoints(),
            beforePoints,
            afterPoints,
            dto.getReferenceNo(),
            dto.getRemark()
        );
    }
    
    public PointsStatisticsResponse getPointsStatistics(Long customerId) {
        // 1. 获取当前积分
        Customer customer = customerRepository.findById(customerId)
            .orElseThrow(() -> new BusinessException("客户不存在"));
            
        // 2. 获取积分汇总信息
        PointsSummaryVO summary = calculatePointsSummary(customerId);
        
        // 3. 获取近期积分变动
        List<PointsTransactionVO> recentTransactions = 
            getRecentTransactions(customerId);
            
        return PointsStatisticsResponse.builder()
            .currentPoints(customer.getPoints())
            .summary(summary)
            .recentTransactions(recentTransactions)
            .build();
    }
    
    private void checkAndUpdateLevel(Customer customer) {
        CustomerLevel newLevel = customerService.calculateCustomerLevel(customer.getId());
        if (newLevel != customer.getLevel()) {
            // 更新客户等级
            customer.setLevel(newLevel);
            customerRepository.save(customer);
            
            // 发送等级变更通知
            notificationService.sendLevelChangeNotification(customer);
        }
    }
}

6. 维修记录查询服务

java 复制代码
@Service
public class ServiceRecordQueryService {
    
    @Autowired
    private ServiceRecordRepository serviceRecordRepository;
    
    public Page<ServiceRecordVO> queryServiceRecords(ServiceRecordQueryDTO query) {
        // 1. 构建查询条件
        Specification<ServiceRecord> spec = buildSpecification(query);
        
        // 2. 创建分页对象
        PageRequest pageRequest = PageRequest.of(
            query.getPageNum(),
            query.getPageSize(),
            Sort.by(Sort.Direction.DESC, "serviceDate")
        );
        
        // 3. 执行查询
        Page<ServiceRecord> page = serviceRecordRepository.findAll(spec, pageRequest);
        
        // 4. 转换响应
        return page.map(this::convertToVO);
    }
    
    public ServiceRecordDetailResponse getServiceRecordDetail(Long id) {
        ServiceRecord record = serviceRecordRepository.findById(id)
            .orElseThrow(() -> new BusinessException("维修记录不存在"));
            
        // 1. 获取基本信息
        ServiceRecordDetailResponse response = buildDetailResponse(record);
        
        // 2. 获取服务项目明细
        List<ServiceItemVO> items = getServiceItems(record);
        response.setItems(items);
        
        // 3. 获取配件使用记录
        List<PartUsageVO> partUsages = getPartUsages(record);
        response.setPartUsages(partUsages);
        
        return response;
    }
    
    public List<ServiceStatisticsVO> getServiceStatistics(Long customerId) {
        // 1. 获取维修频次统计
        Map<String, Long> serviceFrequency = calculateServiceFrequency(customerId);
        
        // 2. 获取维修金额统计
        Map<String, BigDecimal> serviceAmount = calculateServiceAmount(customerId);
        
        // 3. 获取常见维修项目
        List<CommonServiceItemVO> commonItems = getCommonServiceItems(customerId);
        
        return buildStatisticsResponse(serviceFrequency, serviceAmount, commonItems);
    }
}

7. 客户查询接口实现

java 复制代码
@RestController
@RequestMapping("/api/customers")
public class CustomerController {
    
    @Autowired
    private CustomerService customerService;
    
    @Autowired
    private VehicleService vehicleService;
    
    @Autowired
    private PointsService pointsService;
    
    @PostMapping
    public Result<CustomerResponse> createCustomer(@RequestBody @Valid CustomerDTO dto) {
        CustomerResponse response = customerService.createCustomer(dto);
        return Result.success(response);
    }
    
    @PutMapping("/{id}")
    public Result<Void> updateCustomer(
            @PathVariable Long id,
            @RequestBody @Valid CustomerUpdateDTO dto) {
        customerService.updateCustomer(id, dto);
        return Result.success();
    }
    
    @GetMapping("/{id}")
    public Result<CustomerDetailResponse> getCustomerDetail(@PathVariable Long id) {
        CustomerDetailResponse detail = customerService.getCustomerDetail(id);
        return Result.success(detail);
    }
    
    @PostMapping("/{id}/vehicles")
    public Result<VehicleResponse> addVehicle(
            @PathVariable Long id,
            @RequestBody @Valid VehicleDTO dto) {
        dto.setCustomerId(id);
        VehicleResponse response = vehicleService.addVehicle(dto);
        return Result.success(response);
    }
    
    @PostMapping("/{id}/points/add")
    public Result<Void> addPoints(
            @PathVariable Long id,
            @RequestBody @Valid PointsAddDTO dto) {
        dto.setCustomerId(id);
        pointsService.addPoints(dto);
        return Result.success();
    }
    
    @GetMapping("/{id}/points/statistics")
    public Result<PointsStatisticsResponse> getPointsStatistics(@PathVariable Long id) {
        PointsStatisticsResponse statistics = pointsService.getPointsStatistics(id);
        return Result.success(statistics);
    }
    
    @GetMapping("/{id}/service-records")
    public Result<Page<ServiceRecordVO>> getServiceRecords(
            @PathVariable Long id,
            ServiceRecordQueryDTO query) {
        query.setCustomerId(id);
        Page<ServiceRecordVO> page = serviceRecordQueryService.queryServiceRecords(query);
        return Result.success(page);
    }
}

这些代码实现了客户管理的核心功能,包括:

  1. 客户信息的CRUD操作
  2. 车辆信息管理
  3. 维修记录查询
  4. 积分管理和等级计算
  5. 统计分析功能

关键特点:

  • 完整的客户生命周期管理
  • 车辆信息关联
  • 维修记录追踪
  • 积分变动记录
  • 客户等级自动计算
  • 保养提醒功能

员工管理模块的核心代码实现

1. 数据库设计

sql 复制代码
-- 员工信息表
CREATE TABLE employee (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    code VARCHAR(32) UNIQUE NOT NULL COMMENT '员工编号',
    name VARCHAR(50) NOT NULL COMMENT '姓名',
    gender TINYINT NOT NULL COMMENT '性别: 0-女 1-男',
    id_card VARCHAR(18) UNIQUE NOT NULL COMMENT '身份证号',
    phone VARCHAR(20) NOT NULL COMMENT '联系电话',
    email VARCHAR(100) COMMENT '邮箱',
    address TEXT COMMENT '住址',
    job_type_id BIGINT NOT NULL COMMENT '工种ID',
    department_id BIGINT NOT NULL COMMENT '部门ID',
    entry_date DATE NOT NULL COMMENT '入职日期',
    leave_date DATE COMMENT '离职日期',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态: 0-离职 1-在职',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 工种分类表
CREATE TABLE job_type (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL COMMENT '工种名称',
    description TEXT COMMENT '工种描述',
    base_salary DECIMAL(10,2) NOT NULL COMMENT '基本工资',
    commission_rate DECIMAL(5,2) COMMENT '提成比例',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态: 0-禁用 1-启用',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 工作量记录表
CREATE TABLE work_record (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    employee_id BIGINT NOT NULL COMMENT '员工ID',
    work_order_id BIGINT NOT NULL COMMENT '工单ID',
    service_item_id BIGINT NOT NULL COMMENT '服务项目ID',
    work_hours DECIMAL(5,2) NOT NULL COMMENT '工时',
    amount DECIMAL(10,2) NOT NULL COMMENT '金额',
    commission DECIMAL(10,2) NOT NULL COMMENT '提成金额',
    work_date DATE NOT NULL COMMENT '工作日期',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (employee_id) REFERENCES employee(id)
);

-- 绩效考核表
CREATE TABLE performance_evaluation (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    employee_id BIGINT NOT NULL COMMENT '员工ID',
    evaluation_month VARCHAR(7) NOT NULL COMMENT '考核月份 YYYY-MM',
    work_quality_score INT NOT NULL COMMENT '工作质量得分',
    work_attitude_score INT NOT NULL COMMENT '工作态度得分',
    customer_feedback_score INT NOT NULL COMMENT '客户反馈得分',
    total_score INT NOT NULL COMMENT '总分',
    evaluator_id BIGINT NOT NULL COMMENT '评估人ID',
    evaluation_date DATE NOT NULL COMMENT '评估日期',
    remark TEXT COMMENT '评语',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (employee_id) REFERENCES employee(id),
    UNIQUE KEY `uk_employee_month` (`employee_id`, `evaluation_month`)
);

-- 考核指标表
CREATE TABLE evaluation_criteria (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL COMMENT '指标名称',
    category VARCHAR(50) NOT NULL COMMENT '指标类别',
    description TEXT COMMENT '指标描述',
    weight INT NOT NULL COMMENT '权重',
    max_score INT NOT NULL COMMENT '最高分',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

2. 实体类设计

java 复制代码
@Data
@Entity
@Table(name = "employee")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String code;
    private String name;
    private Integer gender;
    private String idCard;
    private String phone;
    private String email;
    private String address;
    private Long jobTypeId;
    private Long departmentId;
    private LocalDate entryDate;
    private LocalDate leaveDate;
    private Integer status;
    
    @ManyToOne
    @JoinColumn(name = "job_type_id", insertable = false, updatable = false)
    private JobType jobType;
}

@Data
@Entity
@Table(name = "job_type")
public class JobType {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private String description;
    private BigDecimal baseSalary;
    private BigDecimal commissionRate;
    private Integer status;
}

@Data
@Entity
@Table(name = "performance_evaluation")
public class PerformanceEvaluation {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private Long employeeId;
    private String evaluationMonth;
    private Integer workQualityScore;
    private Integer workAttitudeScore;
    private Integer customerFeedbackScore;
    private Integer totalScore;
    private Long evaluatorId;
    private LocalDate evaluationDate;
    private String remark;
}

3. 员工服务实现

java 复制代码
@Service
@Transactional
public class EmployeeService {
    
    @Autowired
    private EmployeeRepository employeeRepository;
    
    @Autowired
    private SequenceGenerator sequenceGenerator;
    
    public EmployeeResponse createEmployee(EmployeeDTO dto) {
        // 1. 验证身份证号是否已存在
        validateIdCard(dto.getIdCard());
        
        // 2. 生成员工编号
        String code = sequenceGenerator.generateEmployeeCode();
        
        // 3. 创建员工信息
        Employee employee = new Employee();
        BeanUtils.copyProperties(dto, employee);
        employee.setCode(code);
        employee.setStatus(1);
        
        // 4. 保存员工信息
        employee = employeeRepository.save(employee);
        
        // 5. 创建系统账号
        createUserAccount(employee);
        
        return buildResponse(employee);
    }
    
    public void updateEmployee(Long id, EmployeeUpdateDTO dto) {
        Employee employee = employeeRepository.findById(id)
            .orElseThrow(() -> new BusinessException("员工不存在"));
            
        // 1. 如果修改身份证号,需要验证唯一性
        if (!employee.getIdCard().equals(dto.getIdCard())) {
            validateIdCard(dto.getIdCard());
        }
        
        // 2. 更新员工信息
        BeanUtils.copyProperties(dto, employee);
        employeeRepository.save(employee);
    }
    
    public void handleEmployeeResignation(Long id, ResignationDTO dto) {
        Employee employee = employeeRepository.findById(id)
            .orElseThrow(() -> new BusinessException("员工不存在"));
            
        // 1. 设置离职信息
        employee.setLeaveDate(dto.getLeaveDate());
        employee.setStatus(0);
        
        // 2. 更新员工状态
        employeeRepository.save(employee);
        
        // 3. 处理相关系统账号
        disableUserAccount(employee.getCode());
        
        // 4. 记录离职信息
        saveResignationRecord(employee, dto);
    }
    
    private void createUserAccount(Employee employee) {
        UserCreateDTO userDto = UserCreateDTO.builder()
            .username(employee.getCode())
            .name(employee.getName())
            .phone(employee.getPhone())
            .email(employee.getEmail())
            .roleIds(getRolesByJobType(employee.getJobTypeId()))
            .build();
            
        userService.createUser(userDto);
    }
}

4. 工种管理服务实现

java 复制代码
@Service
@Transactional
public class JobTypeService {
    
    @Autowired
    private JobTypeRepository jobTypeRepository;
    
    public JobTypeResponse createJobType(JobTypeDTO dto) {
        // 1. 验证工种名称是否已存在
        validateJobTypeName(dto.getName());
        
        // 2. 创建工种信息
        JobType jobType = new JobType();
        BeanUtils.copyProperties(dto, jobType);
        jobType.setStatus(1);
        
        // 3. 保存工种信息
        jobType = jobTypeRepository.save(jobType);
        
        return buildResponse(jobType);
    }
    
    public void updateJobType(Long id, JobTypeUpdateDTO dto) {
        JobType jobType = jobTypeRepository.findById(id)
            .orElseThrow(() -> new BusinessException("工种不存在"));
            
        // 1. 如果修改名称,需要验证唯一性
        if (!jobType.getName().equals(dto.getName())) {
            validateJobTypeName(dto.getName());
        }
        
        // 2. 更新工种信息
        BeanUtils.copyProperties(dto, jobType);
        jobTypeRepository.save(jobType);
    }
    
    public void updateCommissionRate(Long id, BigDecimal newRate) {
        JobType jobType = jobTypeRepository.findById(id)
            .orElseThrow(() -> new BusinessException("工种不存在"));
            
        // 1. 验证提成比例
        if (newRate.compareTo(BigDecimal.ZERO) < 0 || 
            newRate.compareTo(BigDecimal.valueOf(100)) > 0) {
            throw new BusinessException("提成比例必须在0-100之间");
        }
        
        // 2. 更新提成比例
        jobType.setCommissionRate(newRate);
        jobTypeRepository.save(jobType);
    }
}

5. 工作量统计服务实现

java 复制代码
@Service
public class WorkloadStatisticsService {
    
    @Autowired
    private WorkRecordRepository workRecordRepository;
    
    public WorkloadStatisticsResponse getEmployeeWorkload(
            Long employeeId, LocalDate startDate, LocalDate endDate) {
        // 1. 获取工作量汇总
        WorkloadSummaryVO summary = calculateWorkloadSummary(employeeId, startDate, endDate);
        
        // 2. 获取每日工作量
        List<DailyWorkloadVO> dailyWorkloads = 
            calculateDailyWorkload(employeeId, startDate, endDate);
        
        // 3. 获取项目分布
        List<ServiceItemDistributionVO> itemDistribution = 
            calculateServiceItemDistribution(employeeId, startDate, endDate);
        
        return WorkloadStatisticsResponse.builder()
            .summary(summary)
            .dailyWorkloads(dailyWorkloads)
            .itemDistribution(itemDistribution)
            .build();
    }
    
    public Page<WorkRecordVO> queryWorkRecords(WorkRecordQueryDTO query) {
        // 1. 构建查询条件
        Specification<WorkRecord> spec = buildSpecification(query);
        
        // 2. 创建分页对象
        PageRequest pageRequest = PageRequest.of(
            query.getPageNum(),
            query.getPageSize(),
            Sort.by(Sort.Direction.DESC, "workDate")
        );
        
        // 3. 执行查询
        Page<WorkRecord> page = workRecordRepository.findAll(spec, pageRequest);
        
        // 4. 转换响应
        return page.map(this::convertToVO);
    }
    
    private WorkloadSummaryVO calculateWorkloadSummary(
            Long employeeId, LocalDate startDate, LocalDate endDate) {
        // 1. 计算总工时
        BigDecimal totalHours = workRecordRepository
            .sumWorkHours(employeeId, startDate, endDate);
            
        // 2. 计算总金额
        BigDecimal totalAmount = workRecordRepository
            .sumAmount(employeeId, startDate, endDate);
            
        // 3. 计算总提成
        BigDecimal totalCommission = workRecordRepository
            .sumCommission(employeeId, startDate, endDate);
            
        // 4. 计算完成工单数
        Long orderCount = workRecordRepository
            .countWorkOrders(employeeId, startDate, endDate);
            
        return WorkloadSummaryVO.builder()
            .totalHours(totalHours)
            .totalAmount(totalAmount)
            .totalCommission(totalCommission)
            .orderCount(orderCount)
            .build();
    }
}

6. 绩效考核服务实现

java 复制代码
@Service
@Transactional
public class PerformanceEvaluationService {
    
    @Autowired
    private PerformanceEvaluationRepository evaluationRepository;
    
    @Autowired
    private EvaluationCriteriaRepository criteriaRepository;
    
    public void createEvaluation(PerformanceEvaluationDTO dto) {
        // 1. 验证是否已存在当月考核
        validateMonthlyEvaluation(dto.getEmployeeId(), dto.getEvaluationMonth());
        
        // 2. 计算总分
        int totalScore = calculateTotalScore(dto);
        
        // 3. 创建考核记录
        PerformanceEvaluation evaluation = new PerformanceEvaluation();
        BeanUtils.copyProperties(dto, evaluation);
        evaluation.setTotalScore(totalScore);
        evaluation.setEvaluationDate(LocalDate.now());
        evaluation.setEvaluatorId(SecurityUtils.getCurrentUserId());
        
        // 4. 保存考核记录
        evaluationRepository.save(evaluation);
        
        // 5. 处理绩效奖金
        handlePerformanceBonus(evaluation);
    }
    
    public PerformanceStatisticsResponse getPerformanceStatistics(
            Long employeeId, String startMonth, String endMonth) {
        // 1. 获取考核汇总
        PerformanceSummaryVO summary = 
            calculatePerformanceSummary(employeeId, startMonth, endMonth);
        
        // 2. 获取月度考核趋势
        List<MonthlyPerformanceVO> monthlyTrend = 
            calculateMonthlyTrend(employeeId, startMonth, endMonth);
        
        // 3. 获取各项得分分布
        List<ScoreDistributionVO> scoreDistribution = 
            calculateScoreDistribution(employeeId, startMonth, endMonth);
        
        return PerformanceStatisticsResponse.builder()
            .summary(summary)
            .monthlyTrend(monthlyTrend)
            .scoreDistribution(scoreDistribution)
            .build();
    }
    
    private void handlePerformanceBonus(PerformanceEvaluation evaluation) {
        // 1. 获取员工信息
        Employee employee = employeeRepository.findById(evaluation.getEmployeeId())
            .orElseThrow();
            
        // 2. 获取工种信息
        JobType jobType = jobTypeRepository.findById(employee.getJobTypeId())
            .orElseThrow();
            
        // 3. 计算绩效奖金
        BigDecimal bonus = calculatePerformanceBonus(
            evaluation.getTotalScore(),
            jobType.getBaseSalary()
        );
        
        // 4. 保存奖金记录
        saveBonusRecord(evaluation, bonus);
    }
    
    private int calculateTotalScore(PerformanceEvaluationDTO dto) {
        // 1. 获取考核指标权重
        Map<String, Integer> weights = getEvaluationWeights();
        
        // 2. 计算加权总分
        return dto.getWorkQualityScore() * weights.get("QUALITY") / 100 +
               dto.getWorkAttitudeScore() * weights.get("ATTITUDE") / 100 +
               dto.getCustomerFeedbackScore() * weights.get("FEEDBACK") / 100;
    }
}

7. 员工查询接口实现

java 复制代码
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
    
    @Autowired
    private EmployeeService employeeService;
    
    @Autowired
    private WorkloadStatisticsService workloadService;
    
    @Autowired
    private PerformanceEvaluationService performanceService;
    
    @PostMapping
    public Result<EmployeeResponse> createEmployee(@RequestBody @Valid EmployeeDTO dto) {
        EmployeeResponse response = employeeService.createEmployee(dto);
        return Result.success(response);
    }
    
    @PutMapping("/{id}")
    public Result<Void> updateEmployee(
            @PathVariable Long id,
            @RequestBody @Valid EmployeeUpdateDTO dto) {
        employeeService.updateEmployee(id, dto);
        return Result.success();
    }
    
    @PostMapping("/{id}/resignation")
    public Result<Void> handleResignation(
            @PathVariable Long id,
            @RequestBody @Valid ResignationDTO dto) {
        employeeService.handleEmployeeResignation(id, dto);
        return Result.success();
    }
    
    @GetMapping("/{id}/workload")
    public Result<WorkloadStatisticsResponse> getWorkloadStatistics(
            @PathVariable Long id,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
        WorkloadStatisticsResponse statistics = 
            workloadService.getEmployeeWorkload(id, startDate, endDate);
        return Result.success(statistics);
    }
    
    @PostMapping("/{id}/performance-evaluation")
    public Result<Void> createPerformanceEvaluation(
            @PathVariable Long id,
            @RequestBody @Valid PerformanceEvaluationDTO dto) {
        dto.setEmployeeId(id);
        performanceService.createEvaluation(dto);
        return Result.success();
    }
    
    @GetMapping("/{id}/performance-statistics")
    public Result<PerformanceStatisticsResponse> getPerformanceStatistics(
            @PathVariable Long id,
            @RequestParam String startMonth,
            @RequestParam String endMonth) {
        PerformanceStatisticsResponse statistics = 
            performanceService.getPerformanceStatistics(id, startMonth, endMonth);
        return Result.success(statistics);
    }
}

这些代码实现了员工管理的核心功能,包括:

  1. 员工信息的CRUD操作
  2. 工种分类管理
  3. 工作量统计分析
  4. 绩效考核管理

关键特点:

  • 完整的员工生命周期管理
  • 灵活的工种配置
  • 详细的工作量记录
  • 多维度的绩效考核
  • 自动化的提成计算
  • 完善的统计分析功能

财务管理模块的核心代码实现

1. 数据库设计

sql 复制代码
-- 财务收支记录表
CREATE TABLE financial_transaction (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    transaction_no VARCHAR(32) UNIQUE NOT NULL COMMENT '交易编号',
    type VARCHAR(20) NOT NULL COMMENT '交易类型: INCOME/EXPENSE',
    category_id BIGINT NOT NULL COMMENT '类别ID',
    amount DECIMAL(12,2) NOT NULL COMMENT '金额',
    payment_method VARCHAR(20) NOT NULL COMMENT '支付方式',
    transaction_date DATE NOT NULL COMMENT '交易日期',
    reference_no VARCHAR(32) COMMENT '关联单号',
    reference_type VARCHAR(20) COMMENT '关联单据类型',
    operator_id BIGINT NOT NULL COMMENT '操作人',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 收支类别表
CREATE TABLE transaction_category (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL COMMENT '类别名称',
    type VARCHAR(20) NOT NULL COMMENT '类型: INCOME/EXPENSE',
    parent_id BIGINT COMMENT '父类别ID',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 成本记录表
CREATE TABLE cost_record (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    cost_type VARCHAR(20) NOT NULL COMMENT '成本类型',
    category_id BIGINT NOT NULL COMMENT '类别ID',
    amount DECIMAL(12,2) NOT NULL COMMENT '金额',
    record_month VARCHAR(7) NOT NULL COMMENT '记录月份 YYYY-MM',
    remark TEXT COMMENT '备注',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 利润核算表
CREATE TABLE profit_statement (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    statement_month VARCHAR(7) NOT NULL COMMENT '核算月份 YYYY-MM',
    total_revenue DECIMAL(12,2) NOT NULL COMMENT '总收入',
    total_cost DECIMAL(12,2) NOT NULL COMMENT '总成本',
    gross_profit DECIMAL(12,2) NOT NULL COMMENT '毛利润',
    operating_expenses DECIMAL(12,2) NOT NULL COMMENT '运营费用',
    net_profit DECIMAL(12,2) NOT NULL COMMENT '净利润',
    status VARCHAR(20) NOT NULL COMMENT '状态',
    created_by BIGINT NOT NULL COMMENT '创建人',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY `uk_month` (`statement_month`)
);

-- 收入明细表
CREATE TABLE revenue_detail (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    statement_id BIGINT NOT NULL COMMENT '利润表ID',
    category_id BIGINT NOT NULL COMMENT '收入类别ID',
    amount DECIMAL(12,2) NOT NULL COMMENT '金额',
    percentage DECIMAL(5,2) NOT NULL COMMENT '占比',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (statement_id) REFERENCES profit_statement(id)
);

-- 成本明细表
CREATE TABLE cost_detail (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    statement_id BIGINT NOT NULL COMMENT '利润表ID',
    category_id BIGINT NOT NULL COMMENT '成本类别ID',
    amount DECIMAL(12,2) NOT NULL COMMENT '金额',
    percentage DECIMAL(5,2) NOT NULL COMMENT '占比',
    created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (statement_id) REFERENCES profit_statement(id)
);

2. 实体类设计

java 复制代码
@Data
@Entity
@Table(name = "financial_transaction")
public class FinancialTransaction {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String transactionNo;
    
    @Enumerated(EnumType.STRING)
    private TransactionType type;
    
    private Long categoryId;
    private BigDecimal amount;
    
    @Enumerated(EnumType.STRING)
    private PaymentMethod paymentMethod;
    
    private LocalDate transactionDate;
    private String referenceNo;
    private String referenceType;
    private Long operatorId;
    private String remark;
    
    @ManyToOne
    @JoinColumn(name = "category_id", insertable = false, updatable = false)
    private TransactionCategory category;
}

@Data
@Entity
@Table(name = "profit_statement")
public class ProfitStatement {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String statementMonth;
    private BigDecimal totalRevenue;
    private BigDecimal totalCost;
    private BigDecimal grossProfit;
    private BigDecimal operatingExpenses;
    private BigDecimal netProfit;
    
    @Enumerated(EnumType.STRING)
    private StatementStatus status;
    
    private Long createdBy;
    
    @OneToMany(mappedBy = "statement", cascade = CascadeType.ALL)
    private List<RevenueDetail> revenueDetails;
    
    @OneToMany(mappedBy = "statement", cascade = CascadeType.ALL)
    private List<CostDetail> costDetails;
}

3. 财务交易服务实现

java 复制代码
@Service
@Transactional
public class FinancialTransactionService {
    
    @Autowired
    private FinancialTransactionRepository transactionRepository;
    
    @Autowired
    private SequenceGenerator sequenceGenerator;
    
    public TransactionResponse recordTransaction(TransactionDTO dto) {
        // 1. 生成交易编号
        String transactionNo = sequenceGenerator.generateTransactionNo();
        
        // 2. 创建交易记录
        FinancialTransaction transaction = new FinancialTransaction();
        BeanUtils.copyProperties(dto, transaction);
        transaction.setTransactionNo(transactionNo);
        transaction.setOperatorId(SecurityUtils.getCurrentUserId());
        
        // 3. 保存交易记录
        transaction = transactionRepository.save(transaction);
        
        // 4. 更新相关统计数据
        updateStatistics(transaction);
        
        return buildResponse(transaction);
    }
    
    public Page<TransactionVO> queryTransactions(TransactionQueryDTO query) {
        // 1. 构建查询条件
        Specification<FinancialTransaction> spec = buildSpecification(query);
        
        // 2. 创建分页对象
        PageRequest pageRequest = PageRequest.of(
            query.getPageNum(),
            query.getPageSize(),
            Sort.by(Sort.Direction.DESC, "transactionDate")
        );
        
        // 3. 执行查询
        Page<FinancialTransaction> page = transactionRepository.findAll(spec, pageRequest);
        
        // 4. 转换响应
        return page.map(this::convertToVO);
    }
    
    public TransactionStatisticsResponse getStatistics(
            LocalDate startDate, LocalDate endDate) {
        // 1. 获取收入统计
        List<CategoryStatisticsVO> incomeStats = 
            calculateCategoryStatistics(TransactionType.INCOME, startDate, endDate);
        
        // 2. 获取支出统计
        List<CategoryStatisticsVO> expenseStats = 
            calculateCategoryStatistics(TransactionType.EXPENSE, startDate, endDate);
        
        // 3. 获取支付方式统计
        List<PaymentMethodStatisticsVO> paymentStats = 
            calculatePaymentMethodStatistics(startDate, endDate);
        
        return TransactionStatisticsResponse.builder()
            .incomeStatistics(incomeStats)
            .expenseStatistics(expenseStats)
            .paymentMethodStatistics(paymentStats)
            .build();
    }
    
    private void updateStatistics(FinancialTransaction transaction) {
        // 1. 更新日统计
        updateDailyStatistics(transaction);
        
        // 2. 更新月统计
        updateMonthlyStatistics(transaction);
        
        // 3. 更新类别统计
        updateCategoryStatistics(transaction);
    }
}

4. 营收报表服务实现

java 复制代码
@Service
public class RevenueReportService {
    
    @Autowired
    private FinancialTransactionRepository transactionRepository;
    
    public RevenueReportResponse generateMonthlyReport(String month) {
        // 1. 获取收入汇总
        RevenueSummaryVO summary = calculateRevenueSummary(month);
        
        // 2. 获取收入趋势
        List<DailyRevenueVO> dailyTrend = calculateDailyRevenue(month);
        
        // 3. 获取收入构成
        List<RevenueCategoryVO> categoryDistribution = 
            calculateCategoryDistribution(month);
        
        // 4. 获取同比环比数据
        ComparisonDataVO comparison = calculateComparison(month);
        
        return RevenueReportResponse.builder()
            .summary(summary)
            .dailyTrend(dailyTrend)
            .categoryDistribution(categoryDistribution)
            .comparison(comparison)
            .build();
    }
    
    private RevenueSummaryVO calculateRevenueSummary(String month) {
        // 1. 计算总收入
        BigDecimal totalRevenue = transactionRepository
            .sumByTypeAndMonth(TransactionType.INCOME, month);
            
        // 2. 计算服务收入
        BigDecimal serviceRevenue = transactionRepository
            .sumByCategoryAndMonth(Arrays.asList(1L, 2L), month);
            
        // 3. 计算配件收入
        BigDecimal partsRevenue = transactionRepository
            .sumByCategoryAndMonth(Arrays.asList(3L), month);
            
        // 4. 计算其他收入
        BigDecimal otherRevenue = totalRevenue
            .subtract(serviceRevenue)
            .subtract(partsRevenue);
            
        return RevenueSummaryVO.builder()
            .totalRevenue(totalRevenue)
            .serviceRevenue(serviceRevenue)
            .partsRevenue(partsRevenue)
            .otherRevenue(otherRevenue)
            .build();
    }
}

5. 成本分析服务实现

java 复制代码
@Service
public class CostAnalysisService {
    
    @Autowired
    private CostRecordRepository costRecordRepository;
    
    public CostAnalysisResponse analyzeMonthlyCost(String month) {
        // 1. 获取成本汇总
        CostSummaryVO summary = calculateCostSummary(month);
        
        // 2. 获取成本构成
        List<CostCategoryVO> categoryAnalysis = analyzeCostCategory(month);
        
        // 3. 获取成本趋势
        List<MonthlyCostTrendVO> costTrend = analyzeCostTrend(month);
        
        // 4. 计算成本比率
        List<CostRatioVO> costRatios = calculateCostRatios(month);
        
        return CostAnalysisResponse.builder()
            .summary(summary)
            .categoryAnalysis(categoryAnalysis)
            .costTrend(costTrend)
            .costRatios(costRatios)
            .build();
    }
    
    private List<CostRatioVO> calculateCostRatios(String month) {
        List<CostRatioVO> ratios = new ArrayList<>();
        
        // 1. 获取总收入
        BigDecimal totalRevenue = revenueService.calculateMonthlyRevenue(month);
        
        // 2. 获取各类成本
        Map<String, BigDecimal> costMap = costRecordRepository
            .getCostsByTypeAndMonth(month);
            
        // 3. 计算各项成本比率
        for (Map.Entry<String, BigDecimal> entry : costMap.entrySet()) {
            BigDecimal ratio = BigDecimal.ZERO;
            if (totalRevenue.compareTo(BigDecimal.ZERO) > 0) {
                ratio = entry.getValue()
                    .divide(totalRevenue, 4, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100));
            }
            
            ratios.add(new CostRatioVO(
                entry.getKey(),
                entry.getValue(),
                ratio
            ));
        }
        
        return ratios;
    }
}

6. 利润核算服务实现

java 复制代码
@Service
@Transactional
public class ProfitStatementService {
    
    @Autowired
    private ProfitStatementRepository statementRepository;
    
    @Autowired
    private RevenueReportService revenueService;
    
    @Autowired
    private CostAnalysisService costService;
    
    public void generateMonthlyStatement(String month) {
        // 1. 验证月份是否已生成报表
        validateMonth(month);
        
        // 2. 创建利润表
        ProfitStatement statement = new ProfitStatement();
        statement.setStatementMonth(month);
        statement.setStatus(StatementStatus.DRAFT);
        statement.setCreatedBy(SecurityUtils.getCurrentUserId());
        
        // 3. 计算收入数据
        calculateRevenue(statement);
        
        // 4. 计算成本数据
        calculateCost(statement);
        
        // 5. 计算利润数据
        calculateProfit(statement);
        
        // 6. 保存利润表
        statement = statementRepository.save(statement);
        
        // 7. 生成明细数据
        generateDetails(statement);
    }
    
    public void approveStatement(Long id) {
        ProfitStatement statement = statementRepository.findById(id)
            .orElseThrow(() -> new BusinessException("利润表不存在"));
            
        // 1. 验证状态
        if (statement.getStatus() != StatementStatus.DRAFT) {
            throw new BusinessException("只有草稿状态的利润表可以审批");
        }
        
        // 2. 更新状态
        statement.setStatus(StatementStatus.APPROVED);
        statementRepository.save(statement);
        
        // 3. 生成财务凭证
        generateVoucher(statement);
    }
    
    public ProfitAnalysisResponse analyzeProfitTrend(
            String startMonth, String endMonth) {
        // 1. 获取利润趋势
        List<MonthlyProfitVO> profitTrend = 
            calculateProfitTrend(startMonth, endMonth);
        
        // 2. 计算利润率
        List<ProfitRatioVO> profitRatios = 
            calculateProfitRatios(startMonth, endMonth);
        
        // 3. 计算同比数据
        List<YearOverYearVO> yearOverYear = 
            calculateYearOverYear(startMonth, endMonth);
        
        return ProfitAnalysisResponse.builder()
            .profitTrend(profitTrend)
            .profitRatios(profitRatios)
            .yearOverYear(yearOverYear)
            .build();
    }
    
    private void calculateProfit(ProfitStatement statement) {
        // 1. 计算毛利润
        BigDecimal grossProfit = statement.getTotalRevenue()
            .subtract(statement.getTotalCost());
        statement.setGrossProfit(grossProfit);
        
        // 2. 计算净利润
        BigDecimal netProfit = grossProfit
            .subtract(statement.getOperatingExpenses());
        statement.setNetProfit(netProfit);
    }
}

7. 财务报表接口实现

java 复制代码
@RestController
@RequestMapping("/api/finance")
public class FinanceController {
    
    @Autowired
    private FinancialTransactionService transactionService;
    
    @Autowired
    private RevenueReportService revenueService;
    
    @Autowired
    private CostAnalysisService costService;
    
    @Autowired
    private ProfitStatementService profitService;
    
    @PostMapping("/transactions")
    public Result<TransactionResponse> recordTransaction(
            @RequestBody @Valid TransactionDTO dto) {
        TransactionResponse response = transactionService.recordTransaction(dto);
        return Result.success(response);
    }
    
    @GetMapping("/transactions/statistics")
    public Result<TransactionStatisticsResponse> getTransactionStatistics(
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
        TransactionStatisticsResponse statistics = 
            transactionService.getStatistics(startDate, endDate);
        return Result.success(statistics);
    }
    
    @GetMapping("/revenue/monthly-report")
    public Result<RevenueReportResponse> getMonthlyRevenueReport(
            @RequestParam String month) {
        RevenueReportResponse report = revenueService.generateMonthlyReport(month);
        return Result.success(report);
    }
    
    @GetMapping("/cost/analysis")
    public Result<CostAnalysisResponse> getCostAnalysis(
            @RequestParam String month) {
        CostAnalysisResponse analysis = costService.analyzeMonthlyCost(month);
        return Result.success(analysis);
    }
    
    @PostMapping("/profit-statements")
    public Result<Void> generateProfitStatement(@RequestParam String month) {
        profitService.generateMonthlyStatement(month);
        return Result.success();
    }
    
    @PostMapping("/profit-statements/{id}/approve")
    public Result<Void> approveProfitStatement(@PathVariable Long id) {
        profitService.approveStatement(id);
        return Result.success();
    }
    
    @GetMapping("/profit/analysis")
    public Result<ProfitAnalysisResponse> getProfitAnalysis(
            @RequestParam String startMonth,
            @RequestParam String endMonth) {
        ProfitAnalysisResponse analysis = 
            profitService.analyzeProfitTrend(startMonth, endMonth);
        return Result.success(analysis);
    }
}

这些代码实现了财务管理的核心功能,包括:

  1. 收支明细记录
  2. 营收报表统计
  3. 成本分析
  4. 利润核算

关键特点:

  • 完整的财务交易记录
  • 多维度的营收分析
  • 详细的成本核算
  • 自动化的利润计算
  • 完善的报表功能
  • 支持同比环比分析
相关推荐
ke_wu20 分钟前
结构型设计模式
开发语言·设计模式·组合模式·简单工厂模式·工厂方法模式·抽象工厂模式·装饰器模式
小马爱打代码22 分钟前
设计模式详解(建造者模式)
java·设计模式·建造者模式
code04号27 分钟前
python脚本:批量提取excel数据
开发语言·python·excel
小王爱吃月亮糖28 分钟前
C++的23种设计模式
开发语言·c++·qt·算法·设计模式·ecmascript
栗子~~1 小时前
idea 8年使用整理
java·ide·intellij-idea
hakesashou1 小时前
python如何打乱list
开发语言·python
2301_801483691 小时前
Maven核心概念
java·maven
网络风云1 小时前
【魅力golang】之-反射
开发语言·后端·golang
Q_19284999061 小时前
基于Spring Boot的电影售票系统
java·spring boot·后端
Want5952 小时前
Java圣诞树
开发语言·python·信息可视化