Files
lab/README.md
2026-09-21 12:51:08 +08:00

172 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实验室预约与资源管理平台
面向学校实验室的场景化预约系统:统一管理**实验室**、**设备**与**实验课程**,支持
**单次预约 / 多次预约 / 课程绑定预约**三种业务模式,内置可测试的**时间冲突检测算法**、
**资源状态机**与**基于角色的访问控制(RBAC)**,并提供 Vue3 前端与日历视图。
## 技术栈
| 层次 | 技术 |
| --- | --- |
| 后端 | Spring Boot 4.1.1、MyBatis-Plus 3.5.17(XML 自定义 SQL + QueryWrapper)、JWT(jjwt)、BCrypt |
| 数据库 | H2(默认,免安装演示)/ MariaDB(`mariadb` Profile,schema 脚本已提供) |
| 测试 | JUnit 5、Mockito、MockMvc、AssertJ、JaCoCo(覆盖率门禁) |
| 前端 | Vue 3 + TypeScript + Vite + Element Plus + Pinia + Vue Router + Axios,包管理 pnpm |
## 快速开始
### 1. 启动后端(默认 H2 文件库,无需安装数据库)
```bash
./mvnw spring-boot:run
# 或者:mvn spring-boot:run
```
- 服务地址:http://localhost:8080
- H2 控制台:http://localhost:8080/h2-console (JDBC URL:`jdbc:h2:file:./data/labdb`,用户 `sa`,密码留空)
- 首次启动会自动建表并写入演示数据(`src/main/resources/db/schema.sql`、`data.sql`)
使用 MariaDB/MySQL 时:
```bash
# 先创建数据库:CREATE DATABASE lab DEFAULT CHARSET utf8mb4;
DB_HOST=localhost DB_USER=root DB_PASSWORD=yourpass \
mvn spring-boot:run -Dspring-boot.run.profiles=mariadb
```
### 2. 启动前端
```bash
cd frontend
pnpm install
pnpm dev # http://localhost:5173,已配置 /api 代理到 8080
pnpm build # 生产构建(vue-tsc 类型检查 + vite build)
```
### 3. Docker 一键部署(推荐用于演示/验收)
```bash
docker compose up -d --build # 构建并启动 mariadb + backend + frontend
# 前端:http://localhost (Nginx 托管静态资源并反代 /api)
# 后端:http://localhost:8080
docker compose ps # 查看健康状态
docker compose down # 停止容器,保留数据库数据卷
docker compose down -v # 停止并清空数据库(下次启动重建演示数据)
```
- 编排:`mariadb:11.4`(数据持久化到命名卷)+ 后端多阶段构建镜像(JRE 21,非 root 运行)+ Nginx 前端镜像
- 三个服务均配置健康检查,后端与前端会等待上游就绪后再启动
- 可用环境变量覆盖:`WEB_PORT`(默认 80)、`BACKEND_PORT`(默认 8080)、
`DB_NAME` / `DB_USER` / `DB_PASSWORD` / `DB_ROOT_PASSWORD`、`LAB_JWT_SECRET`
### 4. 演示账号
| 账号 | 密码 | 角色 | 典型能力 |
| --- | --- | --- | --- |
| `admin` | `admin123` | 管理员 | 全部资源与用户管理、审批、状态流转 |
| `teacher1` | `123456` | 教师 | 课程管理、发起课程预约、审批 |
| `student1` | `123456` | 学生 | 发起预约、查看/取消自己的预约 |
## 功能地图
- **认证与权限**:JWT 登录、`@RequireRole` 角色注解、拦截器统一鉴权,前端路由/菜单按角色过滤
- **实验室管理**:增删改查、状态机流转(空闲 / 已预约 / 使用中 / 维护中)、可用实验室推荐
- **设备管理**:增删改查、归属实验室校验、状态机流转
- **实验课程**:教师排课(起止日期 + 星期 + 时间段)、一键生成整期课程绑定预约
- **预约中心**:
- 单次预约(datetimerange)
- 多次预约(按周重复,自动拆分为系列场次)
- 课程绑定预约(按课程排课规则批量生成)
- 冲突预检、审批(通过/驳回)、取消(可整系列)、开始/完成使用
- **日历视图**:按实验室 + 月份展示预约分布,点击查看详情
- **自动任务**:每 10 分钟自动完结已过期的预约并同步资源状态
## 核心设计
### 冲突检测
分层设计:数据库层用索引粗筛(XML 自定义 SQL,可选 `FOR UPDATE` 行锁),
应用层 `ConflictDetector` 做精确判断。
- 区间语义:左闭右开 `[start, end)`,**首尾相接不算冲突**
- 规则校验:时间区间合法性、过去时间、提前预约上限、单次时长、开放时间/跨天、
资源维护状态、容量、课程绑定关系、请求内部重叠
- 冲突分类:`LAB_CONFLICT` / `DEVICE_CONFLICT` / `USER_CONFLICT` 等,返回多冲突明细
- 并发控制:同事务内 `SELECT ... FOR UPDATE` + 冲突复检,避免并发双写
详细说明见 [docs/design.md](docs/design.md)。
### 状态机
- 实验室/设备:`IDLE → RESERVED → IN_USE → IDLE`,`IDLE ↔ MAINTENANCE`,非法迁移抛 `3003`
- 预约:`PENDING → APPROVED → IN_USE → COMPLETED`,`PENDING → REJECTED`,
`PENDING/APPROVED → CANCELLED`,终态不可再流转
## 测试与覆盖率
```bash
mvn verify # 运行全部测试并执行 JaCoCo 覆盖率门禁
```
- 测试规模:**219** 个用例(19 个测试类)(冲突算法边界、状态机、服务层 Mockito、Mapper/接口集成)
- 覆盖率(核心包,排除实体/DTO/VO/配置):**行 98.1%,分支 92.8%**
- 门禁:行 ≥ 90%,分支 ≥ 85%,不达标 `mvn verify` 直接失败
- 报告:`target/site/jacoco/index.html`
## 目录结构
```
├── src/main/java/com/example/lab
│ ├── common/ # 统一响应、异常、注解、上下文、JWT
│ ├── config/ # MyBatis-Plus、Web、安全、业务参数
│ ├── controller/ # REST 接口
│ ├── domain/
│ │ ├── conflict/ # 时间复杂度可控的冲突检测与重复规则展开
│ │ ├── entity/ # 实体
│ │ ├── enums/ # 角色/状态/类型枚举
│ │ └── statemachine/# 通用枚举状态机
│ ├── dto/ vo/ # 请求与视图对象
│ ├── mapper/ # MyBatis-Plus Mapper
│ ├── security/ # 认证授权拦截器
│ └── service/ # 业务服务
├── src/main/resources
│ ├── db/ # H2 / MariaDB 建表与演示数据
│ └── mapper/ # XML 自定义 SQL
├── src/test/java/... # 单元测试 + 集成测试
├── frontend/ # Vue3 + Element Plus 前端
│ ├── Dockerfile # pnpm 构建 + Nginx 托管(含 /api 反向代理)
│ └── nginx.conf
├── Dockerfile # 后端多阶段构建镜像
├── docker-compose.yml # mariadb + backend + frontend 一键编排
└── docs/design.md # 需求分析与详细设计
```
## 主要接口
| 方法 | 路径 | 说明 | 权限 |
| --- | --- | --- | --- |
| POST | `/api/auth/login` | 登录 | 公开 |
| GET | `/api/auth/me` | 当前用户 | 登录 |
| GET | `/api/labs` / `/api/labs/available` | 实验室列表 / 可用推荐 | 登录 |
| POST/PUT/DELETE | `/api/labs/**` | 实验室管理 | 管理员 |
| GET | `/api/devices` / `/api/devices/by-lab/{id}` | 设备列表 | 登录 |
| POST/PUT/DELETE | `/api/devices/**` | 设备管理 | 管理员 |
| GET | `/api/courses` | 课程列表 | 登录 |
| POST/PUT/DELETE | `/api/courses/**` | 课程管理 | 管理员/教师 |
| POST | `/api/reservations` | 单次预约 | 登录 |
| POST | `/api/reservations/recurring` | 多次预约 | 登录 |
| POST | `/api/reservations/course` | 课程绑定预约 | 管理员/授课教师 |
| POST | `/api/reservations/check` | 冲突预检 | 登录 |
| GET | `/api/reservations` / `/{id}` / `/calendar` | 列表 / 详情 / 日历 | 登录(学生仅本人) |
| POST | `/api/reservations/{id}/approve\|reject` | 审批 | 管理员/教师 |
| POST | `/api/reservations/{id}/cancel\|start\|complete` | 取消/开始/完成 | 本人或管理员 |
| GET/POST/PUT/DELETE | `/api/users/**` | 用户管理 | 管理员 |
统一响应格式:
```json
{ "code": 0, "message": "success", "data": {} }
```
业务错误码:`0` 成功、`1xxx` 用户与认证、`2xxx` 资源管理、`3xxx` 预约与冲突、`4xx/5xx` 通用错误。