# student assignment **Repository Path**: albert-chen04/student-assignment ## Basic Information - **Project Name**: student assignment - **Description**: 作业提交与批改系统 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2026-05-28 - **Last Updated**: 2026-06-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 作业提交与批改系统 [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) ## 项目概述 面向高校的作业全流程管理系统,支持超管、老师、助教、学生四种角色。覆盖班级管理、课程创建、作业发布、学生提交、助教批改、打分评价、答案管理等功能。 ## 技术栈 | 层级 | 技术 | |------|------| | 前端 | Vue 3 + Vite + Element Plus + Pinia + Vue Router + Axios | | 后端 | Spring Boot 3.5 + JPA + Flyway + Spring Security + JWT | | 数据库 | MySQL 8.4 | | 文件存储 | 本地文件系统 | ## 项目结构 ``` student_assignment/ ├── backend/ # Spring Boot 后端 │ ├── src/main/java/.../app/ │ │ ├── assignment/ # 作业、提交、批改、打分 │ │ ├── auth/ # JWT 认证、权限拦截 │ │ ├── common/ # 枚举、异常处理、时间 │ │ ├── config/ # 安全配置、存储配置、数据初始化 │ │ ├── course/ # 课程、班级、助教、花名册 │ │ ├── files/ # 文件上传、校验、存储 │ │ ├── school/ # 学校管理(超管) │ │ └── user/ # 用户、密码、学生档案 │ └── src/main/resources/ │ ├── application.yml # 配置(数据库、JWT、存储路径) │ └── db/migration/ # Flyway 数据库迁移 ├── frontend/ # Vue 3 前端 │ └── src/ │ ├── api/ # Axios 封装 + API 模块 │ ├── assets/ # 全局样式 │ ├── components/ # 可复用组件(对话框、标签等) │ ├── router/ # 路由配置 │ ├── stores/ # Pinia 认证状态 │ ├── utils/ # 格式化工具 │ └── views/ # 页面(登录 + 四个角色仪表盘) └── .gitignore ``` ## 四个角色及核心流程 ### 平台超管 (PLATFORM_ADMIN) - 创建学校,为学校创建老师账号 - 查看所有学校、老师、助教账号 - 无业务操作权限 ### 老师 (TEACHER) - **班级管理**:创建班级 → 导入花名册(Excel/CSV)→ 增删改查学生 - **课程管理**:创建课程(按学期)→ 选择班级加入课程 → 导入重修学生 - **助教管理**:创建助教账号 → 分配权限(班级/重修范围),同一范围只保留最新分配 - **作业管理**:发布作业(选择课程、截止日期、一次/二次打分)→ 上传题目 PDF → 查看提交和批改进度 → 打分 → 下载打包提交/成绩表 - **答案管理**:上传答案 PDF,截止时间后学生自动可见 ### 助教 (TA) - 批改分配给自己的班级或重修学生的作业 - 上传批改 PDF(按学号匹配) - 打分(支持数字或字母等级 A/B+/C 等) - 下载打分模板、批量上传打分表、导出成绩 - 管理答案(上传即生效) ### 学生 (STUDENT) - 查看作业列表、提交 PDF - 截止时间后查看答案、下载批改结果 - 查看自己的成绩 ## 核心业务逻辑 ### 班级与课程的关系(学期快照模型) - 班级 (`class_membership`) 和课程 (`course_enrollment`) 是两张独立的表 - 老师将班级「加入」课程时,系统将**当前**班级全部学生快照复制到课程报名表中 - 之后对班级的增删**不影响**已关联的课程(每个学期的课程是独立快照) - 对学生个人信息的修改(学号/姓名)**全局同步**,因为所有表只存 `student_id` 引用 - 重修学生在课程 Tab 中独立管理,增删都直接影响课程报名 ### 作业发布与范围 - 发布作业时自动选中课程关联的**所有班级和重修学生** - 学生通过 `course_enrollment` 确定是否能查看和提交作业 - 助教只能看到被分配范围内的学生的提交和批改 ### 答案管理 - 助教/老师上传答案即生效,无需单独的「发布」操作 - 截止时间前:助教和老师可见,学生不可见 - 截止时间后:所有人可见,学生自动获得查看和下载权限 ### 打分 - 支持数字成绩(0-1000)和字母等级(A/B+/C- 等) - 打分模板包含提交状态列,未提交学生成绩留空 - 截止时间后才能上传打分表 ### 批改文件 - 下载学生提交包 → ZIP 内文件以 `{学号}_submit.pdf` 命名 - 批改后上传 → 系统按学号自动匹配学生 ## 环境要求 - JDK 17+ - Maven 3.8+ - Node.js 20+ - MySQL 8.4 ## 快速开始 ### 1. 创建数据库 ```sql CREATE DATABASE IF NOT EXISTS student_assignment DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; ``` 数据库名 `student_assignment` 与 `application.yml` 中配置一致。也可以使用 `application.yml` 中的 `createDatabaseIfNotExist=true` 自动创建。 ### 2. 配置数据库连接 编辑 `backend/src/main/resources/application.yml`,或通过环境变量覆盖: ```bash export DB_URL=jdbc:mysql://localhost:3306/student_assignment?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&createDatabaseIfNotExist=true export DB_USERNAME=root export DB_PASSWORD=yourpassword ``` ### 3. 启动后端 ```bash cd backend mvn spring-boot:run ``` 首次启动时 Flyway 自动执行数据库迁移(V1-V6),创建所有表结构。随后 `DataInitializer` 自动创建超管账号: | 用户名 | 密码 | |--------|------| | admin | Admin123! | > 超管首次登录后会提示修改密码。**生产环境请务必修改 `application.yml` 中的 JWT secret 和 Credentials secret。** ### 4. 启动前端 ```bash cd frontend npm install npm run dev ``` 前端默认运行在 `http://localhost:5173`,API 请求自动代理到后端 `http://localhost:8080`。 登录页右上角提供"联系"入口,点击可查看微信二维码。 ### 5. 登录使用 1. 用超管账号登录 → 创建学校 → 创建老师 2. 用老师账号登录 → 创建班级 → 导入花名册 → 创建课程 → 加入班级 → 发布作业 3. 用学生账号登录 → 查看作业 → 提交 PDF 4. 老师创建助教并分配权限 → 助教登录批改打分 ## API 概述 | 模块 | 端点 | 说明 | |------|------|------| | 认证 | `POST /api/auth/login` | 登录获取 JWT | | 认证 | `POST /api/auth/change-password` | 修改密码 | | 平台 | `POST /api/schools` | 创建学校 | | 平台 | `POST /api/teachers` | 创建老师 | | 课程 | `GET /api/classes` | 班级列表 | | 课程 | `POST /api/classes` | 创建班级 | | 课程 | `POST /api/classes/{id}/students/import` | 导入花名册 | | 课程 | `POST /api/classes/{id}/students` | 添加单个学生 | | 课程 | `POST /api/classes/{id}/students/{sid}/delete` | 删除班级学生 | | 课程 | `PUT /api/students/{id}` | 修改学生信息 | | 课程 | `GET /api/courses` | 课程列表 | | 课程 | `POST /api/courses` | 创建课程 | | 课程 | `GET /api/courses/summaries` | 课程概览(含助教分配) | | 课程 | `POST /api/courses/{id}/enrollments/class/{cid}` | 班级加入课程 | | 课程 | `POST /api/courses/{id}/enrollments/retake/import` | 导入重修 | | 课程 | `POST /api/courses/{id}/retake-students` | 添加重修学生 | | 课程 | `POST /api/courses/{id}/retake-students/{sid}/delete` | 删除重修学生 | | 课程 | `POST /api/users/tas` | 创建助教 | | 课程 | `POST /api/courses/{id}/ta-scopes` | 分配助教权限 | | 作业 | `GET /api/assignments` | 作业列表 | | 作业 | `POST /api/assignments` | 发布作业 | | 作业 | `POST /api/assignments/{id}/submit` | 提交作业 | | 作业 | `GET /api/assignments/{id}/submissions.zip` | 下载提交包 | | 作业 | `POST /api/assignments/{id}/corrected-files` | 上传批改 | | 作业 | `GET /api/assignments/{id}/progress` | 提交/批改进度 | | 作业 | `POST /api/assignments/{id}/answer` | 上传答案 | | 作业 | `GET /api/assignments/{id}/answer/download` | 下载答案 | | 作业 | `PUT /api/assignments/{id}/scores/{sid}` | 单个打分 | | 作业 | `GET /api/assignments/{id}/score-template` | 下载打分模板 | | 作业 | `POST /api/assignments/{id}/scores/import` | 批量导入打分 | | 作业 | `GET /api/assignments/{id}/scores.xlsx` | 导出成绩表 | ## 数据库表 | 表 | 说明 | |----|------| | school | 学校 | | user_account | 用户账号(所有角色) | | student_profile | 学生档案(学号、姓名) | | teacher_profile | 老师档案 | | class_group | 班级 | | class_membership | 班级-学生关系 | | course | 课程 | | course_class | 课程-班级关系 | | course_enrollment | 课程-学生报名(学期快照) | | course_ta_scope | 助教分配范围 | | assignment | 作业 | | assignment_target | 作业目标范围 | | assignment_asset | 作业题目附件 | | assignment_answer | 作业答案 | | submission | 学生提交 | | corrected_file | 批改文件 | | score_record | 打分记录 | | audit_log | 操作审计日志 | | account_credential | 账号密码加密存储 | --- ## 部署到服务器 ### 构建后端 ```bash cd backend mvn package -DskipTests # JAR 包在 backend/target/student-assignment-api-*.jar ``` ### 构建前端 ```bash cd frontend npm install npm run build # 静态文件在 frontend/dist/ ``` ### 生产环境配置 部署时**必须**通过环境变量覆盖以下配置: ```bash # JWT 密钥(至少 32 字节) export JWT_SECRET=your-production-secret-at-least-32-bytes # 密码加密密钥(修改后已存储的密码将无法解密) export CREDENTIALS_SECRET=your-production-credential-secret # 数据库连接 export DB_URL=jdbc:mysql://your-db-host:3306/student_assignment?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai export DB_USERNAME=your-db-user export DB_PASSWORD=your-db-password # 文件存储路径(建议使用绝对路径或挂载卷) export STORAGE_ROOT=/data/student-assignment/storage # 异步请求超时时间,毫秒(默认 1 小时) # 学生提交包 ZIP 流式下载时,大文件需要较长时间,必须设长一点 export ASYNC_TIMEOUT=3600000 # 上传文件大小限制 export SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE=100MB export SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE=2048MB ``` ### 运行 ```bash java -jar backend/target/student-assignment-api-*.jar ``` 前端 `dist/` 目录部署到 Nginx 或任意静态文件服务器,反向代理 `/api` 到后端 8080 端口。 ### Nginx 配置示例 ```nginx server { listen 80; server_name your-domain.com; root /var/www/student-assignment; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 大文件上传下载必须配置 proxy_read_timeout 600s; proxy_send_timeout 600s; proxy_buffering off; proxy_request_buffering off; } location / { try_files $uri $uri/ /index.html; } } ``` ### 文件大小限制说明 | 配置项 | 默认值 | 说明 | |--------|--------|------| | `max-file-size` | 100MB | 单个文件上传上限。学生提交 PDF 一般几 MB,但需考虑扫描版 | | `max-request-size` | 2048MB | 单次请求总量上限。老师/助教一次上传 30+ 份批改 PDF 时需较大值 | | `client_max_body_size` | 2048M | Nginx 层上传限制,需与后端一致 | | `spring.mvc.async.request-timeout` | 3600000ms (1h) | 异步请求超时。ZIP 打包下载为流式输出,大文件耗时较长,过短会导致下载中断、ZIP 损坏 | 学生提交包下载(`/api/assignments/{id}/submissions.zip`)使用流式输出,内存占用与文件大小无关,单次下载 2GB 以内均可正常使用。 上传文件限制使用环境变量覆盖: ```bash export SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE=100MB export SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE=2048MB ``` ### 修改 CORS 允许域名 部署前需修改 `backend/src/main/java/com/studentassignment/app/config/SecurityConfig.java` 中的 CORS 配置,将 `as.abm48.com` 替换为实际部署域名: ```java // 修改前 configuration.setAllowedOrigins(List.of("http://localhost:5173", "http://127.0.0.1:5173", "https://as.abm48.com")); // 修改后(示例) configuration.setAllowedOrigins(List.of("http://localhost:5173", "http://127.0.0.1:5173", "https://your-domain.com")); ``` > 本地开发域名 `localhost` 保留即可,只替换 `as.abm48.com` 为你的生产域名。 ### 安全注意事项 - 首次启动后立即登录超管账号修改默认密码 - 生产环境必须更换 `JWT_SECRET` 和 `CREDENTIALS_SECRET` - 建议启用 HTTPS - 定期备份数据库和 `storage` 目录