在计算机专业毕设与课设选题中,前后端分离的Web管理系统是高性价比选择——技术栈成熟、工作量适中、功能拓展性强,且容易出可视化效果。错题管理系统作为教育类典型应用,既贴合实际场景,又能完整覆盖用户管理、数据增删改查、统计分析等核心考点,非常适合作为Web方向的毕设项目。

本文将从架构设计、后端实现、前端开发到本地部署,完整拆解一套基于Python+Flask+Vue的前后端分离错题管理系统,附核心功能代码,方便大家参考学习。

一、项目概览与技术栈

本系统针对传统纸质错题整理效率低、数据分析弱的痛点,采用前后端分离架构开发,支持学生错题录入、多条件检索、知识点维度统计分析,同时满足教师班级数据查看需求。

技术层级

核心技术

版本说明

后端开发语言

Python

3.11

后端Web框架

Flask

2.3.3

ORM框架

Flask-SQLAlchemy

3.1.1

身份认证

Flask-JWT-Extended

4.5.2

数据分析

Pandas

2.1.1

前端框架

Vue 3(Composition API)

3.3.4

前端UI组件库

Element UI Plus

2.3.7

HTTP请求库

Axios

1.5.0

可视化图表

ECharts

5.4.3

数据库

SQLite

轻量内嵌

构建工具

Vite

4.4.9

项目核心优势:

  • 轻量级技术栈,学习门槛低,适合快速落地

  • 分层架构清晰,代码模块化程度高,便于二次修改

  • 自带数据分析与可视化能力,毕设展示效果好

  • 支持学生、教师双角色,功能完整度高

二、系统整体架构与核心流程

系统采用经典的三层前后端分离架构,各层职责解耦:

  1. 前端展示层:基于Vue 3 + Element UI Plus构建,负责页面渲染、表单交互、数据可视化,通过Axios调用后端接口,Vue Router实现路由与权限控制。

  2. 后端服务层:基于Flask构建RESTful API,负责参数校验、业务逻辑处理、权限鉴权,向前端返回标准化JSON数据。

  3. 数据持久层:SQLite数据库存储核心业务数据,通过Flask-SQLAlchemy实现ORM映射,简化数据库操作。

核心业务流程:用户登录获取JWT Token → 前端携带Token请求错题相关接口 → 后端校验权限后执行数据库操作 → 返回数据给前端渲染展示与可视化。

三、后端核心功能实现(附核心代码)

3.1 数据库连接配置

通过配置文件统一管理数据库、JWT等参数,在应用初始化时加载SQLAlchemy,实现数据库连接与ORM映射。

# app/config.py
"""应用核心配置类,统一管理路径、数据库等配置"""
from pathlib import Path
import os

class Config:
    # 项目根目录
    ROOT_DIR = Path(__file__).resolve().parent.parent

    # Flask应用密钥
    SECRET_KEY = "your-secret-key-here"

    # SQLite数据库连接地址
    SQLALCHEMY_DATABASE_URI = f"sqlite:///{ROOT_DIR / 'data/app.db'}"
    # 关闭修改跟踪,提升性能
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = False

    # Token有效期,单位:小时
    TOKEN_EXPIRATION_HOURS = 24

3.2 用户登录接口实现

采用JWT实现无状态登录认证,验证用户名与加密密码后生成Token,同时携带用户角色信息用于权限控制。

# app/api/user.py
from flask import Blueprint, request, jsonify
from flask_jwt_extended import create_access_token
from app.models.user import User
from app.utils.encrypt import md5_encrypt

user_bp = Blueprint('user', __name__)

@user_bp.route('/login', methods=['POST'])
def login():
    """用户登录接口"""
    # 解析请求参数
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')
    
    # 参数非空校验
    if not username or not password:
        return jsonify({'code': 400, 'msg': '用户名或密码不能为空'}), 400
    
    # 查询用户信息
    user = User.query.filter_by(username=username).first()
    if not user:
        return jsonify({'code': 401, 'msg': '用户名不存在'}), 401
    
    # MD5加密后验证密码
    if user.password != md5_encrypt(password):
        return jsonify({'code': 401, 'msg': '密码错误'}), 401
    
    # 生成JWT Token,携带角色信息
    access_token = create_access_token(identity=user.id, additional_claims={'role': user.role})
    
    # 返回登录结果与用户信息
    return jsonify({
        'code': 200,
        'msg': '登录成功',
        'data': {
            'token': access_token,
            'username': user.username,
            'role': user.role,
            'id': user.id
        }
    }), 200

3.3 错题录入接口实现

通过JWT装饰器校验登录状态,获取当前用户ID,校验知识点合法性后将错题数据存入数据库。

# app/api/question.py
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from app.models.question import ErrorQuestion
from app.models.knowledge import KnowledgePoint
from app import db

question_bp = Blueprint('question', __name__)

@question_bp.route('/add', methods=['POST'])
@jwt_required()
def add_question():
    """添加错题接口"""
    # 获取当前登录用户ID
    user_id = get_jwt_identity()
    data = request.get_json()
    
    # 必填参数校验
    required_fields = ['content', 'knowledge_id']
    for field in required_fields:
        if not data.get(field):
            return jsonify({'code': 400, 'msg': f'{field}不能为空'}), 400
    
    # 校验知识点是否存在
    knowledge = KnowledgePoint.query.get(data.get('knowledge_id'))
    if not knowledge:
        return jsonify({'code': 400, 'msg': '知识点不存在'}), 400
    
    # 创建错题对象,默认复习状态为未复习
    new_question = ErrorQuestion(
        user_id=user_id,
        knowledge_id=data.get('knowledge_id'),
        content=data.get('content'),
        answer=data.get('answer', ''),
        error_reason=data.get('error_reason', ''),
        question_type=data.get('question_type', ''),
        review_status='未复习'
    )
    
    # 事务提交与异常回滚
    try:
        db.session.add(new_question)
        db.session.commit()
        return jsonify({'code': 200, 'msg': '错题添加成功', 'data': {'id': new_question.id}}), 200
    except Exception as e:
        db.session.rollback()
        return jsonify({'code': 500, 'msg': f'添加失败:{str(e)}'}), 500

3.4 错题分析接口实现

基于Pandas实现按知识点的错题数量统计,根据用户角色返回不同范围的数据:教师可查看全量数据,学生仅查看个人数据。

# app/api/analysis.py
from flask import Blueprint, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity, get_jwt
import pandas as pd
from app.models.question import ErrorQuestion
from app.models.knowledge import KnowledgePoint

analysis_bp = Blueprint('analysis', __name__)

@analysis_bp.route('/knowledge', methods=['GET'])
@jwt_required()
def knowledge_analysis():
    """按知识点统计错题数量"""
    user_id = get_jwt_identity()
    user_role = get_jwt()['role']
    
    # 角色权限控制:教师看全部,学生仅看自己
    if user_role == 'teacher':
        questions = ErrorQuestion.query.join(KnowledgePoint).all()
    else:
        questions = ErrorQuestion.query.filter_by(user_id=user_id).join(KnowledgePoint).all()
    
    # 转换为DataFrame进行分组统计
    df = pd.DataFrame([{
        'knowledge_name': q.knowledge_point.name,
        'count': 1
    } for q in questions])
    
    # 统计结果处理,适配前端ECharts格式
    if df.empty:
        result = {'x': [], 'y': []}
    else:
        stat_df = df.groupby('knowledge_name')['count'].sum().reset_index()
        result = {
            'x': stat_df['knowledge_name'].tolist(),
            'y': stat_df['count'].tolist()
        }
    
    return jsonify({'code': 200, 'msg': '统计成功', 'data': result}), 200

四、前端核心功能实现

4.1 Axios请求封装

统一封装Axios实例,添加请求拦截器自动携带Token,响应拦截器统一处理错误提示,简化业务代码。

// src/api/index.js
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { getToken } from '../utils/auth'

// 创建Axios实例
const service = axios.create({
  baseURL: 'http://localhost:5000',
  timeout: 5000
})

// 请求拦截器:自动添加Authorization头
service.interceptors.request.use(
  config => {
    const token = getToken()
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器:统一处理业务错误
service.interceptors.response.use(
  response => {
    const res = response.data
    if (res.code !== 200) {
      ElMessage.error(res.msg || '请求失败')
      return Promise.reject(res)
    }
    return res
  },
  error => {
    ElMessage.error(error.message || '服务器错误')
    return Promise.reject(error)
  }
)

export default service

4.2 登录页面实现

基于Element UI表单组件实现登录页,包含表单校验、角色选择、登录请求与页面跳转逻辑。

<!-- src/components/Login.vue -->
<template>
  <div class="login-container">
    <el-card title="错题管理系统登录">
      <el-form :model="loginForm" :rules="loginRules" ref="loginFormRef" label-width="80px">
        <el-form-item label="用户名" prop="username">
          <el-input v-model="loginForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input v-model="loginForm.password" type="password"></el-input>
        </el-form-item>
        <el-form-item label="角色" prop="role">
          <el-select v-model="loginForm.role">
            <el-option label="学生" value="student"></el-option>
            <el-option label="教师" value="teacher"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleLogin">登录</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { login } from '../api/user'
import { setToken, setUserInfo } from '../utils/auth'

const router = useRouter()
const loginFormRef = ref(null)
// 登录表单数据
const loginForm = ref({
  username: '',
  password: '',
  role: 'student'
})
// 表单校验规则
const loginRules = ref({
  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
  password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
  role: [{ required: true, message: '请选择角色', trigger: 'change' }]
})

// 登录处理
const handleLogin = async () => {
  const valid = await loginFormRef.value.validate()
  if (!valid) return
  
  try {
    const res = await login(loginForm.value)
    // 本地存储Token与用户信息
    setToken(res.data.token)
    setUserInfo({
      username: res.data.username,
      role: res.data.role,
      id: res.data.id
    })
    ElMessage.success('登录成功')
    router.push('/home')
  } catch (err) {
    ElMessage.error(err.msg || '登录失败')
  }
}
</script>

<style scoped>
.login-container {
  width: 400px;
  margin: 100px auto;
}
</style>

五、系统功能与效果展示

系统核心功能覆盖完整的错题管理闭环:

  1. 用户体系:学生、教师双角色,支持注册登录、权限隔离

  2. 错题管理:手动录入、编辑删除、多条件筛选检索、批量导入

  3. 数据分析:按知识点统计错题分布,柱状图可视化展示

  4. 复习管理:标记复习状态,生成个性化复习计划

  5. 系统管理:知识点字典维护、数据备份

六、本地部署与运行步骤

6.1 后端环境搭建

  1. 安装Python 3.11版本,配置好环境变量

  2. 进入后端项目目录,执行依赖安装命令:

pip install flask==2.3.3 flask-sqlalchemy==3.1.1 flask-jwt-extended==4.5.2 pandas==2.1.1 openpyxl==3.1.2
  1. 执行启动文件 run.py,服务默认运行在 http://localhost:5000

6.2 前端环境搭建

  1. 安装Node.js 18+版本

  2. 进入前端项目目录,执行依赖安装:

npm install element-plus axios vue-router echarts
  1. 执行启动命令:

npm run dev
  1. 访问 http://localhost:5173 即可进入系统

七、项目总结与扩展方向

本系统完整实现了前后端分离错题管理的核心功能,架构清晰、代码模块化程度高,既可以直接作为毕设/课设项目,也可以在此基础上做功能扩展。

可扩展的优化方向:

  • 接入OCR实现错题拍照录入,提升录入效率

  • 加入AI推荐算法,基于错题分布推送相似练习题

  • 开发微信小程序端,实现移动端错题复习

  • 增加班级错题排行、作业布置等教学互动功能

文末总结

以上就是错题管理系统的核心设计与实现思路,所有代码均来自实际项目工程,可直接参考复用。

更多推荐