一、系统核心架构与选型
本方案采用前后端分离架构,前端使用Vue 3 + Element Plus,后端使用Spring Boot 2.7,数据库使用MySQL 8.0。此组合技术栈成熟,社区资源丰富,适合快速开发企业级应用。
你需要准备以下环境:
- JDK 17 或更高版本
- Node.js 18 或更高版本
- MySQL 8.0
- Maven 3.8+
二、数据库表结构设计
创建数据库及核心表,用于记录培训项目、收费标准及收费记录。
1. 创建数据库与用户
登录MySQL,执行以下命令:
```
CREATE DATABASE IF NOT EXISTS archive_training DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'training_admin'@'localhost' IDENTIFIED BY 'YourStrongPassword123!';
GRANT ALL PRIVILEGES ON archive_training. TO 'training_admin'@'localhost';
FLUSH PRIVILEGES;
USE archive_training;
```
2. 核心数据表SQL
执行以下SQL语句创建表:
```
-- 培训项目表
CREATE TABLE training_program (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
program_name VARCHAR(100) NOT NULL COMMENT '培训项目名称',
description TEXT COMMENT '项目描述',
base_price_per_session DECIMAL(10, 2) NOT NULL COMMENT '单次培训基准价格(元)',
status TINYINT DEFAULT 1 COMMENT '状态:1-启用,0-停用',
created_time DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_status (status)
) COMMENT='培训项目表';
-- 收费标准明细表(支持按次数阶梯定价)
CREATE TABLE pricing_rule (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
program_id BIGINT NOT NULL COMMENT '关联培训项目ID',
min_sessions INT NOT NULL COMMENT '最小次数(包含)',
max_sessions INT COMMENT '最大次数(包含),NULL表示无上限',
unit_price DECIMAL(10, 2) NOT NULL COMMENT '对应次数区间的单价',
FOREIGN KEY (program_id) REFERENCES training_program(id) ON DELETE CASCADE,
INDEX idx_program (program_id)
) COMMENT='按次阶梯收费规则表';
-- 培训订单记录表
CREATE TABLE training_order (
id VARCHAR(32) PRIMARY KEY COMMENT '订单号,规则:ORD+年月日+6位序列,如ORD20240520000001',
program_id BIGINT NOT NULL,
customer_name VARCHAR(50) NOT NULL COMMENT '客户单位名称',
contact_phone VARCHAR(20) COMMENT '联系人电话',
total_sessions INT NOT NULL COMMENT '购买的总培训次数',
applied_sessions INT DEFAULT 0 COMMENT '已消耗次数',
total_amount DECIMAL(12, 2) NOT NULL COMMENT '订单总金额',
order_status TINYINT DEFAULT 0 COMMENT '状态:0-待支付,1-已支付,2-已完成,3-已取消',
created_time DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (program_id) REFERENCES training_program(id)
) COMMENT='培训订单表';
-- 单次培训消耗记录表
CREATE TABLE session_consumption (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_id VARCHAR(32) NOT NULL,
session_date DATE NOT NULL COMMENT '培训日期',
trainer_name VARCHAR(50) NOT NULL COMMENT '培训师姓名',
session_topic VARCHAR(200) COMMENT '本次培训主题',
created_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (order_id) REFERENCES training_order(id) ON DELETE CASCADE,
INDEX idx_order_date (order_id, session_date)
) COMMENT='单次培训消耗记录表';
```
三、后端服务核心实现
在Spring Boot项目中,创建以下核心服务和接口。
1. Maven依赖配置

在pom.xml中添加必要依赖:
```
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
runtime
org.projectlombok
lombok
true
```
2. 按次计费核心算法服务
创建PricingService.java,实现根据培训次数计算费用的核心逻辑:
```
package com.archive.training.service;
import com.archive.training.entity.PricingRule;
import com.archive.training.repository.PricingRuleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
@Service
public class PricingService {
@Autowired
private PricingRuleRepository pricingRuleRepository;
/
根据培训项目ID和购买次数,计算总费用
@param programId 培训项目ID
@param totalSessions 购买的培训总次数
@return 计算出的总金额
/
public BigDecimal calculateTotalPrice(Long programId, Integer totalSessions) {
// 1. 获取该项目的所有阶梯价格规则,并按最小次数升序排序
List
rules = pricingRuleRepository
.findByProgramIdOrderByMinSessionsAsc(programId);
if (rules.isEmpty()) {
throw new RuntimeException("未找到项目ID为 " + programId + " 的收费标准");
}
BigDecimal totalAmount = BigDecimal.ZERO;
int remainingSessions = totalSessions;
// 2. 遍历阶梯规则进行累加计算
for (PricingRule rule : rules) {
Integer maxSessions = rule.getMaxSessions();
int sessionsInThisTier;
if (maxSessions == null) {
// 最后一档,无上限,剩余次数全算在此档
sessionsInThisTier = remainingSessions;
} else {
// 计算本档位可覆盖的次数
int availableSessionsInTier = maxSessions - rule.getMinSessions() + 1;
sessionsInThisTier = Math.min(remainingSessions, availableSessionsInTier);
}
if (sessionsInThisTier > 0) {
// 本档位金额 = 档位单价 本档位次数
BigDecimal tierAmount = rule.getUnitPrice()
.multiply(BigDecimal.valueOf(sessionsInThisTier));
totalAmount = totalAmount.add(tierAmount);
remainingSessions -= sessionsInThisTier;
}
// 如果剩余次数为0,计算结束
if (remainingSessions <= 0) {
break;
}
}
// 3. 验证:如果遍历完所有规则后仍有剩余次数,说明配置有误
if (remainingSessions > 0) {
throw new RuntimeException("收费标准规则未能覆盖全部次数,请检查阶梯规则配置");
}
return totalAmount;
}
}
```
3. 订单创建与培训消耗API
创建OrderController.java,提供订单创建和记录培训消耗的REST接口:
```
package com.archive.training.controller;
import com.archive.training.service.OrderService;
import com.archive.training.vo.OrderCreateVO;
import com.archive.training.vo.SessionConsumeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.;
@RestController
@RequestMapping("/api/order")
public class OrderController {
@Autowired
private OrderService orderService;
/
创建新订单
POST /api/order/create
/
@PostMapping("/create")
public ApiResult createOrder(@RequestBody OrderCreateVO createVO) {
// 参数验证
if (createVO.getProgramId() == null) {
return ApiResult.error("培训项目ID不能为空");
}
if (createVO.getTotalSessions() == null || createVO.getTotalSessions() <= 0) {
return ApiResult.error("培训次数必须大于0");
}
String orderId = orderService.createNewOrder(createVO);
return ApiResult.ok("订单创建成功", orderId);
}
/
记录一次培训消耗
POST /api/order/consume-session
/
@PostMapping("/consume-session")
public ApiResult consumeSession(@RequestBody SessionConsumeVO consumeVO) {
// 参数验证
if (consumeVO.getOrderId() == null || consumeVO.getOrderId().trim().isEmpty()) {
return ApiResult.error("订单号不能为空");
}
if (consumeVO.getTrainerName() == null || consumeVO.getTrainerName().trim().isEmpty()) {
return ApiResult.error("培训师姓名不能为空");
}
boolean success = orderService.recordSessionConsumption(consumeVO);
if (success) {
return ApiResult.ok("培训记录保存成功");
} else {
return ApiResult.error("培训记录保存失败,请检查订单状态或剩余次数");
}
}
/
查询订单剩余次数
GET /api/order/remaining-sessions/{orderId}
/
@GetMapping("/remaining-sessions/{orderId}")
public ApiResult getRemainingSessions(@PathVariable String orderId) {
Integer remaining = orderService.getRemainingSessions(orderId);
return ApiResult.ok(remaining);
}
}
```
四、前端管理界面关键组件
使用Vue 3和Element Plus构建管理后台的关键界面。
1. 安装依赖并初始化项目
使用Vite创建项目并安装UI库:
```
npm create vue@latest archive-training-frontend
cd archive-training-frontend
npm install
npm install element-plus axios
```
2. 阶梯价格配置组件
创建PricingRuleConfig.vue,用于配置按次数阶梯收费规则:
```
```
3. 订单创建与费用试算组件
创建OrderCreate.vue,实现订单创建和实时费用计算:
```
次
¥ {{ calculatedPrice }}
(平均单价:¥ {{ unitPrice }} /次)
创建订单